@flowdesk/core 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/dist/authority-promotion.d.ts +70 -0
  4. package/dist/authority-promotion.d.ts.map +1 -0
  5. package/dist/authority-promotion.js +388 -0
  6. package/dist/authority-promotion.js.map +1 -0
  7. package/dist/chat-control-authority.d.ts +83 -0
  8. package/dist/chat-control-authority.d.ts.map +1 -0
  9. package/dist/chat-control-authority.js +238 -0
  10. package/dist/chat-control-authority.js.map +1 -0
  11. package/dist/chat-hook-authority-probe.d.ts +39 -0
  12. package/dist/chat-hook-authority-probe.d.ts.map +1 -0
  13. package/dist/chat-hook-authority-probe.js +153 -0
  14. package/dist/chat-hook-authority-probe.js.map +1 -0
  15. package/dist/chat-routing.d.ts.map +1 -1
  16. package/dist/chat-routing.js +18 -15
  17. package/dist/chat-routing.js.map +1 -1
  18. package/dist/connector-gateway.d.ts +34 -0
  19. package/dist/connector-gateway.d.ts.map +1 -0
  20. package/dist/connector-gateway.js +147 -0
  21. package/dist/connector-gateway.js.map +1 -0
  22. package/dist/connector-profile.d.ts +41 -0
  23. package/dist/connector-profile.d.ts.map +1 -0
  24. package/dist/connector-profile.js +125 -0
  25. package/dist/connector-profile.js.map +1 -0
  26. package/dist/controlled-conformance-doc-write.d.ts +44 -0
  27. package/dist/controlled-conformance-doc-write.d.ts.map +1 -0
  28. package/dist/controlled-conformance-doc-write.js +142 -0
  29. package/dist/controlled-conformance-doc-write.js.map +1 -0
  30. package/dist/controlled-redacted-audit-export-write.d.ts +45 -0
  31. package/dist/controlled-redacted-audit-export-write.d.ts.map +1 -0
  32. package/dist/controlled-redacted-audit-export-write.js +145 -0
  33. package/dist/controlled-redacted-audit-export-write.js.map +1 -0
  34. package/dist/core-completion-safety-contracts.d.ts +35 -0
  35. package/dist/core-completion-safety-contracts.d.ts.map +1 -0
  36. package/dist/core-completion-safety-contracts.js +98 -0
  37. package/dist/core-completion-safety-contracts.js.map +1 -0
  38. package/dist/dispatch-attempt-manifest.d.ts +59 -0
  39. package/dist/dispatch-attempt-manifest.d.ts.map +1 -0
  40. package/dist/dispatch-attempt-manifest.js +294 -0
  41. package/dist/dispatch-attempt-manifest.js.map +1 -0
  42. package/dist/dispatch-idempotency.d.ts +89 -0
  43. package/dist/dispatch-idempotency.d.ts.map +1 -0
  44. package/dist/dispatch-idempotency.js +275 -0
  45. package/dist/dispatch-idempotency.js.map +1 -0
  46. package/dist/external-auth-policy.d.ts +49 -0
  47. package/dist/external-auth-policy.d.ts.map +1 -0
  48. package/dist/external-auth-policy.js +166 -0
  49. package/dist/external-auth-policy.js.map +1 -0
  50. package/dist/fake-remote-connector-adapter.d.ts +37 -0
  51. package/dist/fake-remote-connector-adapter.d.ts.map +1 -0
  52. package/dist/fake-remote-connector-adapter.js +162 -0
  53. package/dist/fake-remote-connector-adapter.js.map +1 -0
  54. package/dist/fallback-decision.d.ts +29 -0
  55. package/dist/fallback-decision.d.ts.map +1 -0
  56. package/dist/fallback-decision.js +93 -0
  57. package/dist/fallback-decision.js.map +1 -0
  58. package/dist/fallback-regate-plan.d.ts +34 -0
  59. package/dist/fallback-regate-plan.d.ts.map +1 -0
  60. package/dist/fallback-regate-plan.js +122 -0
  61. package/dist/fallback-regate-plan.js.map +1 -0
  62. package/dist/fds1-schema-probe-result.d.ts +37 -0
  63. package/dist/fds1-schema-probe-result.d.ts.map +1 -0
  64. package/dist/fds1-schema-probe-result.js +115 -0
  65. package/dist/fds1-schema-probe-result.js.map +1 -0
  66. package/dist/index.d.ts +25 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +25 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/lane-heartbeat.d.ts +49 -0
  71. package/dist/lane-heartbeat.d.ts.map +1 -0
  72. package/dist/lane-heartbeat.js +149 -0
  73. package/dist/lane-heartbeat.js.map +1 -0
  74. package/dist/lane-lifecycle-record.d.ts +32 -0
  75. package/dist/lane-lifecycle-record.d.ts.map +1 -0
  76. package/dist/lane-lifecycle-record.js +134 -0
  77. package/dist/lane-lifecycle-record.js.map +1 -0
  78. package/dist/lane-stall-projection.d.ts +43 -0
  79. package/dist/lane-stall-projection.d.ts.map +1 -0
  80. package/dist/lane-stall-projection.js +272 -0
  81. package/dist/lane-stall-projection.js.map +1 -0
  82. package/dist/model-availability-cache.d.ts +286 -0
  83. package/dist/model-availability-cache.d.ts.map +1 -0
  84. package/dist/model-availability-cache.js +1109 -0
  85. package/dist/model-availability-cache.js.map +1 -0
  86. package/dist/operational-intelligence.d.ts +38 -0
  87. package/dist/operational-intelligence.d.ts.map +1 -0
  88. package/dist/operational-intelligence.js +107 -0
  89. package/dist/operational-intelligence.js.map +1 -0
  90. package/dist/production-approval-source.d.ts +61 -0
  91. package/dist/production-approval-source.d.ts.map +1 -0
  92. package/dist/production-approval-source.js +226 -0
  93. package/dist/production-approval-source.js.map +1 -0
  94. package/dist/production-enablement.d.ts +92 -1
  95. package/dist/production-enablement.d.ts.map +1 -1
  96. package/dist/production-enablement.js +421 -8
  97. package/dist/production-enablement.js.map +1 -1
  98. package/dist/production-verification.d.ts +31 -0
  99. package/dist/production-verification.d.ts.map +1 -0
  100. package/dist/production-verification.js +126 -0
  101. package/dist/production-verification.js.map +1 -0
  102. package/dist/provider-usage-collector.d.ts +7 -0
  103. package/dist/provider-usage-collector.d.ts.map +1 -1
  104. package/dist/provider-usage-collector.js +64 -10
  105. package/dist/provider-usage-collector.js.map +1 -1
  106. package/dist/release1-contracts.d.ts +8 -2
  107. package/dist/release1-contracts.d.ts.map +1 -1
  108. package/dist/release1-contracts.js +2 -1
  109. package/dist/release1-contracts.js.map +1 -1
  110. package/dist/remote-write-connector-gate.d.ts +91 -0
  111. package/dist/remote-write-connector-gate.d.ts.map +1 -0
  112. package/dist/remote-write-connector-gate.js +291 -0
  113. package/dist/remote-write-connector-gate.js.map +1 -0
  114. package/dist/runtime-lane-productization.d.ts +78 -0
  115. package/dist/runtime-lane-productization.d.ts.map +1 -0
  116. package/dist/runtime-lane-productization.js +270 -0
  117. package/dist/runtime-lane-productization.js.map +1 -0
  118. package/dist/sanitized-auth-capture.d.ts +50 -0
  119. package/dist/sanitized-auth-capture.d.ts.map +1 -0
  120. package/dist/sanitized-auth-capture.js +164 -0
  121. package/dist/sanitized-auth-capture.js.map +1 -0
  122. package/dist/schema-artifacts.d.ts.map +1 -1
  123. package/dist/schema-artifacts.js +37 -6
  124. package/dist/schema-artifacts.js.map +1 -1
  125. package/dist/schema-registry.d.ts.map +1 -1
  126. package/dist/schema-registry.js +21 -0
  127. package/dist/schema-registry.js.map +1 -1
  128. package/dist/session-evidence.d.ts +117 -0
  129. package/dist/session-evidence.d.ts.map +1 -1
  130. package/dist/session-evidence.js +581 -1
  131. package/dist/session-evidence.js.map +1 -1
  132. package/dist/state-paths.d.ts +1 -1
  133. package/dist/state-paths.d.ts.map +1 -1
  134. package/dist/state-paths.js +56 -6
  135. package/dist/state-paths.js.map +1 -1
  136. package/dist/status.d.ts +7 -0
  137. package/dist/status.d.ts.map +1 -1
  138. package/dist/status.js +89 -1
  139. package/dist/status.js.map +1 -1
  140. package/dist/validators.d.ts +1 -0
  141. package/dist/validators.d.ts.map +1 -1
  142. package/dist/validators.js +30 -7
  143. package/dist/validators.js.map +1 -1
  144. package/package.json +11 -2
@@ -1,11 +1,45 @@
1
1
  import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
2
2
  import { dirname, resolve, sep } from "node:path";
3
+ import { validateFlowDeskControlledConformanceDocWriteRecordV1 } from "./controlled-conformance-doc-write.js";
4
+ import { validateFlowDeskControlledRedactedAuditExportWriteRecordV1 } from "./controlled-redacted-audit-export-write.js";
5
+ import { validateFlowDeskDispatchIdempotencySnapshotV1 } from "./dispatch-idempotency.js";
6
+ import { validateFlowDeskExternalAuthProviderPolicyResultV1 } from "./external-auth-policy.js";
7
+ import { validateFlowDeskFallbackRegatePlanV1 } from "./fallback-regate-plan.js";
8
+ import { validateFlowDeskLaneHeartbeatRecordV1 } from "./lane-heartbeat.js";
9
+ import { validateFlowDeskLaneLifecycleRecordV1 } from "./lane-lifecycle-record.js";
10
+ import { validateFlowDeskProductionApprovalDecisionV1 } from "./production-enablement.js";
11
+ import { validateFlowDeskConfiguredVerificationResultV1 } from "./production-verification.js";
12
+ import { validateFlowDeskSanitizedAuthCaptureResultV1 } from "./sanitized-auth-capture.js";
13
+ import { materializeFlowDeskExactModelAvailabilityCacheFromProviderAcquisitionResultV1, planFlowDeskExactModelAvailabilityCacheRefreshV1, planFlowDeskReviewerFanoutV1, revalidateFlowDeskReviewerAssignmentsFromCacheEvidenceV1, validateFlowDeskExactModelAvailabilityCacheAcquisitionPlanV1, validateFlowDeskExactModelAvailabilityCacheProviderAcquisitionResultV1, validateFlowDeskExactModelAvailabilityCacheRefreshPlanV1, validateFlowDeskExactModelAvailabilityCacheV1, validateFlowDeskReviewerFanoutPlanV1, } from "./model-availability-cache.js";
14
+ import { validateFlowDeskProductionApprovalSourceV1 } from "./production-approval-source.js";
15
+ import { validateFlowDeskReviewerLaneConformanceObservationV1 } from "./reviewer-lane-conformance.js";
16
+ import { planFlowDeskRuntimeLaneLaunchV1, validateFlowDeskRuntimeLaneLaunchPlanV1, } from "./runtime-lane-productization.js";
3
17
  import { FLOWDESK_SESSION_EVIDENCE_CLASSES, sessionEvidenceDirectoryPath, sessionEvidenceRecordPath, } from "./state-paths.js";
4
- import { invalid, valid, validateNoForbiddenRawPayloads, validateOpaqueId, validateOpaqueRef, } from "./validators.js";
18
+ import { invalid, valid, validateNoForbiddenRawPayloads, validateOpaqueId, validateOpaqueRef, validateTopTierReviewVerdictV1, } from "./validators.js";
5
19
  const EVIDENCE_SCHEMA_BY_CLASS = {
6
20
  usage_authority: "flowdesk.managed_dispatch_beta.usage_authority_evidence.v1",
7
21
  runtime_echo: "flowdesk.managed_dispatch_beta.runtime_echo_evidence.v1",
8
22
  telemetry_correlation: "flowdesk.managed_dispatch_beta.telemetry_correlation.v1",
23
+ configured_verification: "flowdesk.configured_verification_result.v1",
24
+ sanitized_auth_capture: "flowdesk.sanitized_auth_capture_result.v1",
25
+ external_auth_provider_policy: "flowdesk.external_auth_provider_policy_result.v1",
26
+ production_approval: "flowdesk.production_approval_decision.v1",
27
+ production_approval_source: "flowdesk.production_approval_source.v1",
28
+ dispatch_idempotency: "flowdesk.dispatch_idempotency_snapshot.v1",
29
+ pre_dispatch_audit: "flowdesk.pre_dispatch_audit_record.v1",
30
+ exact_model_availability_cache: "flowdesk.exact_model_availability_cache.v1",
31
+ exact_model_availability_cache_refresh_plan: "flowdesk.exact_model_availability_cache_refresh_plan.v1",
32
+ exact_model_availability_cache_acquisition_plan: "flowdesk.exact_model_availability_cache_acquisition_plan.v1",
33
+ exact_model_availability_cache_provider_acquisition_result: "flowdesk.exact_model_availability_cache_provider_acquisition_result.v1",
34
+ reviewer_verdict: "flowdesk.top_tier_review_verdict.v1",
35
+ reviewer_fanout_plan: "flowdesk.reviewer_fanout_plan.v1",
36
+ runtime_lane_launch_plan: "flowdesk.runtime_lane_launch_plan.v1",
37
+ lane_lifecycle: "flowdesk.lane_lifecycle_record.v1",
38
+ reviewer_lane_conformance: "flowdesk.top_tier_reviewer_lane_conformance_observation.v1",
39
+ controlled_conformance_doc_write: "flowdesk.controlled_conformance_doc_write.v1",
40
+ controlled_redacted_audit_export_write: "flowdesk.controlled_redacted_audit_export_write.v1",
41
+ fallback_regate_plan: "flowdesk.fallback_regate_plan.v1",
42
+ lane_heartbeat: "flowdesk.lane_heartbeat.v1",
9
43
  };
10
44
  const CLASS_BY_SCHEMA = Object.fromEntries(Object.entries(EVIDENCE_SCHEMA_BY_CLASS).map(([cls, schema]) => [schema, cls]));
11
45
  const disabledEvidenceAuthority = {
@@ -17,6 +51,426 @@ const disabledEvidenceAuthority = {
17
51
  function isRecordObject(value) {
18
52
  return typeof value === "object" && value !== null && !Array.isArray(value);
19
53
  }
54
+ function exactModelCacheRefreshPlanMatchesContext(plan, input) {
55
+ return plan.state === "cache_hit" &&
56
+ plan.cache_usable_for_assignment === true &&
57
+ plan.expected_local_date === input.localDate &&
58
+ plan.expected_active_profile_ref === input.activeProfileRef &&
59
+ plan.expected_opencode_version_ref === input.opencodeVersionRef &&
60
+ plan.expected_flowdesk_package_version_ref === input.flowdeskPackageVersionRef &&
61
+ plan.expected_registry_hash === input.registryHash &&
62
+ plan.expected_policy_pack_hash === input.policyPackHash &&
63
+ plan.expected_auth_account_boundary_ref === input.authAccountBoundaryRef;
64
+ }
65
+ function exactModelCacheMatchesRefreshPlan(cache, plan) {
66
+ return plan.cache_id === cache.cache_id &&
67
+ plan.cache_local_date === cache.local_date &&
68
+ plan.cache_active_profile_ref === cache.active_profile_ref &&
69
+ plan.cache_opencode_version_ref === cache.opencode_version_ref &&
70
+ plan.cache_flowdesk_package_version_ref === cache.flowdesk_package_version_ref &&
71
+ plan.cache_registry_hash === cache.registry_hash &&
72
+ plan.cache_policy_pack_hash === cache.policy_pack_hash &&
73
+ plan.cache_auth_account_boundary_ref === cache.auth_account_boundary_ref;
74
+ }
75
+ export function selectFlowDeskExactModelCacheEvidencePairV1(input) {
76
+ const errors = [...input.reloadedEvidence.errors];
77
+ const blockedLabels = [];
78
+ if (!input.reloadedEvidence.ok)
79
+ blockedLabels.push("session_evidence_reload_invalid");
80
+ const refreshPlans = input.reloadedEvidence.entries
81
+ .filter((entry) => entry.evidenceClass === "exact_model_availability_cache_refresh_plan")
82
+ .map((entry) => entry.record)
83
+ .filter((record) => validateFlowDeskExactModelAvailabilityCacheRefreshPlanV1(record).ok)
84
+ .map((record) => record)
85
+ .filter((plan) => exactModelCacheRefreshPlanMatchesContext(plan, input));
86
+ if (refreshPlans.length === 0)
87
+ blockedLabels.push("cache_refresh_pair_missing");
88
+ if (refreshPlans.length > 1)
89
+ blockedLabels.push("cache_refresh_pair_ambiguous");
90
+ const cacheRefreshPlan = refreshPlans.length === 1 ? refreshPlans[0] : undefined;
91
+ const caches = cacheRefreshPlan === undefined ? [] : input.reloadedEvidence.entries
92
+ .filter((entry) => entry.evidenceClass === "exact_model_availability_cache")
93
+ .map((entry) => entry.record)
94
+ .filter((record) => validateFlowDeskExactModelAvailabilityCacheV1(record).ok)
95
+ .map((record) => record)
96
+ .filter((cache) => exactModelCacheMatchesRefreshPlan(cache, cacheRefreshPlan));
97
+ if (cacheRefreshPlan !== undefined && caches.length === 0)
98
+ blockedLabels.push("cache_pair_missing");
99
+ if (caches.length > 1)
100
+ blockedLabels.push("cache_pair_ambiguous");
101
+ const cache = caches.length === 1 ? caches[0] : undefined;
102
+ const ready = blockedLabels.length === 0 && cache !== undefined && cacheRefreshPlan !== undefined;
103
+ return {
104
+ ok: ready && errors.length === 0,
105
+ errors,
106
+ state: ready ? "pair_ready" : "blocked",
107
+ blocked_labels: [...new Set(blockedLabels)],
108
+ ...(cache === undefined ? {} : { cache }),
109
+ ...(cacheRefreshPlan === undefined ? {} : { cacheRefreshPlan }),
110
+ ...disabledEvidenceAuthority,
111
+ };
112
+ }
113
+ function blockedReviewerAssignmentRevalidationFromSelection(input, selection) {
114
+ return {
115
+ schema_version: "flowdesk.reviewer_assignment_revalidation.v1",
116
+ ok: false,
117
+ errors: selection.errors,
118
+ state: "blocked",
119
+ blocked_labels: [...new Set(["cache_evidence_pair_selection_blocked", ...selection.blocked_labels])],
120
+ expected_local_date: input.localDate,
121
+ expected_active_profile_ref: input.activeProfileRef,
122
+ expected_opencode_version_ref: input.opencodeVersionRef,
123
+ expected_flowdesk_package_version_ref: input.flowdeskPackageVersionRef,
124
+ expected_registry_hash: input.registryHash,
125
+ expected_policy_pack_hash: input.policyPackHash,
126
+ expected_auth_account_boundary_ref: input.authAccountBoundaryRef,
127
+ eligible_bindings: [],
128
+ dispatch_authority_enabled: false,
129
+ providerCall: false,
130
+ actualLaneLaunch: false,
131
+ runtimeExecution: false,
132
+ };
133
+ }
134
+ export function planFlowDeskReviewerFanoutFromReloadedCacheEvidenceV1(input) {
135
+ const selection = selectFlowDeskExactModelCacheEvidencePairV1(input);
136
+ const revalidation = selection.state === "pair_ready" && selection.cache !== undefined && selection.cacheRefreshPlan !== undefined
137
+ ? revalidateFlowDeskReviewerAssignmentsFromCacheEvidenceV1({
138
+ cache: selection.cache,
139
+ cacheRefreshPlan: selection.cacheRefreshPlan,
140
+ localDate: input.localDate,
141
+ activeProfileRef: input.activeProfileRef,
142
+ opencodeVersionRef: input.opencodeVersionRef,
143
+ flowdeskPackageVersionRef: input.flowdeskPackageVersionRef,
144
+ registryHash: input.registryHash,
145
+ policyPackHash: input.policyPackHash,
146
+ authAccountBoundaryRef: input.authAccountBoundaryRef,
147
+ })
148
+ : blockedReviewerAssignmentRevalidationFromSelection(input, selection);
149
+ const fanoutPlan = planFlowDeskReviewerFanoutV1({
150
+ revalidation,
151
+ workflowId: input.workflowId,
152
+ attemptId: input.attemptId,
153
+ parentSessionRef: input.parentSessionRef,
154
+ agentRef: input.agentRef,
155
+ requestedAt: input.requestedAt,
156
+ requestedPerspectives: input.requestedPerspectives,
157
+ maxConcurrentLaneCount: input.maxConcurrentLaneCount,
158
+ timeoutMs: input.timeoutMs,
159
+ orphanMaxAgeMs: input.orphanMaxAgeMs,
160
+ retryBudget: input.retryBudget,
161
+ preLaunchAuditRef: input.preLaunchAuditRef,
162
+ laneLaunchApprovalRef: input.laneLaunchApprovalRef,
163
+ });
164
+ const ready = selection.state === "pair_ready" && revalidation.state === "revalidated" && fanoutPlan.state === "fanout_ready";
165
+ return {
166
+ ok: ready && selection.ok && revalidation.ok && fanoutPlan.ok,
167
+ errors: [...selection.errors, ...revalidation.errors, ...fanoutPlan.errors],
168
+ state: ready ? "fanout_ready" : "blocked",
169
+ blocked_labels: [...new Set([...selection.blocked_labels, ...revalidation.blocked_labels, ...fanoutPlan.blocked_labels])],
170
+ selection,
171
+ revalidation,
172
+ fanoutPlan,
173
+ dispatch_authority_enabled: false,
174
+ ...disabledEvidenceAuthority,
175
+ };
176
+ }
177
+ function sessionEvidenceAlreadyContainsId(reloadedEvidence, evidenceClass, evidenceId) {
178
+ return reloadedEvidence.entries.some((entry) => entry.evidenceClass === evidenceClass && entry.evidenceId === evidenceId) ||
179
+ reloadedEvidence.blocked.some((entry) => entry.evidenceClass === evidenceClass && entry.evidenceId === evidenceId);
180
+ }
181
+ function providerAcquisitionResultMatchesStrictContext(result, input) {
182
+ return result.local_date === input.localDate &&
183
+ result.active_profile_ref === input.activeProfileRef &&
184
+ result.opencode_version_ref === input.opencodeVersionRef &&
185
+ result.flowdesk_package_version_ref === input.flowdeskPackageVersionRef &&
186
+ result.registry_hash === input.registryHash &&
187
+ result.policy_pack_hash === input.policyPackHash &&
188
+ result.auth_account_boundary_ref === input.authAccountBoundaryRef;
189
+ }
190
+ function exactModelMaterializationExpectedContext(input) {
191
+ return {
192
+ localDate: input.localDate,
193
+ activeProfileRef: input.activeProfileRef,
194
+ opencodeVersionRef: input.opencodeVersionRef,
195
+ flowdeskPackageVersionRef: input.flowdeskPackageVersionRef,
196
+ registryHash: input.registryHash,
197
+ policyPackHash: input.policyPackHash,
198
+ authAccountBoundaryRef: input.authAccountBoundaryRef,
199
+ };
200
+ }
201
+ export function materializeFlowDeskExactModelCacheEvidenceFromProviderAcquisitionEvidenceV1(input) {
202
+ const errors = [...input.reloadedEvidence.errors];
203
+ const blockedLabels = [];
204
+ if (!input.reloadedEvidence.ok)
205
+ blockedLabels.push("session_evidence_reload_invalid");
206
+ if (sessionEvidenceAlreadyContainsId(input.reloadedEvidence, "exact_model_availability_cache", input.targetCacheEvidenceId))
207
+ blockedLabels.push("target_cache_evidence_duplicate");
208
+ if (sessionEvidenceAlreadyContainsId(input.reloadedEvidence, "exact_model_availability_cache_refresh_plan", input.targetCacheRefreshPlanEvidenceId))
209
+ blockedLabels.push("target_cache_refresh_evidence_duplicate");
210
+ const acquisitionEntries = input.reloadedEvidence.entries
211
+ .filter((entry) => entry.evidenceClass === "exact_model_availability_cache_provider_acquisition_result")
212
+ .filter((entry) => input.providerAcquisitionEvidenceId === undefined || entry.evidenceId === input.providerAcquisitionEvidenceId)
213
+ .map((entry) => ({
214
+ ...entry,
215
+ validation: validateFlowDeskExactModelAvailabilityCacheProviderAcquisitionResultV1(entry.record),
216
+ }))
217
+ .filter((entry) => entry.validation.ok)
218
+ .map((entry) => ({
219
+ ...entry,
220
+ record: entry.record,
221
+ }))
222
+ .filter((entry) => input.providerAcquisitionEvidenceId !== undefined || providerAcquisitionResultMatchesStrictContext(entry.record, input));
223
+ if (acquisitionEntries.length === 0)
224
+ blockedLabels.push("provider_acquisition_evidence_missing");
225
+ if (acquisitionEntries.length > 1)
226
+ blockedLabels.push("provider_acquisition_evidence_ambiguous");
227
+ const acquisition = acquisitionEntries.length === 1 ? acquisitionEntries[0].record : undefined;
228
+ const materialized = materializeFlowDeskExactModelAvailabilityCacheFromProviderAcquisitionResultV1({
229
+ providerAcquisitionResult: acquisition,
230
+ cacheId: input.cacheId,
231
+ entryId: input.entryId,
232
+ expectedContext: exactModelMaterializationExpectedContext(input),
233
+ });
234
+ if (!materialized.ok) {
235
+ errors.push(...materialized.errors);
236
+ blockedLabels.push(...materialized.blocked_labels);
237
+ }
238
+ const cache = materialized.cache;
239
+ const cacheRefreshPlan = cache === undefined ? undefined : planFlowDeskExactModelAvailabilityCacheRefreshV1({
240
+ cache,
241
+ localDate: input.localDate,
242
+ activeProfileRef: input.activeProfileRef,
243
+ opencodeVersionRef: input.opencodeVersionRef,
244
+ flowdeskPackageVersionRef: input.flowdeskPackageVersionRef,
245
+ registryHash: input.registryHash,
246
+ policyPackHash: input.policyPackHash,
247
+ authAccountBoundaryRef: input.authAccountBoundaryRef,
248
+ });
249
+ if (cacheRefreshPlan !== undefined) {
250
+ const refreshValidation = validateFlowDeskExactModelAvailabilityCacheRefreshPlanV1(cacheRefreshPlan);
251
+ if (!refreshValidation.ok) {
252
+ errors.push(...refreshValidation.errors.map((error) => `cache_refresh_plan: ${error}`));
253
+ blockedLabels.push("materialized_cache_refresh_plan_invalid");
254
+ }
255
+ if (cacheRefreshPlan.state !== "cache_hit")
256
+ blockedLabels.push("materialized_cache_refresh_not_cache_hit");
257
+ }
258
+ if (cache !== undefined) {
259
+ const existingRefreshPlans = input.reloadedEvidence.entries
260
+ .filter((entry) => entry.evidenceClass === "exact_model_availability_cache_refresh_plan")
261
+ .map((entry) => entry.record)
262
+ .filter((record) => validateFlowDeskExactModelAvailabilityCacheRefreshPlanV1(record).ok)
263
+ .map((record) => record)
264
+ .filter((plan) => exactModelCacheRefreshPlanMatchesContext(plan, input));
265
+ if (existingRefreshPlans.length > 0)
266
+ blockedLabels.push("cache_refresh_context_already_exists");
267
+ const existingCachesForPlannedRefresh = cacheRefreshPlan === undefined ? [] : input.reloadedEvidence.entries
268
+ .filter((entry) => entry.evidenceClass === "exact_model_availability_cache")
269
+ .map((entry) => entry.record)
270
+ .filter((record) => validateFlowDeskExactModelAvailabilityCacheV1(record).ok)
271
+ .map((record) => record)
272
+ .filter((existingCache) => exactModelCacheMatchesRefreshPlan(existingCache, cacheRefreshPlan));
273
+ if (existingCachesForPlannedRefresh.length > 0)
274
+ blockedLabels.push("cache_context_already_exists");
275
+ }
276
+ if (blockedLabels.length > 0 || cache === undefined || cacheRefreshPlan === undefined)
277
+ return {
278
+ ok: false,
279
+ errors,
280
+ state: "blocked",
281
+ blocked_labels: [...new Set(blockedLabels)],
282
+ ...(cache === undefined ? {} : { cache }),
283
+ ...(cacheRefreshPlan === undefined ? {} : { cacheRefreshPlan }),
284
+ writeIntents: [],
285
+ ...disabledEvidenceAuthority,
286
+ };
287
+ const cacheIntent = prepareFlowDeskSessionEvidenceWriteIntentV1({
288
+ workflowId: input.workflowId,
289
+ evidenceId: input.targetCacheEvidenceId,
290
+ record: cache,
291
+ });
292
+ const refreshIntent = prepareFlowDeskSessionEvidenceWriteIntentV1({
293
+ workflowId: input.workflowId,
294
+ evidenceId: input.targetCacheRefreshPlanEvidenceId,
295
+ record: cacheRefreshPlan,
296
+ });
297
+ if (!cacheIntent.ok || cacheIntent.writeIntent === undefined || !refreshIntent.ok || refreshIntent.writeIntent === undefined)
298
+ return {
299
+ ok: false,
300
+ errors: [...errors, ...cacheIntent.errors, ...refreshIntent.errors],
301
+ state: "blocked",
302
+ blocked_labels: [...new Set([...blockedLabels, "cache_materialization_write_intent_invalid"])],
303
+ cache,
304
+ cacheRefreshPlan,
305
+ writeIntents: [],
306
+ ...disabledEvidenceAuthority,
307
+ };
308
+ const writeIntents = [cacheIntent.writeIntent, refreshIntent.writeIntent];
309
+ if (input.rootDir === undefined)
310
+ return {
311
+ ok: true,
312
+ errors,
313
+ state: "materialized",
314
+ blocked_labels: [],
315
+ cache,
316
+ cacheRefreshPlan,
317
+ writeIntents,
318
+ ...disabledEvidenceAuthority,
319
+ };
320
+ const applyResult = applyFlowDeskSessionEvidenceWriteIntentsV1(input.rootDir, writeIntents);
321
+ if (!applyResult.ok)
322
+ return {
323
+ ok: false,
324
+ errors: [...errors, ...applyResult.errors],
325
+ state: "blocked",
326
+ blocked_labels: [...new Set([...blockedLabels, "cache_materialization_apply_failed"])],
327
+ cache,
328
+ cacheRefreshPlan,
329
+ writeIntents,
330
+ applyResult,
331
+ ...disabledEvidenceAuthority,
332
+ };
333
+ const reloadedEvidence = reloadFlowDeskSessionEvidenceV1({ workflowId: input.workflowId, rootDir: input.rootDir });
334
+ const selection = selectFlowDeskExactModelCacheEvidencePairV1({
335
+ reloadedEvidence,
336
+ localDate: input.localDate,
337
+ activeProfileRef: input.activeProfileRef,
338
+ opencodeVersionRef: input.opencodeVersionRef,
339
+ flowdeskPackageVersionRef: input.flowdeskPackageVersionRef,
340
+ registryHash: input.registryHash,
341
+ policyPackHash: input.policyPackHash,
342
+ authAccountBoundaryRef: input.authAccountBoundaryRef,
343
+ });
344
+ const ready = reloadedEvidence.ok && selection.state === "pair_ready";
345
+ return {
346
+ ok: ready,
347
+ errors: [...errors, ...reloadedEvidence.errors, ...selection.errors],
348
+ state: ready ? "materialized" : "blocked",
349
+ blocked_labels: ready ? [] : [...new Set([...blockedLabels, "cache_materialization_reload_verification_failed", ...selection.blocked_labels])],
350
+ cache,
351
+ cacheRefreshPlan,
352
+ writeIntents,
353
+ applyResult,
354
+ reloadedEvidence,
355
+ selection,
356
+ ...disabledEvidenceAuthority,
357
+ };
358
+ }
359
+ export function materializeFlowDeskRuntimeLaneLaunchPlansFromReviewerFanoutEvidenceV1(input) {
360
+ const errors = [...input.reloadedEvidence.errors];
361
+ const blockedLabels = [];
362
+ if (!input.reloadedEvidence.ok)
363
+ blockedLabels.push("session_evidence_reload_invalid");
364
+ const targetIds = input.targetLaunchPlanEvidenceIds;
365
+ if (targetIds.length === 0)
366
+ blockedLabels.push("target_launch_plan_ids_missing");
367
+ if (new Set(targetIds).size !== targetIds.length)
368
+ blockedLabels.push("target_launch_plan_ids_duplicate");
369
+ for (const targetId of targetIds) {
370
+ if (sessionEvidenceAlreadyContainsId(input.reloadedEvidence, "runtime_lane_launch_plan", targetId))
371
+ blockedLabels.push("target_runtime_launch_plan_evidence_duplicate");
372
+ }
373
+ const fanoutEntries = input.reloadedEvidence.entries
374
+ .filter((entry) => entry.evidenceClass === "reviewer_fanout_plan")
375
+ .filter((entry) => input.reviewerFanoutEvidenceId === undefined || entry.evidenceId === input.reviewerFanoutEvidenceId)
376
+ .map((entry) => ({ ...entry, validation: validateFlowDeskReviewerFanoutPlanV1(entry.record) }))
377
+ .filter((entry) => entry.validation.ok)
378
+ .map((entry) => ({ ...entry, record: entry.record }))
379
+ .filter((entry) => entry.record.workflow_id === input.workflowId);
380
+ if (fanoutEntries.length === 0)
381
+ blockedLabels.push("reviewer_fanout_evidence_missing");
382
+ if (fanoutEntries.length > 1)
383
+ blockedLabels.push("reviewer_fanout_evidence_ambiguous");
384
+ const fanoutPlan = fanoutEntries.length === 1 ? fanoutEntries[0].record : undefined;
385
+ if (fanoutPlan !== undefined && (fanoutPlan.state !== "fanout_ready" || !fanoutPlan.ok))
386
+ blockedLabels.push("reviewer_fanout_not_ready");
387
+ const launchRequests = fanoutPlan?.runtime_lane_launch_requests ?? [];
388
+ if (fanoutPlan !== undefined && targetIds.length !== launchRequests.length)
389
+ blockedLabels.push("target_launch_plan_count_mismatch");
390
+ const launchPlans = launchRequests.map((request) => planFlowDeskRuntimeLaneLaunchV1({
391
+ request,
392
+ sdkClientAvailable: input.sdkClientAvailable,
393
+ durableEvidenceRootRef: input.durableEvidenceRootRef,
394
+ }));
395
+ for (const [index, plan] of launchPlans.entries()) {
396
+ errors.push(...plan.errors.map((error) => `launch_plans[${index}]: ${error}`));
397
+ if (plan.state !== "launch_ready")
398
+ blockedLabels.push(...(plan.blocked_labels.length > 0 ? plan.blocked_labels : ["runtime_launch_plan_blocked"]));
399
+ }
400
+ if (blockedLabels.length > 0 || fanoutPlan === undefined || launchPlans.length === 0)
401
+ return {
402
+ ok: false,
403
+ errors,
404
+ state: "blocked",
405
+ blocked_labels: [...new Set(blockedLabels)],
406
+ ...(fanoutPlan === undefined ? {} : { fanoutPlan }),
407
+ launchPlans,
408
+ writeIntents: [],
409
+ ...disabledEvidenceAuthority,
410
+ };
411
+ const prepared = launchPlans.map((plan, index) => prepareFlowDeskSessionEvidenceWriteIntentV1({
412
+ workflowId: input.workflowId,
413
+ evidenceId: targetIds[index],
414
+ record: plan,
415
+ }));
416
+ const prepareErrors = prepared.flatMap((result) => result.errors);
417
+ const writeIntents = prepared
418
+ .map((result) => result.writeIntent)
419
+ .filter((intent) => intent !== undefined);
420
+ if (prepareErrors.length > 0 || writeIntents.length !== launchPlans.length)
421
+ return {
422
+ ok: false,
423
+ errors: [...errors, ...prepareErrors],
424
+ state: "blocked",
425
+ blocked_labels: ["runtime_launch_plan_write_intent_invalid"],
426
+ fanoutPlan,
427
+ launchPlans,
428
+ writeIntents: [],
429
+ ...disabledEvidenceAuthority,
430
+ };
431
+ if (input.rootDir === undefined)
432
+ return {
433
+ ok: true,
434
+ errors,
435
+ state: "materialized",
436
+ blocked_labels: [],
437
+ fanoutPlan,
438
+ launchPlans,
439
+ writeIntents,
440
+ ...disabledEvidenceAuthority,
441
+ };
442
+ const applyResult = applyFlowDeskSessionEvidenceWriteIntentsV1(input.rootDir, writeIntents);
443
+ if (!applyResult.ok)
444
+ return {
445
+ ok: false,
446
+ errors: [...errors, ...applyResult.errors],
447
+ state: "blocked",
448
+ blocked_labels: ["runtime_launch_plan_apply_failed"],
449
+ fanoutPlan,
450
+ launchPlans,
451
+ writeIntents,
452
+ applyResult,
453
+ ...disabledEvidenceAuthority,
454
+ };
455
+ const reloadedEvidence = reloadFlowDeskSessionEvidenceV1({ workflowId: input.workflowId, rootDir: input.rootDir });
456
+ const reloadedIds = new Set(reloadedEvidence.entries
457
+ .filter((entry) => entry.evidenceClass === "runtime_lane_launch_plan")
458
+ .map((entry) => entry.evidenceId));
459
+ const allReloaded = targetIds.every((targetId) => reloadedIds.has(targetId));
460
+ const ready = reloadedEvidence.ok && allReloaded;
461
+ return {
462
+ ok: ready,
463
+ errors: [...errors, ...reloadedEvidence.errors],
464
+ state: ready ? "materialized" : "blocked",
465
+ blocked_labels: ready ? [] : ["runtime_launch_plan_reload_verification_failed"],
466
+ fanoutPlan,
467
+ launchPlans,
468
+ writeIntents,
469
+ applyResult,
470
+ reloadedEvidence,
471
+ ...disabledEvidenceAuthority,
472
+ };
473
+ }
20
474
  function validateSchemaVersionForClass(record, evidenceClass) {
21
475
  const expected = EVIDENCE_SCHEMA_BY_CLASS[evidenceClass];
22
476
  return record.schema_version === expected
@@ -27,12 +481,76 @@ function validateEvidenceShape(record, evidenceClass) {
27
481
  const schemaCheck = validateSchemaVersionForClass(record, evidenceClass);
28
482
  if (!schemaCheck.ok)
29
483
  return schemaCheck;
484
+ if (evidenceClass === "dispatch_idempotency")
485
+ return validateFlowDeskDispatchIdempotencySnapshotV1(record);
486
+ if (evidenceClass === "production_approval_source")
487
+ return validateFlowDeskProductionApprovalSourceV1(record);
488
+ if (evidenceClass === "reviewer_verdict")
489
+ return validateTopTierReviewVerdictV1(record);
490
+ if (evidenceClass === "exact_model_availability_cache")
491
+ return validateFlowDeskExactModelAvailabilityCacheV1(record);
492
+ if (evidenceClass === "exact_model_availability_cache_refresh_plan")
493
+ return validateFlowDeskExactModelAvailabilityCacheRefreshPlanV1(record);
494
+ if (evidenceClass === "exact_model_availability_cache_acquisition_plan")
495
+ return validateFlowDeskExactModelAvailabilityCacheAcquisitionPlanV1(record);
496
+ if (evidenceClass === "exact_model_availability_cache_provider_acquisition_result")
497
+ return validateFlowDeskExactModelAvailabilityCacheProviderAcquisitionResultV1(record);
498
+ if (evidenceClass === "reviewer_fanout_plan")
499
+ return validateFlowDeskReviewerFanoutPlanV1(record);
500
+ if (evidenceClass === "runtime_lane_launch_plan")
501
+ return validateFlowDeskRuntimeLaneLaunchPlanV1(record);
502
+ if (evidenceClass === "lane_lifecycle")
503
+ return validateFlowDeskLaneLifecycleRecordV1(record);
504
+ if (evidenceClass === "lane_heartbeat")
505
+ return validateFlowDeskLaneHeartbeatRecordV1(record);
506
+ if (evidenceClass === "reviewer_lane_conformance")
507
+ return validateFlowDeskReviewerLaneConformanceObservationV1(record);
508
+ if (evidenceClass === "controlled_conformance_doc_write")
509
+ return validateFlowDeskControlledConformanceDocWriteRecordV1(record);
510
+ if (evidenceClass === "controlled_redacted_audit_export_write")
511
+ return validateFlowDeskControlledRedactedAuditExportWriteRecordV1(record);
512
+ if (evidenceClass === "fallback_regate_plan")
513
+ return validateFlowDeskFallbackRegatePlanV1(record);
514
+ if (evidenceClass === "configured_verification")
515
+ return validateFlowDeskConfiguredVerificationResultV1(record);
516
+ if (evidenceClass === "sanitized_auth_capture")
517
+ return validateFlowDeskSanitizedAuthCaptureResultV1(record);
518
+ if (evidenceClass === "external_auth_provider_policy")
519
+ return validateFlowDeskExternalAuthProviderPolicyResultV1(record);
520
+ if (evidenceClass === "production_approval")
521
+ return validateFlowDeskProductionApprovalDecisionV1(record);
30
522
  const requiredCommon = ["schema_version"];
31
523
  for (const key of requiredCommon)
32
524
  if (!(key in record))
33
525
  return invalid(`evidence is missing required field: ${key}`);
34
526
  return validateNoForbiddenRawPayloads(record, "session_evidence_record");
35
527
  }
528
+ function validateOptionalTimestampFreshness(record, rejectStaleAt) {
529
+ if (rejectStaleAt === undefined || !("expires_at" in record))
530
+ return valid();
531
+ const checkedAt = Date.parse(rejectStaleAt);
532
+ if (!Number.isFinite(checkedAt))
533
+ return invalid("rejectStaleAt must be a parseable timestamp");
534
+ if (typeof record.expires_at !== "string")
535
+ return invalid("evidence expires_at must be a timestamp string");
536
+ const expiresAt = Date.parse(record.expires_at);
537
+ if (!Number.isFinite(expiresAt))
538
+ return invalid("evidence expires_at must be parseable");
539
+ return expiresAt > checkedAt ? valid() : invalid("evidence is stale");
540
+ }
541
+ function validateOptionalProfileAlignment(record, expectedProfileRef) {
542
+ if (expectedProfileRef === undefined)
543
+ return valid();
544
+ const expected = validateOpaqueRef(expectedProfileRef, "expected_profile_ref");
545
+ if (!expected.ok)
546
+ return expected;
547
+ const profileRef = record.profile_ref ?? record.auth_profile_ref;
548
+ if (profileRef === undefined)
549
+ return valid();
550
+ return profileRef === expectedProfileRef
551
+ ? valid()
552
+ : invalid("evidence profile_ref mismatch");
553
+ }
36
554
  function ensureWorkflowAlignment(record, workflowId) {
37
555
  if (!("workflow_id" in record))
38
556
  return valid();
@@ -147,6 +665,8 @@ export function applyFlowDeskSessionEvidenceWriteIntentsV1(rootDir, intents) {
147
665
  const writtenPaths = [];
148
666
  const root = resolve(rootDir);
149
667
  try {
668
+ const seenTargets = new Set();
669
+ const seenTemps = new Set();
150
670
  for (const intent of intents) {
151
671
  const intentResult = validateSessionEvidenceWriteIntent(intent);
152
672
  if (!intentResult.ok)
@@ -158,6 +678,20 @@ export function applyFlowDeskSessionEvidenceWriteIntentsV1(rootDir, intents) {
158
678
  };
159
679
  const target = safeJoin(root, intent.path);
160
680
  const temp = safeJoin(root, intent.tempPath);
681
+ if (seenTargets.has(target))
682
+ return {
683
+ ...invalid("session evidence batch contains duplicate target path"),
684
+ rootDir: root,
685
+ writtenPaths,
686
+ ...disabledEvidenceAuthority,
687
+ };
688
+ if (seenTemps.has(temp))
689
+ return {
690
+ ...invalid("session evidence batch contains duplicate temp path"),
691
+ rootDir: root,
692
+ writtenPaths,
693
+ ...disabledEvidenceAuthority,
694
+ };
161
695
  if (dirname(target) !== dirname(temp))
162
696
  return {
163
697
  ...invalid("session evidence tempPath must stay beside target path"),
@@ -165,6 +699,12 @@ export function applyFlowDeskSessionEvidenceWriteIntentsV1(rootDir, intents) {
165
699
  writtenPaths,
166
700
  ...disabledEvidenceAuthority,
167
701
  };
702
+ seenTargets.add(target);
703
+ seenTemps.add(temp);
704
+ }
705
+ for (const intent of intents) {
706
+ const target = safeJoin(root, intent.path);
707
+ const temp = safeJoin(root, intent.tempPath);
168
708
  mkdirSync(dirname(target), { recursive: true });
169
709
  writeFileSync(temp, JSON.stringify(intent.record), "utf8");
170
710
  renameSync(temp, target);
@@ -316,6 +856,26 @@ export function reloadFlowDeskSessionEvidenceV1(options) {
316
856
  });
317
857
  continue;
318
858
  }
859
+ const profileAlignment = validateOptionalProfileAlignment(parsed, options.expectedProfileRef);
860
+ if (!profileAlignment.ok) {
861
+ blocked.push({
862
+ evidenceClass,
863
+ evidenceId,
864
+ reason: profileAlignment.errors.join("; "),
865
+ path: expectedRelative,
866
+ });
867
+ continue;
868
+ }
869
+ const freshness = validateOptionalTimestampFreshness(parsed, options.rejectStaleAt);
870
+ if (!freshness.ok) {
871
+ blocked.push({
872
+ evidenceClass,
873
+ evidenceId,
874
+ reason: freshness.errors.join("; "),
875
+ path: expectedRelative,
876
+ });
877
+ continue;
878
+ }
319
879
  entries.push({
320
880
  evidenceClass,
321
881
  evidenceId,
@@ -333,4 +893,24 @@ export function reloadFlowDeskSessionEvidenceV1(options) {
333
893
  };
334
894
  return reloadResult;
335
895
  }
896
+ export function summarizeFlowDeskSessionEvidenceInventoryV1(workflowId, reload) {
897
+ return {
898
+ schema_version: "flowdesk.session_evidence_inventory.v1",
899
+ workflow_id: workflowId,
900
+ total_entries: reload.entries.length,
901
+ total_blocked: reload.blocked.length,
902
+ classes: FLOWDESK_SESSION_EVIDENCE_CLASSES.map((evidenceClass) => {
903
+ const blocked = reload.blocked.filter((entry) => entry.evidenceClass === evidenceClass);
904
+ return {
905
+ evidenceClass,
906
+ valid: reload.entries.filter((entry) => entry.evidenceClass === evidenceClass).length,
907
+ blocked: blocked.length,
908
+ ...(blocked.length === 0
909
+ ? {}
910
+ : { lastBlockedReason: blocked[blocked.length - 1].reason }),
911
+ };
912
+ }),
913
+ ...disabledEvidenceAuthority,
914
+ };
915
+ }
336
916
  //# sourceMappingURL=session-evidence.js.map