@tea-agent/loop-agent 0.42.0-next.2 → 0.42.0-next.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 (193) hide show
  1. package/CHANGELOG.md +242 -1
  2. package/dist/application/dag/generate-task-dag.js +75 -19
  3. package/dist/application/task-lifecycle/advance.js +24 -5
  4. package/dist/application/task-lifecycle/observe.js +171 -17
  5. package/dist/application/task-lifecycle/plan-transitions.js +42 -7
  6. package/dist/application/task-lifecycle/recommendations.js +13 -2
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +7 -0
  9. package/dist/cli/program.js +5 -0
  10. package/dist/commands/client-recovery.js +3 -0
  11. package/dist/commands/dag-follow-up.js +138 -0
  12. package/dist/commands/init.js +27 -1
  13. package/dist/commands/task-advance.js +19 -0
  14. package/dist/executors/dag-pi-executor.js +3784 -231
  15. package/dist/executors/pi-executor.js +15 -4
  16. package/dist/executors/pi-read-budget-policy.js +239 -0
  17. package/dist/executors/shell-executor.js +942 -187
  18. package/dist/executors/shell-write-guard.js +7 -0
  19. package/dist/infrastructure/console/operation-store.js +226 -6
  20. package/dist/shared/dag-failure-category.js +12 -0
  21. package/dist/shared/openspec-spec.js +70 -4
  22. package/dist/shared/operator/capabilities.js +7 -0
  23. package/dist/task/config-types.js +34 -5
  24. package/dist/task/contract/adopt.js +4 -0
  25. package/dist/task/contract/import-revision.js +4 -0
  26. package/dist/task/contract/project.js +3 -0
  27. package/dist/task/contract/schema.js +2 -1
  28. package/dist/task/frontend-project-capability.js +203 -20
  29. package/dist/task/runtime.js +5 -2
  30. package/dist/task/source-prepare/build-draft.js +3 -3
  31. package/dist/task/source-prepare/fragment-inventory.js +15 -9
  32. package/dist/task/source-prepare/prepare.js +89 -1
  33. package/dist/task/source-prepare/semantic-intake.js +6 -2
  34. package/dist/task/source-references.js +22 -1
  35. package/dist/worker/console/chat/chat-ui-policy.js +4 -2
  36. package/dist/worker/console/chat/pi-runtime.js +173 -7
  37. package/dist/worker/console/chat/repo-browser.js +10 -3
  38. package/dist/worker/console/chat/routes.js +30 -19
  39. package/dist/worker/console/chat/session-store.js +117 -70
  40. package/dist/worker/console/chat/shortcuts.js +1 -1
  41. package/dist/worker/console/chat/turn-process.js +111 -56
  42. package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
  43. package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
  44. package/dist/worker/console/index.js +3 -0
  45. package/dist/worker/console/operator-actions.js +169 -7
  46. package/dist/worker/console/server.js +3 -0
  47. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DZZ8m3PO.js → abnfDiagram-N423BO3Z-CeznJ4Iw.js} +1 -1
  48. package/dist/worker/console/static/assets/{arc-D6PvaVd-.js → arc-B4u9u7SX.js} +1 -1
  49. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B_OTOiI8.js → architectureDiagram-T3A2C74G-oghpT81p.js} +1 -1
  50. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Bv6rqHBg.js → blockDiagram-VBNYF7ZC-BPJ5Kvcj.js} +1 -1
  51. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B8eHr0oz.js → c4Diagram-5PPSVZJV-CoIu69pd.js} +1 -1
  52. package/dist/worker/console/static/assets/channel-DmIXqJ6B.js +1 -0
  53. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DYwR0im2.js → chunk-2GRJ4B5K-DtgiAsSc.js} +1 -1
  54. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D2WPGqXt.js → chunk-2Q5K7J3B-YSu_EVSD.js} +1 -1
  55. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CQISJ_I7.js → chunk-5RXB4S5H-DaRO-NB6.js} +1 -1
  56. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C0o2Du1e.js → chunk-5VM5RSS4-Dh0ZKiGA.js} +1 -1
  57. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-4f8kr-U7.js → chunk-6Q2QTUOP-DOrvbR-H.js} +1 -1
  58. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D_OWvXzX.js → chunk-GF5L2VYU-C3b22LN2.js} +1 -1
  59. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CasdPz5X.js → chunk-JWPE2WC7-CXlqO8l6.js} +1 -1
  60. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Cj8lRrla.js → chunk-KBJHAD2P-BblTBrDu.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUvD1FSd.js → chunk-RYQCIY6F-DswqPALe.js} +1 -1
  62. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CqLw_eqB.js → chunk-XXDRQBXY-CfTwVOlc.js} +1 -1
  63. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-MFV5Qxb5.js +1 -0
  64. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-MFV5Qxb5.js +1 -0
  65. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ku-WqJPx.js → cose-bilkent-JH36ORCC-bLD8jVFo.js} +1 -1
  66. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-Bq_PYDhl.js → cynefin-VYW2F7L2-BvoG1fh5.js} +1 -1
  67. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BiGZV641.js → cynefinDiagram-MW4NZA55-DEPAdJu3.js} +1 -1
  68. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C4JRlglF.js → dagre-VZM6K2ZE-DmrNvBLy.js} +1 -1
  69. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0dNeWYG.js → diagram-7IWD3JNH-CdwzIwvs.js} +1 -1
  70. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cj35YvYM.js → diagram-B4RE2ZJO-CJ3hj-md.js} +1 -1
  71. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-uzQoJ2-8.js → diagram-LBJQPF4R-C6YJT2a4.js} +1 -1
  72. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D1a-Buoz.js → diagram-Q27KOJAE-C_LPfjhX.js} +1 -1
  73. package/dist/worker/console/static/assets/{diagram-UB23O5K3-XjRrLRSs.js → diagram-UB23O5K3-xvsSb5Ie.js} +1 -1
  74. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Da_O24cW.js → ebnfDiagram-BXEA7PRR-Rxp2tKcD.js} +1 -1
  75. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BLJ8jrYU.js → erDiagram-JOGREHBK-DRyLYmZh.js} +1 -1
  76. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-B9GrLjM0.js → flowDiagram-UKHOOZJN-TLSU_D2B.js} +1 -1
  77. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CeJ0TqiK.js → ganttDiagram-PKOTCBZU-DGqeTvHC.js} +1 -1
  78. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js → gitGraphDiagram-DS77QQ5N-BZxyH2wh.js} +1 -1
  79. package/dist/worker/console/static/assets/index-C8V8K9b4.js +451 -0
  80. package/dist/worker/console/static/assets/index-Cnf_KxTQ.css +1 -0
  81. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DB26i3d8.js → infoDiagram-6WML65LV-BsYtzx01.js} +1 -1
  82. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BOGRyeZT.js → ishikawaDiagram-WSZJBQD7-Qr-ezGv-.js} +1 -1
  83. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CZRoBO_6.js → journeyDiagram-NVQOT4AX-DYbB3ibo.js} +1 -1
  84. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-qlWhJyoB.js → kanban-definition-27J2QSJJ-BHJHewZO.js} +1 -1
  85. package/dist/worker/console/static/assets/{linear-CfUiDDB3.js → linear-CmPIPmCG.js} +1 -1
  86. package/dist/worker/console/static/assets/{mermaid.core-BQe6fpqj.js → mermaid.core-F--C1uV0.js} +5 -5
  87. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-zFzWHw64.js → mindmap-definition-FAOFIHXS-YTXfL1st.js} +1 -1
  88. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DFGUqjZO.js → pegDiagram-VL7TDLO6-DdDMYXP9.js} +1 -1
  89. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BB5i0l8Z.js → pieDiagram-7S7Q4E2Y-C3nH4KVd.js} +1 -1
  90. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-obbVZ_X5.js → quadrantDiagram-CIZ2JOQS-kXyxjG7Y.js} +1 -1
  91. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BwdaNzc1.js → railroadDiagram-AXF67PYL-KNzbl-7w.js} +1 -1
  92. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CkTJaugh.js → requirementDiagram-LRYGKXZP-CSwI6dG0.js} +1 -1
  93. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BwJ-hIgq.js → sankeyDiagram-W5VNT64P-Bl1AyuXy.js} +1 -1
  94. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BzSgmm7w.js → sequenceDiagram-SI44F4Z6-2y4EmXQa.js} +1 -1
  95. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Bn3oj5Q1.js → sizeCapture-X5ZJPWSS-E8v8YrMg.js} +1 -1
  96. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-dxhGtL8K.js → stateDiagram-OKZ733FA-eGGlR856.js} +1 -1
  97. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8e4J3at.js +1 -0
  98. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BLpEInya.js → swimlanes-SLNWSIFB-B7g7xc07.js} +2 -2
  99. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Do88I1Nb.js +8 -0
  100. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ChJGYcXy.js → timeline-definition-Z64GVDOM-DR3VCHBG.js} +1 -1
  101. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DK-qjRer.js → vennDiagram-T6HMQDX7-LUvapZIy.js} +1 -1
  102. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-3qeaWAg-.js → wardleyDiagram-T6FBY63Y-C7GDcaXq.js} +1 -1
  103. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CootlyP9.js → xychartDiagram-ELKLHX3M-CbNAqoGK.js} +1 -1
  104. package/dist/worker/console/static/index.html +2 -2
  105. package/dist/worker/console/static-src/active-run-badge.js +17 -0
  106. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
  107. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
  108. package/dist/worker/console/workspace-context.js +111 -1
  109. package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
  110. package/dist/worker/observe/static/dag-node-purpose.js +5 -0
  111. package/dist/workflows/dag/contract-validator-registrations.js +1 -2
  112. package/dist/workflows/dag/dag-retry-schema.js +138 -0
  113. package/dist/workflows/dag/frontend-closeout.js +221 -0
  114. package/dist/workflows/dag/frontend-design-policy.js +400 -0
  115. package/dist/workflows/dag/frontend-human-decision.js +182 -0
  116. package/dist/workflows/dag/frontend-implementation-contract.js +907 -162
  117. package/dist/workflows/dag/frontend-plan-render.js +2 -1
  118. package/dist/workflows/dag/frontend-prewrite-gate.js +255 -349
  119. package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
  120. package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
  121. package/dist/workflows/dag/frontend-recovery-controller.js +202 -0
  122. package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
  123. package/dist/workflows/dag/frontend-recovery-plan.js +17 -10
  124. package/dist/workflows/dag/frontend-recovery-run.js +33 -20
  125. package/dist/workflows/dag/frontend-repair.js +1 -432
  126. package/dist/workflows/dag/frontend-review-context.js +261 -15
  127. package/dist/workflows/dag/frontend-review-findings.js +270 -0
  128. package/dist/workflows/dag/frontend-shadow-dual-write.js +914 -0
  129. package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
  130. package/dist/workflows/dag/frontend-shape-facts.js +419 -0
  131. package/dist/workflows/dag/frontend-shape.js +435 -0
  132. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
  133. package/dist/workflows/dag/frontend-split-application-service.js +203 -0
  134. package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
  135. package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
  136. package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
  137. package/dist/workflows/dag/frontend-verification-trace.js +249 -24
  138. package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
  139. package/dist/workflows/dag/frontend-writer-admission.js +285 -0
  140. package/dist/workflows/dag/frontend-writer-status.js +256 -0
  141. package/dist/workflows/dag/init-hybrid.js +677 -492
  142. package/dist/workflows/dag/interrupt-request.js +7 -0
  143. package/dist/workflows/dag/node-execution.js +732 -4
  144. package/dist/workflows/dag/prompt.js +34 -1
  145. package/dist/workflows/dag/recovery-lease.js +80 -0
  146. package/dist/workflows/dag/report.js +37 -1
  147. package/dist/workflows/dag/rerun-feedback.js +256 -1
  148. package/dist/workflows/dag/rerun-plan.js +17 -6
  149. package/dist/workflows/dag/rerun-run.js +23 -0
  150. package/dist/workflows/dag/rerun-task.js +29 -0
  151. package/dist/workflows/dag/retry-policy.js +214 -104
  152. package/dist/workflows/dag/runner.js +433 -126
  153. package/dist/workflows/dag/scheduler.js +114 -16
  154. package/dist/workflows/dag/types.js +239 -12
  155. package/dist/workflows/dag/validate.js +28 -12
  156. package/docs/examples/README.md +5 -0
  157. package/docs/init-surface.manifest.json +30 -12
  158. package/docs/skills/vetted-skill-registry.md +4 -2
  159. package/docs/templates/README.md +2 -0
  160. package/docs/templates/agent-dag-report.schema.json +8 -2
  161. package/docs/templates/agent-dag.schema.json +1 -1
  162. package/docs/templates/frontend-implementation-contract.schema.json +4 -1
  163. package/docs/templates/frontend-implementation-dag.json +89 -0
  164. package/docs/templates/spec-registry.schema.json +45 -0
  165. package/harness.json +1 -1
  166. package/package.json +1 -1
  167. package/skills/frontend-bounded-implement/SKILL.md +15 -14
  168. package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
  169. package/skills/frontend-contract/SKILL.md +23 -0
  170. package/skills/frontend-contract/references/contract-protocol.md +34 -0
  171. package/skills/frontend-design-review/SKILL.md +22 -41
  172. package/skills/frontend-plan/SKILL.md +26 -0
  173. package/skills/frontend-plan/references/decision-contract.md +37 -0
  174. package/skills/frontend-plan/references/design-decisions.md +17 -0
  175. package/skills/frontend-review/SKILL.md +20 -15
  176. package/skills/frontend-review/references/review-findings.md +6 -7
  177. package/skills/frontend-scout/SKILL.md +25 -0
  178. package/skills/frontend-scout/references/design-evidence.md +16 -0
  179. package/skills/frontend-scout/references/scout-evidence.md +23 -0
  180. package/skills/frontend-verification/SKILL.md +1 -1
  181. package/skills/loop-agent/references/command-reference.md +1 -0
  182. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  183. package/dist/worker/console/static/assets/channel-BU5gOilw.js +0 -1
  184. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +0 -1
  185. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +0 -1
  186. package/dist/worker/console/static/assets/index-H9rFJiGL.css +0 -1
  187. package/dist/worker/console/static/assets/index-xwu9GxEc.js +0 -451
  188. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +0 -1
  189. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +0 -8
  190. package/skills/frontend-implementation/SKILL.md +0 -52
  191. package/skills/frontend-implementation/references/code-standards.md +0 -33
  192. package/skills/frontend-implementation/references/design-spec.md +0 -56
  193. package/skills/frontend-implementation/references/node-contracts.md +0 -31
@@ -0,0 +1,203 @@
1
+ import { z } from "zod";
2
+ import { assertFrontendSplitBindingConsistency, buildFrontendOperationExecution, buildFrontendSplitAggregateCloseout, completeFrontendSplitIntegration, completeFrontendSplitIntegrationInputSchema, finalizeFrontendSplitAggregate, frontendCommittedFactRefSchema, frontendOperationExecutionSchema, frontendSplitAggregateCloseoutSchema, frontendSplitCandidateBindingSchema, frontendSplitChildObservationSchema, frontendSplitIntegrationBindingSchema, frontendSplitManifestSchema, frontendSplitParentRecordSchema, isFrontendSplitChildReady, observeFrontendSplitChild, prepareFrontendSplitJoin, } from "./frontend-split-orchestrator.js";
3
+ const idSchema = z.string().trim().min(1);
4
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/);
5
+ const positiveIntegerSchema = z.number().int().positive();
6
+ export const frontendSplitProjectionSchema = z.object({
7
+ revision: positiveIntegerSchema,
8
+ execution: frontendOperationExecutionSchema,
9
+ manifest: frontendSplitManifestSchema,
10
+ parent: frontendSplitParentRecordSchema,
11
+ candidateBinding: frontendSplitCandidateBindingSchema.optional(),
12
+ integrationBinding: frontendSplitIntegrationBindingSchema.optional(),
13
+ aggregateCloseout: z.object({ value: frontendSplitAggregateCloseoutSchema, committedRef: frontendCommittedFactRefSchema }).strict().optional(),
14
+ }).strict().superRefine((value, ctx) => {
15
+ if (value.revision !== value.parent.operationRevision || value.execution.kind !== "split-parent" || value.execution.operationId !== value.parent.operationId || value.execution.operationRevision !== value.parent.operationRevision || value.execution.parentRecordDigest !== value.parent.digest)
16
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "revision/execution/parent projection mismatch" });
17
+ if (value.manifest.parentOperationId !== value.parent.operationId || value.manifest.digest !== value.parent.manifestDigest)
18
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "manifest/parent projection mismatch" });
19
+ try {
20
+ assertFrontendSplitBindingConsistency(value);
21
+ }
22
+ catch (error) {
23
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: error instanceof Error ? error.message : "split projection binding mismatch" });
24
+ }
25
+ });
26
+ export function assertFrontendSplitProjectionSuccessor(currentValue, nextValue) {
27
+ const current = frontendSplitProjectionSchema.parse(currentValue);
28
+ const next = frontendSplitProjectionSchema.parse(nextValue);
29
+ if (next.revision !== current.revision + 1 || next.parent.operationRevision !== current.parent.operationRevision + 1)
30
+ throw new Error("split successor revision mismatch");
31
+ if (JSON.stringify(next.manifest) !== JSON.stringify(current.manifest) || next.parent.operationId !== current.parent.operationId || next.parent.generation !== current.parent.generation || next.parent.sourceRunId !== current.parent.sourceRunId || next.parent.sourceDigest !== current.parent.sourceDigest || next.parent.manifestDigest !== current.parent.manifestDigest)
32
+ throw new Error("split successor immutable binding mismatch");
33
+ if (next.parent.operationState === "success" || next.parent.operationTerminal === "success" || next.parent.phase === "closed") {
34
+ if (!next.aggregateCloseout)
35
+ throw new Error("split success requires committed aggregate closeout");
36
+ const finalized = finalizeFrontendSplitAggregate(current.parent, next.aggregateCloseout.value, next.aggregateCloseout.committedRef);
37
+ const expected = frontendSplitProjectionSchema.parse({ ...current, revision: current.revision + 1, parent: finalized.parent, execution: finalized.execution, aggregateCloseout: next.aggregateCloseout });
38
+ if (JSON.stringify(next) !== JSON.stringify(expected))
39
+ throw new Error("split success is not the canonical aggregate successor");
40
+ }
41
+ else if (next.aggregateCloseout)
42
+ throw new Error("non-success successor may not carry aggregate closeout");
43
+ return next;
44
+ }
45
+ const commandBase = { operationId: idSchema, expectedRevision: positiveIntegerSchema, expectedParentDigest: digestSchema, expectedManifestDigest: digestSchema };
46
+ export const frontendSplitWakeupCommandSchema = z.object(commandBase).strict();
47
+ export const frontendSplitChildCallbackCommandSchema = z.object({ ...commandBase, observation: frontendSplitChildObservationSchema }).strict();
48
+ export const frontendSplitIntegrationCallbackCommandSchema = z.object({ ...commandBase, completion: completeFrontendSplitIntegrationInputSchema }).strict();
49
+ export const frontendSplitFinalizeCommandSchema = z.object(commandBase).strict();
50
+ function commandFreshnessMismatch(projection, command) {
51
+ if (projection.parent.operationId !== command.operationId)
52
+ return "operationId";
53
+ if (projection.revision !== command.expectedRevision)
54
+ return "expectedRevision";
55
+ if (projection.parent.digest !== command.expectedParentDigest)
56
+ return "expectedParentDigest";
57
+ if (projection.manifest.digest !== command.expectedManifestDigest)
58
+ return "expectedManifestDigest";
59
+ return undefined;
60
+ }
61
+ function assertCurrent(raw, command) {
62
+ const projection = frontendSplitProjectionSchema.parse(raw);
63
+ if (commandFreshnessMismatch(projection, command))
64
+ throw new Error("frontend split command freshness mismatch");
65
+ return projection;
66
+ }
67
+ function executionForParent(parent) {
68
+ return buildFrontendOperationExecution({ kind: "split-parent", operationId: parent.operationId, operationRevision: parent.operationRevision, sourceRunId: parent.sourceRunId, sourceDigest: parent.sourceDigest, generation: parent.generation, parentRecordDigest: parent.digest });
69
+ }
70
+ function nextProjection(current, patch) {
71
+ return frontendSplitProjectionSchema.parse({ ...current, ...patch, revision: current.revision + 1 });
72
+ }
73
+ export class FrontendSplitOrchestrator {
74
+ ports;
75
+ constructor(ports) {
76
+ this.ports = ports;
77
+ }
78
+ async loadProjection(operationId) {
79
+ const loaded = await this.ports.load(operationId);
80
+ if (!loaded)
81
+ throw new Error(`frontend split operation not found: ${operationId}`);
82
+ return frontendSplitProjectionSchema.parse(loaded);
83
+ }
84
+ async loadCurrent(command) {
85
+ return assertCurrent(await this.loadProjection(command.operationId), command);
86
+ }
87
+ async loadCallbackCurrent(command, fact) {
88
+ const projection = await this.loadProjection(command.operationId);
89
+ const mismatch = commandFreshnessMismatch(projection, command);
90
+ if (!mismatch)
91
+ return projection;
92
+ await this.ports.auditStale({
93
+ operationId: command.operationId,
94
+ reason: "frontend split command freshness mismatch",
95
+ fact: { mismatch, callbackFact: fact },
96
+ });
97
+ return undefined;
98
+ }
99
+ cas(current, next) {
100
+ return this.ports.compareAndSwap({ operationId: current.parent.operationId, expectedRevision: current.revision, expectedExecutionDigest: current.execution.digest, expectedParentDigest: current.parent.digest, next });
101
+ }
102
+ async wakeupChildren(raw) {
103
+ const command = frontendSplitWakeupCommandSchema.parse(raw);
104
+ const current = await this.loadCurrent(command);
105
+ const materialized = [];
106
+ const scheduled = [];
107
+ for (const childId of current.manifest.topologicalOrder) {
108
+ const child = current.manifest.children.find((item) => item.childId === childId);
109
+ const result = await this.ports.materialize({ kind: "child", parentOperationId: current.parent.operationId, manifestDigest: current.manifest.digest, generation: current.parent.generation, taskId: child.taskId, operationId: child.operationId, payloadDigest: current.manifest.digest, allowedPaths: child.allowedPaths, writeSet: child.writeSet, verifyRefs: current.manifest.verifyRefs });
110
+ if (result.taskId !== child.taskId || result.operationId !== child.operationId)
111
+ throw new Error("child materialization binding drift");
112
+ materialized.push(child.operationId);
113
+ const childControllerOwnsScheduling = current.parent.observations.some((observation) => observation.childId === childId && observation.operationId === child.operationId);
114
+ if (!childControllerOwnsScheduling && isFrontendSplitChildReady(current.parent, current.manifest, childId)) {
115
+ await this.ports.schedule({ operationId: child.operationId, generation: current.parent.generation, bindingDigest: current.parent.digest });
116
+ scheduled.push(child.operationId);
117
+ }
118
+ }
119
+ return { materialized, scheduled };
120
+ }
121
+ async childCallback(raw) {
122
+ const command = frontendSplitChildCallbackCommandSchema.parse(raw);
123
+ const current = await this.loadCallbackCurrent(command, command.observation);
124
+ if (!current)
125
+ return { outcome: "ignored-stale" };
126
+ const reduced = observeFrontendSplitChild(current.parent, current.manifest, command.observation);
127
+ if (reduced.outcome === "ignored-stale") {
128
+ await this.ports.auditStale({ operationId: command.operationId, reason: reduced.auditFact.reason, fact: reduced.auditFact });
129
+ return { outcome: "ignored-stale" };
130
+ }
131
+ return this.cas(current, nextProjection(current, { parent: reduced.parent, execution: executionForParent(reduced.parent) }));
132
+ }
133
+ async wakeupIntegration(raw) {
134
+ const command = frontendSplitWakeupCommandSchema.parse(raw);
135
+ const current = await this.loadCurrent(command);
136
+ const integration = current.manifest.integration;
137
+ const materializeAndSchedule = async (bindingDigest) => {
138
+ if (!integration.required || !integration.operationId)
139
+ return;
140
+ const taskId = `${current.parent.operationId}:integration`;
141
+ const result = await this.ports.materialize({ kind: "integration", parentOperationId: current.parent.operationId, manifestDigest: current.manifest.digest, generation: current.parent.generation, taskId, operationId: integration.operationId, payloadDigest: bindingDigest, allowedPaths: integration.allowedPaths, writeSet: integration.writeSet, verifyRefs: integration.verifyRefs });
142
+ if (result.taskId !== taskId || result.operationId !== integration.operationId)
143
+ throw new Error("integration materialization binding drift");
144
+ await this.ports.schedule({ operationId: integration.operationId, generation: current.parent.generation, bindingDigest });
145
+ };
146
+ if (current.parent.phase === "awaiting-integration") {
147
+ if (!integration.required || !current.candidateBinding)
148
+ return { outcome: "not-ready" };
149
+ await materializeAndSchedule(current.candidateBinding.digest);
150
+ return { outcome: "scheduled-existing" };
151
+ }
152
+ const joined = prepareFrontendSplitJoin(current.parent, current.manifest);
153
+ if (joined.outcome === "not-ready")
154
+ return { outcome: "not-ready" };
155
+ if (integration.required) {
156
+ const taskId = `${current.parent.operationId}:integration`;
157
+ const result = await this.ports.materialize({ kind: "integration", parentOperationId: current.parent.operationId, manifestDigest: current.manifest.digest, generation: current.parent.generation, taskId, operationId: integration.operationId, payloadDigest: joined.binding.digest, allowedPaths: integration.allowedPaths, writeSet: integration.writeSet, verifyRefs: integration.verifyRefs });
158
+ if (result.taskId !== taskId || result.operationId !== integration.operationId)
159
+ throw new Error("integration materialization binding drift");
160
+ }
161
+ const next = nextProjection(current, { parent: joined.parent, execution: executionForParent(joined.parent), candidateBinding: joined.binding });
162
+ const applied = await this.cas(current, next);
163
+ if (applied.outcome === "applied" && integration.required)
164
+ await this.ports.schedule({ operationId: integration.operationId, generation: current.parent.generation, bindingDigest: joined.binding.digest });
165
+ return applied;
166
+ }
167
+ async integrationCallback(raw) {
168
+ const command = frontendSplitIntegrationCallbackCommandSchema.parse(raw);
169
+ const current = await this.loadCallbackCurrent(command, command.completion);
170
+ if (!current)
171
+ return { outcome: "ignored-stale" };
172
+ if (!current.candidateBinding)
173
+ throw new Error("candidate binding is missing");
174
+ const completed = completeFrontendSplitIntegration(current.parent, current.manifest, current.candidateBinding, command.completion);
175
+ if (completed.outcome === "ignored-stale") {
176
+ await this.ports.auditStale({ operationId: command.operationId, reason: completed.reason, fact: command.completion });
177
+ return { outcome: "ignored-stale" };
178
+ }
179
+ return this.cas(current, nextProjection(current, { parent: completed.parent, execution: executionForParent(completed.parent), integrationBinding: completed.binding }));
180
+ }
181
+ async finalize(raw) {
182
+ const command = frontendSplitFinalizeCommandSchema.parse(raw);
183
+ const current = await this.loadCurrent(command);
184
+ if (!current.candidateBinding)
185
+ throw new Error("candidate binding is missing");
186
+ const childCloseoutFacts = [];
187
+ for (const child of current.candidateBinding.children) {
188
+ childCloseoutFacts.push(await this.ports.loadChildCloseoutFacts({ childId: child.childId, closeoutRef: child.closeoutRef }));
189
+ }
190
+ const aggregate = buildFrontendSplitAggregateCloseout(current.parent, current.manifest, current.candidateBinding, current.integrationBinding, childCloseoutFacts);
191
+ return this.ports.settleAggregate({
192
+ operationId: current.parent.operationId,
193
+ expectedRevision: current.revision,
194
+ expectedExecutionDigest: current.execution.digest,
195
+ expectedParentDigest: current.parent.digest,
196
+ expectedManifestDigest: current.manifest.digest,
197
+ expectedCandidateBindingDigest: current.candidateBinding.digest,
198
+ expectedIntegrationBindingDigest: current.integrationBinding?.digest,
199
+ childCloseoutFacts,
200
+ aggregate,
201
+ });
202
+ }
203
+ }