@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.1

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 (273) hide show
  1. package/CHANGELOG.md +61 -207
  2. package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
  3. package/dist/adapters/context-transfer/pi-session.js +61 -0
  4. package/dist/application/dag/generate-task-dag.js +19 -75
  5. package/dist/application/task-lifecycle/advance.js +5 -24
  6. package/dist/application/task-lifecycle/observe.js +17 -171
  7. package/dist/application/task-lifecycle/plan-transitions.js +7 -42
  8. package/dist/application/task-lifecycle/recommendations.js +2 -13
  9. package/dist/build-stamp.json +3 -3
  10. package/dist/cli/command-definitions.js +12 -7
  11. package/dist/cli/program.js +23 -6
  12. package/dist/commands/client-recovery.js +0 -3
  13. package/dist/commands/dag-artifact.js +284 -0
  14. package/dist/commands/dag-context.js +184 -0
  15. package/dist/commands/dag-rerun.js +206 -1
  16. package/dist/commands/init.js +1 -27
  17. package/dist/commands/task-advance.js +0 -19
  18. package/dist/executors/dag-pi-executor.js +266 -3792
  19. package/dist/executors/pi-executor.js +4 -15
  20. package/dist/executors/pi-sdk-executor.js +3 -0
  21. package/dist/executors/shell-executor.js +217 -945
  22. package/dist/executors/shell-write-guard.js +0 -7
  23. package/dist/{worker → infrastructure}/console/app-data.js +4 -0
  24. package/dist/infrastructure/console/artifact-revision-store.js +430 -0
  25. package/dist/infrastructure/console/context-export-store.js +160 -0
  26. package/dist/infrastructure/console/dir-lock.js +132 -0
  27. package/dist/infrastructure/console/operation-store.js +197 -0
  28. package/dist/infrastructure/harness/artifact-store.js +10 -1
  29. package/dist/infrastructure/harness/atomic-write.js +12 -2
  30. package/dist/shared/context-transfer/artifact-revision.js +172 -0
  31. package/dist/shared/context-transfer.js +418 -0
  32. package/dist/shared/dag-failure-category.js +0 -12
  33. package/dist/shared/openspec-spec.js +4 -70
  34. package/dist/shared/operator/capabilities.js +14 -7
  35. package/dist/shared/operator/safe-run-summary.js +1 -0
  36. package/dist/shared/path-safety.js +93 -0
  37. package/dist/shared/preview.js +28 -4
  38. package/dist/task/config-types.js +9 -35
  39. package/dist/task/contract/adopt.js +0 -4
  40. package/dist/task/contract/import-revision.js +0 -4
  41. package/dist/task/contract/project.js +0 -3
  42. package/dist/task/contract/schema.js +1 -2
  43. package/dist/task/frontend-project-capability.js +20 -203
  44. package/dist/task/runtime.js +2 -5
  45. package/dist/task/source-prepare/build-draft.js +3 -3
  46. package/dist/task/source-prepare/fragment-inventory.js +9 -15
  47. package/dist/task/source-prepare/prepare.js +1 -89
  48. package/dist/task/source-prepare/semantic-intake.js +2 -6
  49. package/dist/task/source-references.js +1 -22
  50. package/dist/task/task-demand-routing.js +3 -0
  51. package/dist/worker/console/chat/chat-event-store.js +2 -2
  52. package/dist/worker/console/chat/pi-runtime.js +3 -2
  53. package/dist/worker/console/chat/resource-preferences-store.js +1 -1
  54. package/dist/worker/console/chat/routes.js +13 -4
  55. package/dist/worker/console/chat/semantic-activity.js +12 -11
  56. package/dist/worker/console/chat/session-stats.js +96 -0
  57. package/dist/worker/console/chat/session-store.js +1 -1
  58. package/dist/worker/console/chat/turn-process.js +28 -4
  59. package/dist/worker/console/chat/user-questions.js +1 -1
  60. package/dist/worker/console/console-update-runtime.js +1 -1
  61. package/dist/worker/console/context-transfer-diagnostics.js +198 -0
  62. package/dist/worker/console/dag-confirmation.js +1 -1
  63. package/dist/worker/console/dag-execution-receipt.js +1 -1
  64. package/dist/worker/console/doctor.js +1 -1
  65. package/dist/worker/console/draft-store.js +1 -1
  66. package/dist/worker/console/human-gate-token.js +1 -1
  67. package/dist/worker/console/index.js +3 -6
  68. package/dist/worker/console/interview/assessment.js +1 -1
  69. package/dist/worker/console/interview/session.js +1 -1
  70. package/dist/worker/console/operation-runner.js +45 -4
  71. package/dist/worker/console/operation-sse.js +1 -1
  72. package/dist/worker/console/operation-wait.js +1 -1
  73. package/dist/worker/console/operator-actions.js +107 -168
  74. package/dist/worker/console/operator-surface-health.js +1 -1
  75. package/dist/worker/console/operator-user-error.js +169 -0
  76. package/dist/worker/console/pi-plugins.js +60 -1
  77. package/dist/worker/console/routes.js +637 -8
  78. package/dist/worker/console/security.js +35 -0
  79. package/dist/worker/console/server.js +6 -6
  80. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
  81. package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
  82. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
  83. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
  84. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
  85. package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
  86. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
  87. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
  88. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
  89. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
  90. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
  91. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
  92. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
  93. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
  94. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
  95. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
  96. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
  97. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
  98. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
  99. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
  100. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
  101. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
  102. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
  103. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
  104. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
  105. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
  106. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
  107. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
  108. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
  109. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
  110. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
  111. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
  112. package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
  113. package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
  114. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
  115. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
  116. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
  117. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
  118. package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
  119. package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
  120. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
  121. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
  122. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
  123. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
  124. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
  125. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
  126. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
  127. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
  128. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
  129. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
  130. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
  131. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
  132. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
  133. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
  134. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
  135. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
  136. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
  137. package/dist/worker/console/static/index.html +7 -2
  138. package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
  139. package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
  140. package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
  141. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
  142. package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
  143. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
  144. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
  145. package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
  146. package/dist/worker/console/workspace-context.js +28 -112
  147. package/dist/worker/console/workspace-registry.js +2 -2
  148. package/dist/worker/continuation/worker-continuation.js +278 -0
  149. package/dist/worker/observability/read-model.js +4 -0
  150. package/dist/worker/observe/health.js +1 -1
  151. package/dist/worker/observe/node-transparency.js +572 -0
  152. package/dist/worker/observe/routes.js +51 -1
  153. package/dist/worker/observe/static/api.js +69 -5
  154. package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
  155. package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
  156. package/dist/worker/observe/static/dag-node-purpose.js +0 -5
  157. package/dist/worker/observe/static/state.js +3 -1
  158. package/dist/worker/observe/static/styles.css +1037 -126
  159. package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
  160. package/dist/worker/observe/static/views/session-timeline.js +121 -25
  161. package/dist/worker/outcomes/adapters.js +19 -0
  162. package/dist/worker/outcomes/types.js +1 -0
  163. package/dist/worker/pool/attempt-lease.js +97 -66
  164. package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
  165. package/dist/worker/pool/reconcile.js +46 -1
  166. package/dist/worker/pool/run-store.js +2 -0
  167. package/dist/worker/pool/state-projection.js +2 -0
  168. package/dist/worker/task-spec/workflow-routing.js +8 -3
  169. package/dist/workflows/dag/artifact-bindings.js +149 -0
  170. package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
  171. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  172. package/dist/workflows/dag/budget-enforcement.js +10 -0
  173. package/dist/workflows/dag/context-receipt.js +305 -0
  174. package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
  175. package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
  176. package/dist/workflows/dag/context-transfer/renderers.js +93 -0
  177. package/dist/workflows/dag/contract-validator-registrations.js +2 -1
  178. package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
  179. package/dist/workflows/dag/frontend-plan-render.js +1 -2
  180. package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
  181. package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
  182. package/dist/workflows/dag/frontend-recovery-run.js +20 -33
  183. package/dist/workflows/dag/frontend-repair.js +432 -1
  184. package/dist/workflows/dag/frontend-review-context.js +15 -261
  185. package/dist/workflows/dag/frontend-verification-trace.js +24 -249
  186. package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
  187. package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
  188. package/dist/workflows/dag/init-hybrid.js +640 -685
  189. package/dist/workflows/dag/interrupt-request.js +0 -7
  190. package/dist/workflows/dag/node-execution.js +116 -759
  191. package/dist/workflows/dag/path-safety.js +1 -0
  192. package/dist/workflows/dag/prompt.js +30 -38
  193. package/dist/workflows/dag/report.js +1 -37
  194. package/dist/workflows/dag/rerun-feedback.js +1 -256
  195. package/dist/workflows/dag/rerun-plan.js +557 -11
  196. package/dist/workflows/dag/rerun-run.js +601 -38
  197. package/dist/workflows/dag/rerun-task.js +0 -29
  198. package/dist/workflows/dag/retry-policy.js +104 -214
  199. package/dist/workflows/dag/runner.js +142 -430
  200. package/dist/workflows/dag/scheduler.js +16 -114
  201. package/dist/workflows/dag/skill-snapshot.js +17 -0
  202. package/dist/workflows/dag/types.js +195 -246
  203. package/dist/workflows/dag/validate.js +12 -28
  204. package/docs/architecture/runtime-boundaries.md +6 -6
  205. package/docs/architecture/worker-and-feature.md +1 -1
  206. package/docs/init-surface.manifest.json +12 -30
  207. package/docs/skills/vetted-skill-registry.md +2 -4
  208. package/docs/templates/README.md +0 -2
  209. package/docs/templates/agent-dag-report.schema.json +2 -8
  210. package/docs/templates/agent-dag.schema.json +33 -1
  211. package/docs/templates/frontend-implementation-contract.schema.json +1 -4
  212. package/docs/templates/product-line/task.yaml +1 -1
  213. package/harness.json +3 -3
  214. package/package.json +3 -1
  215. package/skills/frontend-bounded-implement/SKILL.md +14 -15
  216. package/skills/frontend-design-review/SKILL.md +41 -22
  217. package/skills/frontend-implementation/SKILL.md +52 -0
  218. package/skills/frontend-implementation/references/code-standards.md +33 -0
  219. package/skills/frontend-implementation/references/design-spec.md +56 -0
  220. package/skills/frontend-implementation/references/node-contracts.md +31 -0
  221. package/skills/frontend-review/SKILL.md +15 -20
  222. package/skills/frontend-review/references/review-findings.md +7 -6
  223. package/skills/frontend-verification/SKILL.md +1 -1
  224. package/skills/loop-agent/references/command-reference.md +6 -1
  225. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  226. package/dist/commands/dag-follow-up.js +0 -138
  227. package/dist/executors/pi-read-budget-policy.js +0 -239
  228. package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
  229. package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
  230. package/dist/worker/console/operation-store.js +0 -389
  231. package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
  232. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
  233. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
  234. package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
  235. package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
  236. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
  237. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
  238. package/dist/worker/console/static-src/active-run-badge.js +0 -17
  239. package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
  240. package/dist/workflows/dag/dag-retry-schema.js +0 -138
  241. package/dist/workflows/dag/frontend-closeout.js +0 -221
  242. package/dist/workflows/dag/frontend-design-policy.js +0 -400
  243. package/dist/workflows/dag/frontend-human-decision.js +0 -182
  244. package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
  245. package/dist/workflows/dag/frontend-read-budgets.js +0 -12
  246. package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
  247. package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
  248. package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
  249. package/dist/workflows/dag/frontend-review-findings.js +0 -270
  250. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
  251. package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
  252. package/dist/workflows/dag/frontend-shape-facts.js +0 -409
  253. package/dist/workflows/dag/frontend-shape.js +0 -427
  254. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
  255. package/dist/workflows/dag/frontend-split-application-service.js +0 -203
  256. package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
  257. package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
  258. package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
  259. package/dist/workflows/dag/frontend-writer-admission.js +0 -285
  260. package/dist/workflows/dag/frontend-writer-status.js +0 -256
  261. package/dist/workflows/dag/recovery-lease.js +0 -80
  262. package/docs/templates/frontend-implementation-dag.json +0 -89
  263. package/docs/templates/spec-registry.schema.json +0 -45
  264. package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
  265. package/skills/frontend-contract/SKILL.md +0 -23
  266. package/skills/frontend-contract/references/contract-protocol.md +0 -34
  267. package/skills/frontend-plan/SKILL.md +0 -26
  268. package/skills/frontend-plan/references/decision-contract.md +0 -37
  269. package/skills/frontend-plan/references/design-decisions.md +0 -17
  270. package/skills/frontend-scout/SKILL.md +0 -25
  271. package/skills/frontend-scout/references/design-evidence.md +0 -16
  272. package/skills/frontend-scout/references/scout-evidence.md +0 -23
  273. /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
@@ -0,0 +1,149 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { canonicalSha256 } from "../../shared/context-transfer.js";
5
+ export function buildArtifactBindingGraph(spec) {
6
+ const consumers = new Map();
7
+ for (const task of spec.tasks) {
8
+ for (const binding of task.consumesArtifacts ?? []) {
9
+ const nodeIds = consumers.get(binding.artifactId) ?? [];
10
+ nodeIds.push(task.id);
11
+ consumers.set(binding.artifactId, nodeIds);
12
+ }
13
+ }
14
+ const artifacts = spec.tasks
15
+ .flatMap((task) => (task.producesArtifacts ?? []).map((artifact) => ({
16
+ ...artifact,
17
+ producerNodeId: task.id,
18
+ directConsumerNodeIds: [...(consumers.get(artifact.artifactId) ?? [])].sort(),
19
+ })))
20
+ .sort((a, b) => a.artifactId.localeCompare(b.artifactId));
21
+ const available = artifacts.length > 0;
22
+ const payload = { schemaVersion: 1, artifacts };
23
+ return {
24
+ ...payload,
25
+ available,
26
+ ...(available ? {} : { reasonCode: "ARTIFACT_BINDING_UNAVAILABLE" }),
27
+ artifactGraphSha256: canonicalSha256(payload),
28
+ };
29
+ }
30
+ function collectDescendants(spec, roots) {
31
+ const children = new Map();
32
+ for (const task of spec.tasks) {
33
+ for (const parent of task.depends_on) {
34
+ const values = children.get(parent) ?? [];
35
+ values.push(task.id);
36
+ children.set(parent, values);
37
+ }
38
+ }
39
+ const queue = [...roots];
40
+ const seen = new Set();
41
+ while (queue.length > 0) {
42
+ const nodeId = queue.shift();
43
+ if (seen.has(nodeId))
44
+ continue;
45
+ seen.add(nodeId);
46
+ queue.push(...(children.get(nodeId) ?? []));
47
+ }
48
+ return spec.tasks.map((task) => task.id).filter((nodeId) => seen.has(nodeId));
49
+ }
50
+ export function computeArtifactImpact(spec, artifactId) {
51
+ const graph = buildArtifactBindingGraph(spec);
52
+ const artifact = graph.artifacts.find((entry) => entry.artifactId === artifactId);
53
+ if (!artifact || artifact.directConsumerNodeIds.length === 0)
54
+ return undefined;
55
+ const affectedNodeIds = collectDescendants(spec, artifact.directConsumerNodeIds);
56
+ const affectedSet = new Set(affectedNodeIds);
57
+ const importedNodeIds = spec.tasks
58
+ .map((task) => task.id)
59
+ .filter((nodeId) => !affectedSet.has(nodeId));
60
+ return {
61
+ artifactId,
62
+ producerNodeId: artifact.producerNodeId,
63
+ directConsumerNodeIds: artifact.directConsumerNodeIds,
64
+ effectiveFromNodeId: affectedNodeIds[0],
65
+ affectedNodeIds,
66
+ importedNodeIds,
67
+ };
68
+ }
69
+ function runtimeArtifactFields(node, kind) {
70
+ if (kind === "structured") {
71
+ return {
72
+ path: node.structuredArtifactPath,
73
+ sha256: node.structuredArtifactSha256,
74
+ schemaId: node.structuredArtifactSchemaId,
75
+ };
76
+ }
77
+ if (kind === "assistant") {
78
+ return { path: node.assistantArtifactPath, sha256: node.assistantSha256 };
79
+ }
80
+ return { path: node.stdoutArtifactPath, sha256: node.stdoutSha256 };
81
+ }
82
+ export async function materializeDeclaredArtifactFacts(input) {
83
+ const facts = [];
84
+ for (const declaration of input.task.producesArtifacts ?? []) {
85
+ const runtime = runtimeArtifactFields(input.node, declaration.kind);
86
+ const base = { ...declaration, revisionEligible: false };
87
+ if (!runtime.path || !runtime.sha256) {
88
+ facts.push({
89
+ ...base,
90
+ status: "missing",
91
+ reasonCode: "ARTIFACT_NOT_MATERIALIZED",
92
+ });
93
+ continue;
94
+ }
95
+ const relativePath = path
96
+ .relative(input.runDir, runtime.path)
97
+ .split(path.sep)
98
+ .join("/");
99
+ if (relativePath !== declaration.path) {
100
+ facts.push({
101
+ ...base,
102
+ status: "mismatch",
103
+ sha256: runtime.sha256,
104
+ reasonCode: "ARTIFACT_PATH_MISMATCH",
105
+ });
106
+ continue;
107
+ }
108
+ if (declaration.schemaId !== runtime.schemaId) {
109
+ facts.push({
110
+ ...base,
111
+ status: "mismatch",
112
+ sha256: runtime.sha256,
113
+ reasonCode: "ARTIFACT_SCHEMA_MISMATCH",
114
+ });
115
+ continue;
116
+ }
117
+ let bytes;
118
+ try {
119
+ bytes = await readFile(runtime.path);
120
+ }
121
+ catch {
122
+ facts.push({
123
+ ...base,
124
+ status: "missing",
125
+ reasonCode: "ARTIFACT_NOT_MATERIALIZED",
126
+ });
127
+ continue;
128
+ }
129
+ const actualSha256 = createHash("sha256").update(bytes).digest("hex");
130
+ if (actualSha256 !== runtime.sha256) {
131
+ facts.push({
132
+ ...base,
133
+ status: "mismatch",
134
+ sha256: actualSha256,
135
+ bytes: bytes.byteLength,
136
+ reasonCode: "ARTIFACT_HASH_MISMATCH",
137
+ });
138
+ continue;
139
+ }
140
+ facts.push({
141
+ ...base,
142
+ status: "materialized",
143
+ sha256: actualSha256,
144
+ bytes: bytes.byteLength,
145
+ revisionEligible: declaration.revisionPolicy === "replace-file",
146
+ });
147
+ }
148
+ return facts;
149
+ }
@@ -0,0 +1,31 @@
1
+ import { backendPytestCollectionFactsSchema, backendTestExecutionReadinessSchema } from "./backend-test-pytest-collection.js";
2
+ import { backendTestCaseManifestSchema } from "./backend-test-case-manifest.js";
3
+ import { backendTestAnalysisContractSchema } from "./backend-test-analysis-contract.js";
4
+ import { backendTestExecutionContractSchema } from "./backend-test-execution-contract.js";
5
+ import { backendTestCaseCoverageFactsSchema } from "./backend-test-case-coverage-analysis.js";
6
+ import { frontendImplementationContractSchema } from "./frontend-implementation-contract.js";
7
+ /**
8
+ * Standalone artifact revision schema registry (exec-plan
9
+ * 2026-08-25-console-node-context-artifact-rerun W4.3 / M4 exit criteria).
10
+ *
11
+ * Maps a frozen produced-artifact `schemaId` to a deterministic zod validator
12
+ * that can check candidate revision bytes without run context. Declared
13
+ * schemaIds without an entry here are rejected fail-closed with
14
+ * ARTIFACT_REVISION_SCHEMA_INVALID — an artifact cannot be staged until its
15
+ * schema is registered. Never guessed, never silently passed.
16
+ */
17
+ const ARTIFACT_REVISION_SCHEMAS = Object.freeze({
18
+ "backend-test-pytest-collection-v3": backendPytestCollectionFactsSchema,
19
+ "backend-test-execution-readiness-v2": backendTestExecutionReadinessSchema,
20
+ "backend-test-case-manifest-v1": backendTestCaseManifestSchema,
21
+ "backend-test-analysis-v2": backendTestAnalysisContractSchema,
22
+ "backend-test-execution-v1": backendTestExecutionContractSchema,
23
+ "backend-test-case-coverage-facts-v4": backendTestCaseCoverageFactsSchema,
24
+ "frontend-implementation-contract-v1": frontendImplementationContractSchema,
25
+ });
26
+ export function resolveArtifactRevisionSchema(schemaId) {
27
+ return ARTIFACT_REVISION_SCHEMAS[schemaId];
28
+ }
29
+ export function listArtifactRevisionSchemaIds() {
30
+ return Object.keys(ARTIFACT_REVISION_SCHEMAS).sort();
31
+ }
@@ -934,7 +934,7 @@ export async function materializeBackendTestResultFromPytestHtml(input) {
934
934
  outcome = "command-error";
935
935
  }
936
936
  const commandSummary = input.commandSummary ??
937
- `PYTHONUTF8=1 PYTHONIOENCODING=utf-8 PYTHONDONTWRITEBYTECODE=1 python -m pytest -v -p no:cacheprovider --html=${htmlRelativePath} --self-contained-html`;
937
+ `PYTHONUTF8=1 PYTHONIOENCODING=utf-8 PYTHONDONTWRITEBYTECODE=1 python reports/backend-test-pytest-launcher.py reports/backend-test-pytest-targets.txt ${htmlRelativePath} -> pytest.main(-v -p no:cacheprovider --self-contained-html)`;
938
938
  assertNoSecrets("commandSummary", commandSummary);
939
939
  const result = backendTestResultContractSchema.parse({
940
940
  schemaVersion: 1,
@@ -8,9 +8,19 @@ export function initRunBudgetLedger(state, budget) {
8
8
  state.budgetLedger = createBudgetLedger(budget);
9
9
  }
10
10
  function wallTimeMs(state, now = Date.now()) {
11
+ const lineage = state.continuation?.budgetLineage;
12
+ if (lineage) {
13
+ return (lineage.inheritedConsumed.wallTimeMs +
14
+ Math.max(0, now - new Date(lineage.inheritedAt).getTime()));
15
+ }
11
16
  return Math.max(0, now - new Date(state.startedAt).getTime());
12
17
  }
13
18
  function repairPasses(state) {
19
+ const lineage = state.continuation?.budgetLineage;
20
+ if (lineage) {
21
+ return (lineage.inheritedConsumed.repairPasses +
22
+ Math.max(0, (state.convergence?.currentPass ?? 1) - 1));
23
+ }
14
24
  return state.convergence?.currentPass ?? 0;
15
25
  }
16
26
  export function applyHardBudgetBreach(state, breach) {
@@ -0,0 +1,305 @@
1
+ import { createHash } from "node:crypto";
2
+ import path from "node:path";
3
+ import { computeContextDigest, effectiveNodeContextV1Schema, } from "../../shared/context-transfer.js";
4
+ import { writeDagNodeBufferArtifact, writeDagNodeJsonArtifact, writeDagNodeTextArtifact, } from "../../infrastructure/harness/artifact-store.js";
5
+ import { resolveDagTaskSourcePath } from "../../task/dag-source-paths.js";
6
+ import { getTaskPaths } from "../../task/runtime.js";
7
+ import { readStoredContractRef } from "../../task/contract/observe.js";
8
+ import { computeCanonicalHash } from "../../task/contract/hash.js";
9
+ import { readFileBoundarySafe } from "./path-safety.js";
10
+ const CONTEXT_FACT_WRITE_OPTIONS = Object.freeze({
11
+ mode: 0o600,
12
+ directoryMode: 0o700,
13
+ });
14
+ function sha256(value) {
15
+ return createHash("sha256").update(value).digest("hex");
16
+ }
17
+ function bytes(value) {
18
+ return Buffer.byteLength(value, "utf8");
19
+ }
20
+ function sourceDocumentMediaType(filePath) {
21
+ const ext = path.extname(filePath).toLowerCase();
22
+ if (ext === ".md" || ext === ".markdown") {
23
+ return "text/markdown; charset=utf-8";
24
+ }
25
+ if (ext === ".txt")
26
+ return "text/plain; charset=utf-8";
27
+ if (ext === ".json")
28
+ return "application/json";
29
+ return "application/octet-stream";
30
+ }
31
+ /**
32
+ * Managed Task Contract facts, materialized so a portable bundle can verify
33
+ * the canonical hash without the run directory. The material carries the full
34
+ * canonical-hash material (including the source hashes the canonical hash is
35
+ * computed from), so a bundle consumer can recompute `computeCanonicalHash`
36
+ * and compare it against the recorded canonicalHash — the JSON is no longer a
37
+ * self-describing blob. The contract prose itself is not re-inlined here: it
38
+ * reached the model through the assembled system prompt (component 0), and
39
+ * declared sources below carry the per-document provenance.
40
+ */
41
+ async function captureTaskContractComponent(input, materialRoot) {
42
+ const binding = input.spec?.taskContractBinding;
43
+ if (!binding)
44
+ return null;
45
+ if (!input.repoRoot) {
46
+ throw new Error("context receipt requires repoRoot to verify managed task contract");
47
+ }
48
+ const contractPath = getTaskPaths(path.resolve(input.repoRoot), binding.taskId).contractPath;
49
+ const ref = await readStoredContractRef(contractPath);
50
+ if (!ref) {
51
+ throw new Error(`context task contract unavailable: ${binding.taskId} (no stored contract.json)`);
52
+ }
53
+ if (ref.canonicalHash !== binding.canonicalHash) {
54
+ throw new Error(`context task contract drift: ${binding.taskId}`);
55
+ }
56
+ const material = {
57
+ schemaVersion: binding.schemaVersion,
58
+ taskId: binding.taskId,
59
+ revision: binding.revision,
60
+ projectionVersion: binding.projectionVersion,
61
+ canonicalizerVersion: binding.canonicalizerVersion,
62
+ taskConfigSchemaVersion: binding.taskConfigSchemaVersion,
63
+ sourceHashes: ref.sourceHashes,
64
+ taskConfigSha256: binding.taskConfigSha256,
65
+ canonicalHash: binding.canonicalHash,
66
+ };
67
+ const recomputed = computeCanonicalHash({
68
+ sourceHashes: material.sourceHashes,
69
+ taskConfigSha256: material.taskConfigSha256,
70
+ projectionVersion: binding.projectionVersion,
71
+ canonicalizerVersion: binding.canonicalizerVersion,
72
+ taskConfigSchemaVersion: binding.taskConfigSchemaVersion,
73
+ });
74
+ if (recomputed !== binding.canonicalHash) {
75
+ throw new Error(`context task contract canonical hash mismatch: ${binding.taskId}`);
76
+ }
77
+ const materialBytes = Buffer.from(`${JSON.stringify(material, null, 2)}\n`, "utf8");
78
+ const materializedPath = `${input.nodeId}/${materialRoot}/task-contract-binding.json`;
79
+ await writeDagNodeBufferArtifact(input.runDir, input.nodeId, `${materialRoot}/task-contract-binding.json`, materialBytes, CONTEXT_FACT_WRITE_OPTIONS);
80
+ return {
81
+ kind: "task-contract",
82
+ logicalName: "managed-task-contract",
83
+ source: {
84
+ type: "managed-task-contract-binding",
85
+ identity: "run.json#taskContractBinding",
86
+ revision: binding.canonicalHash,
87
+ },
88
+ materializedPath,
89
+ sha256: createHash("sha256").update(materialBytes).digest("hex"),
90
+ bytes: materialBytes.byteLength,
91
+ mediaType: "application/json",
92
+ inclusion: "full",
93
+ authoritativeSource: {
94
+ identity: "run.json#taskContractBinding",
95
+ sha256: binding.canonicalHash,
96
+ },
97
+ };
98
+ }
99
+ /**
100
+ * Declared source bindings are contract-level provenance facts, NOT model
101
+ * inputs: at dispatch only the assembled system prompt and user message are
102
+ * sent (dag-pi-executor attaches no files). Their prose is embedded into the
103
+ * system prompt during prompt assembly. Components are therefore recorded as
104
+ * reference-only with hash-verified integrity (drift fails closed) and paths
105
+ * resolved through the authoritative task-source boundary — never as
106
+ * full/excerpt "effective context".
107
+ */
108
+ async function captureSourceContextComponents(input, _materialRoot, startIndex) {
109
+ const binding = input.spec?.sourceBinding;
110
+ if (!binding || binding.sources.length === 0) {
111
+ return { components: [], truncations: [] };
112
+ }
113
+ if (!input.repoRoot) {
114
+ throw new Error("context receipt requires repoRoot to verify declared source documents");
115
+ }
116
+ const components = [];
117
+ const truncations = [];
118
+ for (let i = 0; i < binding.sources.length; i += 1) {
119
+ const declared = binding.sources[i];
120
+ const sourcePath = resolveDagTaskSourcePath({
121
+ workspaceRoot: path.resolve(input.repoRoot),
122
+ taskId: binding.taskId,
123
+ sourcePath: declared.path,
124
+ });
125
+ const sourceDir = getTaskPaths(path.resolve(input.repoRoot), binding.taskId).sourceDir;
126
+ const sourceBytes = await readFileBoundarySafe({
127
+ boundaryRoot: sourceDir,
128
+ targetPath: sourcePath,
129
+ label: `context source ${declared.path}`,
130
+ });
131
+ const sourceSha256 = createHash("sha256").update(sourceBytes).digest("hex");
132
+ if (sourceSha256 !== declared.sha256) {
133
+ throw new Error(`context source drift detected: ${declared.path}`);
134
+ }
135
+ components.push({
136
+ kind: declared.kind === "constraint" ? "execution-constraint" : "context-file",
137
+ logicalName: declared.path,
138
+ source: {
139
+ type: "declared-source-binding",
140
+ identity: `run.json#sourceBinding/sources/${String(i)}`,
141
+ revision: declared.sha256,
142
+ },
143
+ sha256: sourceSha256,
144
+ bytes: sourceBytes.byteLength,
145
+ mediaType: sourceDocumentMediaType(declared.path),
146
+ inclusion: "reference-only",
147
+ authoritativeSource: {
148
+ identity: declared.path,
149
+ sha256: sourceSha256,
150
+ },
151
+ omissionReason: "declared source is contract provenance; its prose was embedded into the assembled system prompt at dispatch and the bytes are not copied into the v1 receipt",
152
+ });
153
+ }
154
+ return { components, truncations };
155
+ }
156
+ async function captureConsumedArtifactComponents(input, _materialRoot, _startIndex) {
157
+ if (!input.spec || (input.task.consumesArtifacts?.length ?? 0) === 0) {
158
+ return { components: [], truncations: [] };
159
+ }
160
+ const components = [];
161
+ const resolvedRunDir = path.resolve(input.runDir);
162
+ for (const binding of input.task.consumesArtifacts ?? []) {
163
+ const producers = input.spec.tasks.flatMap((task) => (task.producesArtifacts ?? [])
164
+ .filter((artifact) => artifact.artifactId === binding.artifactId)
165
+ .map((artifact) => ({ task, artifact })));
166
+ if (producers.length !== 1) {
167
+ if (binding.required) {
168
+ throw new Error(`context artifact binding unavailable: ${binding.artifactId}`);
169
+ }
170
+ continue;
171
+ }
172
+ const producer = producers[0];
173
+ const sourcePath = path.resolve(resolvedRunDir, ...producer.artifact.path.split("/"));
174
+ const sourceBytes = await readFileBoundarySafe({
175
+ boundaryRoot: resolvedRunDir,
176
+ targetPath: sourcePath,
177
+ label: `context artifact ${binding.artifactId}`,
178
+ }).catch(async (error) => {
179
+ const message = error instanceof Error ? error.message : String(error);
180
+ if (/missing|no such|ENOENT|not found/i.test(message) && !binding.required) {
181
+ return undefined;
182
+ }
183
+ throw error;
184
+ });
185
+ if (sourceBytes === undefined)
186
+ continue;
187
+ const sourceSha256 = createHash("sha256").update(sourceBytes).digest("hex");
188
+ components.push({
189
+ kind: "upstream-artifact",
190
+ logicalName: binding.artifactId,
191
+ source: {
192
+ type: "frozen-artifact-binding",
193
+ identity: `run.json#tasks/${producer.task.id}/producesArtifacts/${binding.artifactId}`,
194
+ revision: sourceSha256,
195
+ },
196
+ sha256: sourceSha256,
197
+ bytes: sourceBytes.byteLength,
198
+ mediaType: producer.artifact.mediaType,
199
+ inclusion: "reference-only",
200
+ authoritativeSource: {
201
+ identity: `${producer.task.id}:${producer.artifact.path}`,
202
+ sha256: sourceSha256,
203
+ },
204
+ omissionReason: "upstream artifact is dispatched as a read-tool pointer (path + sha256 + use-read instruction), not as inline content; the consumer must read it through the frozen binding and the bytes are not copied into the v1 receipt",
205
+ });
206
+ }
207
+ return { components, truncations: [] };
208
+ }
209
+ /**
210
+ * Persist the exact Pi dispatch messages before the provider is called. Material
211
+ * bytes are committed first and the validated receipt last, so a crash can only
212
+ * leave an ignorable partial material directory — never a receipt that points at
213
+ * missing bytes.
214
+ */
215
+ export async function writeEffectiveContextReceipt(input) {
216
+ if (!Number.isSafeInteger(input.attempt) || input.attempt < 1) {
217
+ throw new Error("context receipt attempt must be a positive integer");
218
+ }
219
+ const materialRoot = `context-materials/attempt-${input.attempt}`;
220
+ const systemPath = `${input.nodeId}/${materialRoot}/system-prompt.md`;
221
+ const userPath = `${input.nodeId}/${materialRoot}/user-message.md`;
222
+ await writeDagNodeTextArtifact(input.runDir, input.nodeId, `${materialRoot}/system-prompt.md`, input.systemPrompt, CONTEXT_FACT_WRITE_OPTIONS);
223
+ await writeDagNodeTextArtifact(input.runDir, input.nodeId, `${materialRoot}/user-message.md`, input.userMessage, CONTEXT_FACT_WRITE_OPTIONS);
224
+ const taskContractComponent = await captureTaskContractComponent(input, materialRoot);
225
+ const sourceCapture = await captureSourceContextComponents(input, materialRoot, 2 + (taskContractComponent ? 1 : 0));
226
+ const upstreamCapture = await captureConsumedArtifactComponents(input, materialRoot, 2 +
227
+ (taskContractComponent ? 1 : 0) +
228
+ sourceCapture.components.length);
229
+ const extraComponents = [
230
+ ...(taskContractComponent ? [taskContractComponent] : []),
231
+ ...sourceCapture.components,
232
+ ...upstreamCapture.components,
233
+ ];
234
+ const truncations = [
235
+ ...sourceCapture.truncations,
236
+ ...upstreamCapture.truncations,
237
+ ];
238
+ const contextWithoutDigest = {
239
+ schemaVersion: 1,
240
+ identity: {
241
+ runId: input.runId,
242
+ nodeId: input.nodeId,
243
+ attempt: input.attempt,
244
+ capturedAt: input.capturedAt ?? new Date().toISOString(),
245
+ },
246
+ orderedComponents: [
247
+ {
248
+ index: 0,
249
+ kind: "system-prompt",
250
+ logicalName: "dag-pi-system-prompt",
251
+ source: {
252
+ type: "assembled-dag-prompt",
253
+ identity: `run.json#tasks/${input.nodeId}`,
254
+ },
255
+ materializedPath: systemPath,
256
+ sha256: sha256(input.systemPrompt),
257
+ bytes: bytes(input.systemPrompt),
258
+ mediaType: "text/markdown; charset=utf-8",
259
+ inclusion: "full",
260
+ },
261
+ {
262
+ index: 1,
263
+ kind: "user-prompt",
264
+ logicalName: "dag-pi-user-message",
265
+ source: {
266
+ type: "executor-message",
267
+ identity: `dag-pi-user-message/${input.nodeId}`,
268
+ },
269
+ materializedPath: userPath,
270
+ sha256: sha256(input.userMessage),
271
+ bytes: bytes(input.userMessage),
272
+ mediaType: "text/plain; charset=utf-8",
273
+ inclusion: "full",
274
+ },
275
+ ...extraComponents.map((component, offset) => ({
276
+ ...component,
277
+ index: 2 + offset,
278
+ })),
279
+ ],
280
+ promptAssembly: {
281
+ strategy: "dag-pi-system-plus-user-v1",
282
+ finalPromptSha256: sha256(input.systemPrompt),
283
+ truncations,
284
+ },
285
+ boundaries: {
286
+ allowedPaths: [...(input.task.allowedPaths ?? [])],
287
+ forbiddenPaths: [...(input.task.forbiddenPaths ?? [])],
288
+ writeSet: [...(input.task.writeSet ?? [])],
289
+ },
290
+ runtime: {
291
+ executor: "pi",
292
+ resolvedModel: input.resolvedModel,
293
+ skills: [...input.resolvedSkills],
294
+ extensions: [...input.resolvedExtensions],
295
+ activeTools: [...input.activeTools],
296
+ },
297
+ };
298
+ const receipt = effectiveNodeContextV1Schema.parse({
299
+ ...contextWithoutDigest,
300
+ contextDigest: computeContextDigest(contextWithoutDigest),
301
+ });
302
+ const receiptFile = `context-receipts/attempt-${input.attempt}.json`;
303
+ const receiptPath = await writeDagNodeJsonArtifact(input.runDir, input.nodeId, receiptFile, receipt, CONTEXT_FACT_WRITE_OPTIONS);
304
+ return { receipt, receiptPath };
305
+ }