@abelxiaoxing/cadence 1.0.12 → 1.0.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abelxiaoxing/cadence",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Prompts, skills, and a private orchestration extension exposing the Abel four-stage workflow (/abel-init, /abel-design, /abel-implement, /abel-diagnose) with package-owned professional Agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -153,13 +153,16 @@ $ARGUMENTS
153
153
  - 每个 phase 的 Runtime verification contract:只使用 `kind: "vitest"`、`kind: "package-script"`、`kind: "static-check"` 或 `kind: "steps"`;Red 命令 + 预期失败原因;Green 预期行为
154
154
  - `vitest` 明确 runner、安全相对 `testFiles`、`args`、`minTests`;`package-script` 明确 `bun | npm | pnpm | yarn`、真实 script、Gate B 固定的完整 script command 与 `args`;`static-check` 明确本地 executable、`npx` + `noInstall: true` 或安全相对 Node script
155
155
  - 复合验证建模为有序 `steps`:前置检查为 `expected-green`,最后一步匹配 phase classification;不得使用 `&&` 或其他 shell operator
156
+ - 每个 phase 的 `verificationInputs`:每个直接输入恰好绑定为 Gate B 时已存在的 `workspace` 安全普通文件,或唯一 `outputId`
156
157
  - 受影响套件命令;目标范围;验证命令的并行资格及资源锁
157
158
  - 影响闭包(impact closure):`changedSurfaces`、检索命令/命中证据、全部相关既有测试及其 `current-task | regression-task | unaffected` 归类、affected suite 中的既有测试证据
158
159
  - 已批准依赖变化清单(无则 `[]`)
159
160
  - AGENTS 影响:`none | update-existing | create-index | remove-index`
160
161
  - AGENTS 目标索引(`none` 时省略)+ 基于证据的原因;`agentsManagedOnly: true`;AGENTS 验证命令(可执行或静态)
161
- - 每个任务只生成一次固定 `TaskBoundary`:包含稳定 identity、objective/context、逐 phase 精确 read/write、verification、scheduling、dependency、impact closure 与 AGENTS 合同。
162
- 首次 Red 使用 `open-task`,同时携带完整 boundary 与初始 snapshot;后续 Green、Refactor、artifact correction 或 stale refresh 只能使用 `phase-attempt`,仅携带 phase/request identity 与新的动态 snapshot,不得重述或改变 boundary。
162
+ - 将全部任务汇总成唯一、机器可读的 `ImplementGraphBoundary`:graph 持有 `changeId`、完整 tasks 与 outputs;每个 task 显式包含 `dependsOn` 和固定的 objective/context、逐 phase 精确 read/write、verification/verificationInputs、scheduling、impact closure 与 AGENTS 合同。
163
+ 每个 output 显式声明 `id`、安全相对 `path`、producer `taskId/phase` 与 `regular-file` postcondition;同一路径只能有一个 producer,且路径必须在 producer phase write set 中。
164
+ write set 只授予写权限,不证明 artifact 已产生,provenance 不得从 write set 推断。
165
+ Runtime 首先接收一次 `admit-graph`;后续每个阶段只接收 `task-attempt`,包含 change/task/request/phase identity 和新的动态 snapshot,不得重述或改变 graph/task 稳定事实。
163
166
  - **影响闭包审计**:任务修改路由授权、页面状态、API 响应或公共 HTML 结构时,必须用 URL、路由名、handler/template 符号检索所有现有入口和测试。
164
167
  相关 E2E、theme/layout、authorization、HTML/template 与 API contract 测试必须纳入当前写集、绑定明确后续回归任务,或以引用证据证明不受影响。
165
168
  `affected suite` 不得只包含新增测试;例如 `/videos`、`/api/videos` 变化必须覆盖上述全部测试面。
@@ -168,25 +171,31 @@ $ARGUMENTS
168
171
  - 写集未知、过宽或可能重叠的任务不得标为并行;先重塑任务,或用 `conflict-order` 串行化。
169
172
  - 非行为变更任务的 Red 是变更前即可执行的静态验证。
170
173
  仅人工验证的任务不具备实施就绪性,绝不通过 Gate B 或退出;重塑任务直至具备可执行验证。
171
- - Gate B 呈现前,使用 Cadence 与 Implement Runtime 共用的 `src/verification-capability.ts::assessVerificationReadiness` 在 consumer root 校验全部 phase verification contracts。
172
- 仅允许 consumer 已存在且内容与合同完全一致的 package script、可用的显式 package manager、本地 `node_modules` executable,以及 `npx` 的 `noInstall: true`/`--no-install` 语义;绝不允许隐式联网下载、任意 shell 或 shell operator。
173
- 将来才由任务创建的测试/静态输入只有在其精确安全相对路径已列入批准写集时才可暂缺;绝对路径、路径逃逸和符号链接仍关闭失败。
174
+ - Gate B 呈现前,使用 Cadence 与 Implement Runtime 共用的 `src/implement-graph.ts::assessImplementGraphReadiness` 在 consumer root 校验完整 canonical graph;初始 facts 为 completed/blocked tasks 与 applied phases 均为空,且无 candidate overlay。
175
+ Gate B 要求静态 `closure` 为 `{ executable: true, diagnostics: [] }`;尚待前置任务完成是动态 readiness,不使合法 closure 失败。
176
+ 调用方不得自行构造 missing-input 集合或在 graph 外另算可执行性。
177
+ `workspace` binding 在 Gate B 时必须已经是安全普通文件。
178
+ 缺失输入必须绑定唯一 output;跨任务 consumer 必须在 producer 的传递 DAG 后继中;suggested wave、conflict、resource 与 verification lock 均不能代替 `dependsOn`。
179
+ 同一 phase candidate 可以创建并使用自己的 output,更早 phase output 必须先成功应用;Red 不得依赖仅由 Green/Refactor 生产的 output。
180
+ 仅允许内容与合同完全一致的 package script、可用的显式 package manager、本地 `node_modules` executable,以及 `npx` 的 `noInstall: true`/`--no-install` 语义;绝不允许隐式联网下载、任意 shell 或 shell operator。
181
+ 绝对路径、非规范路径、`..`、NUL、root escape、任一已存在组件 symlink、非目录父项及非普通最终输入/output 均关闭失败。
174
182
  不支持的合同以 `design-readiness/verification-contract-unsupported` 诊断关闭;脚本缺失以 `verification-adapter/script-missing` 关闭。
175
- 任何诊断存在时不得呈现 Gate B 为可批准、不得生成 `taskContractsExecutable: true`。
183
+ 任何 closure 诊断存在时不得呈现 Gate B 为可批准,也不得写 ready receipt。
176
184
  - `vitest` 才允许 Runtime 注入 JSON reporter、要求 `minTests` 并用 assertion identity 判定 Red;`package-script` 与 `static-check` 只按退出码及批准的稳定输出 identity 判定,绝不附加 Vitest 参数。
177
185
  `bun run check`、`bun run test:target`、precheck 与 affected suite 都不得由 Runtime 隐式补充;需要时必须成为 Gate B 明确批准的 contract/step。
178
- Design 不生成 argv-only legacy contract。
186
+ Design 只生成上述结构化 contract;argv-only shape 无效。
179
187
  - 范围内每个索引过期发现分配给一个任务,或报告为无关的既有过期问题。
180
188
  - 循环至未决技术决策为零;在内存中备好剩余产物内容/统一 diff。
181
189
 
182
190
  ## ⛔ Gate B —— 批准实施契约
183
191
 
184
192
  - 核实阶段 3/4 忠实展开 Gate A 契约,未引入未批准的新决策。
185
- - 重新运行共享 `assessVerificationReadiness`;只有结果为 `{ taskContractsExecutable: true, diagnostics: [] }` 才可请求 Gate B 批准。
193
+ - 对将写入 receipt 的同一个 `ImplementGraphBoundary` 重新运行 `assessImplementGraphReadiness`;只有静态 closure 为 `{ executable: true, diagnostics: [] }` 才可请求 Gate B 批准。
186
194
  否则以精确 readiness/adapter 诊断返回阶段 3/4 修正,不把缺失 consumer capability 延迟到 Implement Red。
187
195
  - 呈现实质技术决策、任务 DAG/建议波次、前置条件、计划写集/冲突/资源锁、验证映射、AGENTS 影响矩阵与产物物化预览;用户显式批准。
188
196
  - 按写入协议逐个写入剩余就绪产物。
189
- - 最后写 `changeRoot/ready.yaml`:记录 receipt 版本、change/schema、Gate B 批准原文的忠实摘要(含任务 DAG、建议波次、前置条件、计划写集、冲突与资源锁)、共享 capability validator 产生的 `taskContractsExecutable: true` 与空 diagnostics、任务验证与 AGENTS 影响摘要、`gate-a.yaml` 的 SHA-256,以及全部规划产物的规范化相对路径与 SHA-256;排除 `ready.yaml` 自身。
197
+ - 最后写 `changeRoot/ready.yaml`:记录当前 receipt 版本、change/schema、Gate B 批准原文的忠实摘要(含任务 DAG、建议波次、前置条件、计划写集、冲突与资源锁)、唯一 `implementGraph`、`hashImplementGraphBoundary(implementGraph)` 产生的 `implementGraphHash`、`verificationClosure: { executable: true, diagnostics: [] }`、任务验证与 AGENTS 影响摘要、`gate-a.yaml` 的 SHA-256,以及全部规划产物的规范化相对路径与 SHA-256;排除 `ready.yaml` 自身。
198
+ receipt 不保存另一份 task readiness 摘要、Runtime task/session 状态或 retry budget。
190
199
  任务跟踪文件计算 hash 前只将任务完成标记 `- [x]`/`- [X]` 规范化为 `- [ ]`,其余字节不得忽略。
191
200
 
192
201
  ## 回环规则
@@ -210,7 +219,7 @@ $ARGUMENTS
210
219
  - [ ] `openspec validate <name> --strict --type change` 问题为零
211
220
  - [ ] `applyRequires` 中每个产物 id 状态均为 `done`
212
221
  - [ ] `apply.tracks` 解析到 `changeRoot` 内生成的任务产物
213
- - [ ] 产物一致且可追溯;任务 DAG 无环、前置条件可判定、波次及冲突排序有效、计划写集与资源锁完整;每个任务验证契约完整且可执行,无仅人工任务
222
+ - [ ] 产物一致且可追溯;canonical graph/hash 一致,静态 verification closure 无诊断;任务 DAG 无环、前置条件可判定、波次及冲突排序有效、计划写集与资源锁完整;每个任务验证契约完整且可执行,无仅人工任务
214
223
  - [ ] 每个任务的结构化 AGENTS 影响、批准依赖与影响闭包契约完整;仓库索引在 Design 阶段未被修改
215
224
  - [ ] BLOCKING_DECISIONS = 0
216
225
  - [ ] `gate-a.yaml` 与 `ready.yaml` 格式、覆盖范围及全部 hash 校验通过
@@ -56,19 +56,25 @@ Implement 不重新作出或请求 Gate A/B 决策;只有 Gate receipts、arti
56
56
  4. `openspec schema which <schemaName> --json` 读取解析出的 schema.yaml,提取 `apply.tracks` 并相对 `changeRoot` 解析;必须是 `changeRoot` 内一个已存在的具体常规文件。
57
57
  缺失/空/不具体/越界路径一律关闭失败;绝不从 apply 指令的 `contextFiles`/`tasks` 推断跟踪路径。
58
58
  5. `applyRequires` 中每个产物 id 状态必须为 `done`;数组存在或总体完成标记不算数。
59
- 6. 校验 `changeRoot/gate-a.yaml` 与 `changeRoot/ready.yaml`:receipt 版本、change/schema 绑定、批准摘要、artifact 覆盖范围、`gate-a.yaml` hash,以及每个规范化相对路径的 SHA-256。
59
+ 6. 校验 `changeRoot/gate-a.yaml` 与 `changeRoot/ready.yaml`:当前 receipt 版本、change/schema 绑定、批准摘要、artifact 覆盖范围、`gate-a.yaml` hash,以及每个规范化相对路径的 SHA-256。
60
+ `ready.yaml` 必须只含一份 canonical `implementGraph`,且 `implementGraphHash` 必须等于 `hashImplementGraphBoundary(implementGraph)`;`verificationClosure` 必须精确为 `{ executable: true, diagnostics: [] }`。
60
61
  hash 使用文件原始字节;仅对 schema `apply.tracks` 指向的任务文件先把 `- [x]`/`- [X]` 规范化为 `- [ ]`。
61
62
  拒绝绝对路径、`..`、越界与符号链接逃逸。
62
63
  receipt 缺失或任一 hash 失效即关闭失败。
63
64
  7. `openspec validate <name> --strict --type change` 问题为零。
64
65
  8. 阅读 `artifactPaths` 报告的全部规划产物;运行 `openspec instructions apply --change <name> --json` 并遵循其 apply 契约。
65
- 9. 校验稳定 Requirement/Scenario 引用、Requirement → Scenario → Verification → Task 追溯链,以及每个任务的前置条件、`depends_on`、计划写集、冲突/资源锁、派发上下文、验证、批准依赖、结构化 AGENTS 影响和影响闭包契约;缺失、含糊或不可判定时按下方矩阵关闭失败。
66
+ 9. 从 receipt 的 `implementGraph` 校验稳定 Requirement/Scenario 引用、Requirement → Scenario → Verification → Task 追溯链,以及每个任务的前置条件、`dependsOn`、计划写集、冲突/资源锁、派发上下文、验证、批准依赖、结构化 AGENTS 影响和影响闭包契约;缺失、含糊或不可判定时按下方矩阵关闭失败。
66
67
  每个 phase 必须是 Gate B 批准的结构化 `kind: "vitest" | "package-script" | "static-check" | "steps"`;Implement 不从命令固定下标猜测语义,也不隐式运行 `bun run check`、`bun run test:target` 或任何 consumer script。
67
68
  `steps` 按声明顺序执行;precheck 必须是显式 `expected-green` step,不得用 `&&` 或其他 shell operator 合成。
69
+ 每个 phase 的直接 verification input 必须恰好绑定为 `workspace` path 或 graph `outputId`;每个 output 必须有唯一 id/path/producer phase 和 `regular-file` postcondition。
70
+ write set 只授予权限,不能推断 provenance。
68
71
  10. 影响闭包(impact closure):若任务修改路由授权、页面状态、API 响应或公共 HTML,检查 URL/路由/handler/template 检索证据及全部相关既有测试归类。
69
72
  E2E、theme/layout、authorization、HTML/template、API contract 测试必须进入当前写集、明确后续回归任务或有不受影响证据;affected suite 不能只包含新增测试。
70
73
  `/videos`、`/api/videos` 等变化须检查全部这些测试面。
71
- 11. 在注册任务和运行 Red 前,对 ready receipt 的 `taskContractsExecutable: true` 与所有 TaskBoundary verification 重跑共享 `assessVerificationReadiness`。
74
+ 11. 在 graph admission 前,使用 receipt 中同一个 `implementGraph` 重跑共享 `assessImplementGraphReadiness`。
75
+ fresh context 的 facts 只来自父代理在跟踪文件中拥有的 completed tasks、当前进程已知的 blocked tasks 与当前工作区安全扫描;不得因文件碰巧存在而推断 task/phase 完成。
76
+ 静态 closure 必须继续为 `{ executable: true, diagnostics: [] }`;completed producer 的全部 outputs 必须实际为安全普通文件。
77
+ 任一不一致都是 `delivery-invalid` stage blocker,不得调用方另算 missing inputs。
72
78
  package script 的 package manager、名称与完整 command 必须和当前 consumer `package.json` 一致;本地 executable 必须受 `node_modules` 约束;`npx` 只能用 `noInstall: true` 并编译为 `--no-install`,不允许下载。
73
79
  `vitest` 才注入 JSON reporter、应用 `minTests` 并解析 assertion Red identity;`package-script`/`static-check` 不附加 Vitest 参数,只使用退出码和批准的稳定输出 identity。
74
80
  parent-only AGENTS checkpoint 可使用合法的 Node/static contract。
@@ -84,14 +90,16 @@ Implement 不重新作出或请求 Gate A/B 决策;只有 Gate receipts、arti
84
90
 
85
91
  ## 执行图与并行调度(父代理专有)
86
92
 
87
- 1. 从全部未完成任务的直接前置任务构建 DAG,拒绝未知任务、自依赖和环。
93
+ 1. 以 receipt-bound `ImplementGraphBoundary` 为唯一执行图;校验 hash 后先调用一次 `admit-graph`,不得另建 stage graph 或逐任务重述完整 boundary。
94
+ 从 graph tasks 的 `dependsOn` 计算 DAG,拒绝未知任务、自依赖和环。
88
95
  非任务前置条件通过契约检查后,且所有前置任务均已由父代理验收并推进状态,任务才进入 ready 集合。
89
96
  2. 规范化每个计划写集、冲突集和资源锁;写集覆盖测试、fixture、快照与生成输出。
90
97
  拒绝绝对路径、`..`、符号链接逃逸和不可判定的宽泛 glob。
91
98
  Gate receipt、OpenSpec 跟踪文件和 `AGENTS.md` 不属于子代理写集,只能由父代理按契约写入。
92
99
  3. 父代理从 ready 集合计算受可用并发槽约束的批次;仅计划写集两两不相交、无冲突边且共享/验证资源锁兼容的任务可同批。
93
100
  相同路径、祖先/后代目录、共同生成输出或互斥资源均串行;Design 的建议波次只供核对,不替代重新计算。
94
- 4. 每个 ready 任务绑定一个任务局部 worker,并在同一 worker 上通过后续派发连续完成 Red、Green、Refactor,避免把全局上下文复制给 worker。
101
+ 4. 每个 ready task 的首次 Red `task-attempt` 由 Runtime 从已 admitted graph 打开一个 immutable TaskRecord;后续 Green、Refactor、artifact correction 或 stale refresh 仍只提交 `task-attempt` 的 change/task/request/phase identity 与 fresh snapshot。
102
+ 每个 ready 任务绑定一个任务局部 worker,并在同一 worker 上通过后续派发连续完成 Red、Green、Refactor,避免把全局上下文复制给 worker。
95
103
  首次派发只提供相关 AGENTS 内容、任务契约、允许读取/改动范围、可信基线标识与当前阶段;worker 不得广泛探索。
96
104
  5. 同批 worker 并行生成当前阶段的统一 diff 和说明,不得写入任何工作树。
97
105
  父代理按跟踪文件顺序校验基线、实际路径、契约与 diff,再机械应用合格 diff;父代理不得自行补写或修正实现。
@@ -102,6 +110,8 @@ Implement 不重新作出或请求 Gate A/B 决策;只有 Gate receipts、arti
102
110
  禁止无界重试。
103
111
  7. 一批任务稳定后,父代理逐任务完成 AGENTS 检查点和状态推进,再重新计算 ready 集合;任何后继不得提前调度。
104
112
  循环直至 DAG 全部完成。
113
+ 8. 当前 phase candidate 在隔离 checkout apply 后、verification 前必须满足该 phase 的全部 output postconditions;main workspace apply 后、phase progression 前再次检查。
114
+ 跨任务 output 仅在 producer 整个 task completed 后发布;producer blocked/failed 时 consumer 保持 `dependency-blocked` 且不启动 child,producer completed 但 output 缺失或 unsafe 时返回 `producer-output-unavailable`。
105
115
 
106
116
  ## 每个任务的委派式 TDD 循环
107
117
 
@@ -130,12 +140,15 @@ Runtime 只报告当前任务事实,不选择用户恢复动作,也不控制
130
140
 
131
141
  - malformed diff、syntax/import/load、no-test/错误命令、wrong Red identity、重复/无效提交或 Red 候选意外通过:`{ kind: "artifact", code: <closed-artifact-code> }`,其中意外通过使用 `red-not-witnessed`;首次可在共享两次 launch 内修正,耗尽为 `attempts-exhausted`。
132
142
  - stale snapshot 使用 `{ kind: "stale", code: <closed-stale-code> }`;可机械重派的 transport failure 使用 `{ kind: "transport", code: "transport-failure" }`;首次可在共享两次 launch 内刷新或同调用重派,耗尽为 `attempts-exhausted`。
143
+ - artifact、stale 或 transport 耗尽必须返回 `{ kind: "attempts-exhausted", cause, attemptsUsed: 2, lastFailure: { code, stage, details? } }`。
144
+ `lastFailure` 保留最终具体 closed code 与 `child-session-create | child-provider-stream | child-timeout | child-finalization | structural-submit | candidate-retention | candidate-diff | candidate-preflight | parent-review | candidate-apply | agents-checkpoint | phase-runtime` stage。
145
+ 安全 details 只允许 final submit category、有界 submit attempts、schema state、request/role/task/phase 中不匹配的维度名和受约束 verification id;不得返回 prompt、diff、模型原始输出、excerpt、consumer 内容、command/argv、endpoint、credential、环境值或 identity 实际值。
133
146
  - Bubblewrap、依赖路径、测试沙箱或外部环境不可用:`{ kind: "environment", code: <closed-environment-code> }`,当前任务 terminal blocked。
134
147
  - 缺失/漂移的已批准 script、runner、本地 executable 或 verification input:`{ kind: "verification-adapter", code: <closed-adapter-code> }`;`script-missing` 不得误报为 `bubblewrap-or-dependency-unavailable`。
135
148
  - 新路径、依赖、行为、策略、架构、冲突、资源、verification 或 AGENTS 合同:对应 closed `approval-boundary` code,当前任务 terminal blocked,不扩大 boundary。
136
149
  - result size 超限:`{ kind: "result-limit", limitBytes }`,当前任务 terminal blocked,不接受 partial diff。
137
150
 
138
- 可信 delivery 的 receipt/hash/trace/strict failure 发生在 `open-task` 前并成为 `delivery-invalid` stage blocker,不是 TaskFailure。
151
+ 可信 delivery 的 receipt/hash/trace/strict/graph closure failure 发生在 `admit-graph` 前并成为 `delivery-invalid` stage blocker,不是 TaskFailure。
139
152
  预期 Red 失败、artifact defect、stale snapshot、环境失败、已批准 AGENTS checkpoint、已批准文档/测试和 boundary 内兼容修复均不产生阶段选择。
140
153
  重试预算始终有限。
141
154
 
@@ -19,16 +19,34 @@ Design and Implement may run in different contexts.
19
19
  A handoff is trusted only when versioned Gate receipts bind the same change and schema, every covered artifact's normalized relative path and SHA-256 hash is valid, the Gate A receipt hash is valid, OpenSpec strict validation passes, and the artifact graph is complete.
20
20
  Normalize only the tracked task file's completed Markdown checkboxes before hashing; reject absolute paths, `..`, path escapes, and symbolic-link escapes.
21
21
  A missing receipt, invalid hash, or inconsistent artifact is a `delivery-invalid` stage blocker before Implement registers a task.
22
+ The current `ready.yaml` receipt embeds one canonical `implementGraph`, its `implementGraphHash`, and the graph closure result; it has no alternate task-readiness summary.
22
23
 
23
24
  Every approved behavior must retain a stable trace from Requirement to Scenario to Verification to Task.
24
25
  Every task must state exactly one executable verification type, its Red command and expected target failure, Green behavior, affected suite, target files, approved dependency changes, impact-closure evidence, and structured AGENTS impact.
25
26
 
26
- ### Structured verification capability
27
+ ### Graph-proven structured verification
27
28
 
28
- Design and Implement share `src/verification-capability.ts`; Design must call `assessVerificationReadiness` over every phase verification contract before Gate B approval and again immediately before writing `ready.yaml`.
29
- The receipt may state `taskContractsExecutable: true` only when that assessment returns true with no diagnostics.
30
- A future verification input may be absent only when its exact safe relative path is in the task's approved write set.
31
- Missing, escaping, absolute, or symbolic-link inputs remain closed failures.
29
+ Design emits exactly one immutable `ImplementGraphBoundary` for the change.
30
+ It contains every task, each task's explicit `dependsOn`, each phase's `verificationInputs`, and every generated output as an id, safe relative path, producer task and phase, and `regular-file` postcondition.
31
+ A write set grants permission only; it never proves that an output exists.
32
+
33
+ Every direct verification input binds exactly once to either an existing workspace path or a graph output id.
34
+ A workspace binding must already be a safe regular file at Gate B. An output binding must resolve to one unique producer whose path is in that producer phase's write set.
35
+ A cross-task consumer must have the producer as a transitive DAG dependency.
36
+ Suggested waves, conflicts, resources, and verification locks do not create a dependency edge.
37
+ A phase may consume an output created by its own candidate or an earlier applied phase, but never one produced only by a later phase.
38
+
39
+ Design and Implement share `src/implement-graph.ts::assessImplementGraphReadiness`.
40
+ The same core receives the canonical graph, consumer root, current completed and blocked task facts, applied phases, and an optional candidate overlay.
41
+ Gate B and receipt creation require an executable static closure with no diagnostics; current dependency waiting is a dynamic readiness fact and does not invalidate that closure.
42
+ `ready.yaml` stores the exact `implementGraph`, `hashImplementGraphBoundary(implementGraph)` as `implementGraphHash`, and `verificationClosure: { executable: true, diagnostics: [] }`.
43
+
44
+ Runtime admits that same graph once, recomputes readiness before a task launch, checks declared outputs in the isolated candidate before verification, checks them again after main-workspace application and before phase or task completion, and publishes a cross-task output only after its producer task completes.
45
+ A blocked producer keeps its consumers `dependency-blocked`; a completed producer with an absent or unsafe output is `producer-output-unavailable`.
46
+
47
+ Fresh Implement reconstructs availability only from the receipt-bound graph and hash, parent-owned completed task facts, current in-process blocked facts, and a fresh safe scan of the workspace.
48
+ It never infers phase completion merely because a file exists and never persists Runtime state, retry budgets, sessions, or model output.
49
+ All path observations reject absolute or noncanonical paths, `..`, NUL, root escape, a symbolic link in any existing component, a non-directory parent, and a non-regular final input or output.
32
50
 
33
51
  Design emits only the structured Runtime kinds `kind: "vitest"`, `kind: "package-script"`, `kind: "static-check"`, and `kind: "steps"`:
34
52
 
@@ -50,7 +68,7 @@ Bun, npm, pnpm, and Yarn package scripts are allowed only when the named package
50
68
 
51
69
  Runtime never invents `bun run check`, `bun run test:target`, or another consumer script.
52
70
  A precheck or affected verification runs only as an explicit approved contract or ordered step.
53
- Legacy Cadence 1.0.x `bun run test:target <paths>` and `bun run check` inputs remain accepted and are normalized immediately, but Design must not generate new argv-only contracts.
71
+ Argv-only verification contracts are invalid; there is no legacy normalizer or parallel verification schema.
54
72
 
55
73
  An unsupported shape is `design-readiness/verification-contract-unsupported`.
56
74
  A missing approved script is `verification-adapter/script-missing`; other missing or drifted consumer capabilities use their closed `verification-adapter` code.
@@ -74,11 +92,12 @@ When the artifact correction budget is exhausted, terminally block the current I
74
92
  A Red candidate that passes is `{ kind: "artifact", code: "red-not-witnessed" }`; Runtime returns a bounded `{ kind: "retry", scope: "worker", cause: "artifact", remainingAttempts: 1 }`, and candidate success alone does not prove a Design defect.
75
93
  If separate evidence proves that the approved command cannot witness the approved behavior without changing behavior, policy, dependency, architecture, scope, write-set, or verification contract, terminally block the current task as `verification-contract-insufficient` without consuming the artifact correction budget.
76
94
 
77
- ### Implement fixed task boundary
95
+ ### Implement graph and fixed task boundary
78
96
 
79
97
  This boundary applies only to Implement.
80
- The parent registers each ready task once with one immutable `TaskBoundary`; its first Red uses `open-task`, and every later Green, Refactor, correction, or stale refresh uses `phase-attempt` with only phase/request identity and a fresh dynamic snapshot.
81
- The boundary includes all phase-local exact read/write paths, target and affected verification, scheduling declarations, approved dependencies, impact closure, and AGENTS impact.
98
+ The parent submits the receipt-bound graph once with `admit-graph`.
99
+ A ready task's first Red `task-attempt` opens one process-local task record from the graph; every later Green, Refactor, correction, or stale refresh is another `task-attempt` with only change/task/request/phase identity and a fresh dynamic snapshot.
100
+ The immutable task entry includes all phase-local exact read/write paths, verification input bindings, target and affected verification, scheduling declarations, explicit dependencies, approved dependency changes, impact closure, and AGENTS impact.
82
101
  Runtime never expands it.
83
102
  Keep each command, exit code, normalized failure identity, reproducibility result, attribution, and root-cause evidence in context and the final report, not in a state file.
84
103
  Every reproducible pre-existing affected failure remains separate from task Red and may be repaired only when its paths and behavior are already inside the approved boundary.
@@ -125,7 +144,10 @@ Implement reports facts about only the current task.
125
144
  It does not select a user recovery action, recommend another workflow, or claim control over the parent-owned DAG.
126
145
 
127
146
  - Generated artifact defects are closed typed failures: malformed diff, syntax/import/load, no-test or wrong command, wrong Red identity, duplicate/invalid structured result, and `red-not-witnessed`.
128
- - Artifact, stale-snapshot, and transport failures share two non-cancelled launches per phase; exhaustion is `attempts-exhausted` and cancellation is budget-neutral.
147
+ - Artifact, stale-snapshot, and transport failures share two non-cancelled launches per phase; exhaustion is `{ kind: "attempts-exhausted", cause, attemptsUsed: 2, lastFailure: { code, stage, details? } }` and cancellation is budget-neutral.
148
+ - `lastFailure` always preserves the final closed code and stage for artifact, stale, and transport exhaustion.
149
+ Optional details are limited to final submission category, a bounded submit-attempt count, schema state, mismatched identity dimension names, and a validated verification id.
150
+ - Public outcomes never contain a prompt, diff, model output, excerpt, consumer file content, command or argv, endpoint, credential, environment value, or actual/expected identity value.
129
151
  - Bubblewrap, dependency-path, sandbox, or external runtime failure is `{ kind: "environment", code: <closed-environment-code> }` and terminally blocks the current task.
130
152
  - Unsupported verification contracts close Design readiness; missing scripts,
131
153
  runners, local executables, or inputs are closed `verification-adapter` failures
@@ -58,6 +58,7 @@ export interface CandidatePreflightInput {
58
58
  packageManifest: FileBound;
59
59
  lockfile: FileBound;
60
60
  dependencyTarget: FileBound | DirBound;
61
+ candidateOutputsAvailable?: (checkoutRoot: string) => boolean;
61
62
  signal?: AbortSignal;
62
63
  }
63
64
 
@@ -1281,11 +1282,6 @@ export async function preflightCandidate(
1281
1282
  try {
1282
1283
  if (input.signal?.aborted) reject("cancelled", "cancelled");
1283
1284
  if (!validSnapshot(input.snapshot)) reject("artifact", "invalid-snapshot");
1284
- requireCurrentHost(input);
1285
- const validated = validateInput(input);
1286
- targets = validated.targets;
1287
- verifyBaselineAt(input.root, input.baseline);
1288
-
1289
1285
  let root: string;
1290
1286
  try {
1291
1287
  root = dependencies.realpath(input.root);
@@ -1295,8 +1291,12 @@ export async function preflightCandidate(
1295
1291
  const dependencySource = resolveDependencySource(
1296
1292
  dependencies,
1297
1293
  root,
1298
- validated.dependencyPath,
1294
+ "node_modules",
1299
1295
  );
1296
+ requireCurrentHost(input);
1297
+ const validated = validateInput(input);
1298
+ targets = validated.targets;
1299
+ verifyBaselineAt(input.root, input.baseline);
1300
1300
  const prefix = path.join(
1301
1301
  path.dirname(root),
1302
1302
  `.${path.basename(root)}-candidate-`,
@@ -1431,6 +1431,9 @@ export async function preflightCandidate(
1431
1431
  );
1432
1432
  await requireRegularGitModes(dependencies, checkout, input.signal);
1433
1433
  scanCheckout(checkout);
1434
+ if (input.candidateOutputsAvailable?.(checkout) === false) {
1435
+ reject("artifact", "producer-output-unavailable");
1436
+ }
1434
1437
 
1435
1438
  for (const verificationPath of verificationInputPaths(
1436
1439
  validated.verification,
@@ -8,7 +8,13 @@ import {
8
8
  SettingsManager,
9
9
  } from "@earendil-works/pi-coding-agent";
10
10
  import { Type } from "typebox";
11
- import type { ChildFailure, DiffResult, EvidenceResult } from "./contracts.ts";
11
+ import type {
12
+ ChildFailure,
13
+ DiffResult,
14
+ EvidenceResult,
15
+ IdentityDimension,
16
+ SafeFailureDetails,
17
+ } from "./contracts.ts";
12
18
  import { EmptyResourceLoader } from "./empty-resource-loader.ts";
13
19
  import { createScopedTools, TOOL_LIMITS } from "./scoped-tools.ts";
14
20
  import {
@@ -213,6 +219,35 @@ function safeChildError(failure: ChildFailure): string {
213
219
  }
214
220
  }
215
221
 
222
+ function submitDetails(
223
+ classification: SubmitClassification,
224
+ ): SafeFailureDetails {
225
+ const identityMismatch = (
226
+ ["request", "role", "task", "phase"] as IdentityDimension[]
227
+ ).filter((dimension) => !classification.identity[dimension]);
228
+ return {
229
+ finalCategory: classification.finalCategory,
230
+ submitAttempts: Math.min(classification.attempts, 2),
231
+ schema: classification.schema,
232
+ ...(identityMismatch.length > 0 ? { identityMismatch } : {}),
233
+ };
234
+ }
235
+
236
+ function withSubmitDetails(
237
+ failure: ChildFailure,
238
+ classification: SubmitClassification,
239
+ ): ChildFailure {
240
+ return failure.kind === "artifact"
241
+ ? {
242
+ ...failure,
243
+ details: {
244
+ ...failure.details,
245
+ ...submitDetails(classification),
246
+ },
247
+ }
248
+ : failure;
249
+ }
250
+
216
251
  export type ChildSessionResult =
217
252
  | {
218
253
  ok: true;
@@ -350,8 +385,16 @@ export async function runChildSession(input: {
350
385
  };
351
386
  const noStructuralSubmit = (): ChildFailure =>
352
387
  submit.getAttempts() === 0
353
- ? { kind: "artifact", code: "child-no-structural-submit" }
354
- : { kind: "artifact", code: "invalid-structural-result" };
388
+ ? {
389
+ kind: "artifact",
390
+ code: "child-no-structural-submit",
391
+ stage: "child-finalization",
392
+ }
393
+ : {
394
+ kind: "artifact",
395
+ code: "invalid-structural-result",
396
+ stage: "structural-submit",
397
+ };
355
398
  try {
356
399
  abort.signal.throwIfAborted();
357
400
  const creation = createAgentSession({
@@ -411,11 +454,13 @@ export async function runChildSession(input: {
411
454
  const attempts = submit.getAttempts();
412
455
  const classification = classifySession();
413
456
  if (!result || attempts !== 1) {
414
- const failure =
457
+ const failure = withSubmitDetails(
415
458
  submit.getFailure() ??
416
- input.failureOverride?.() ??
417
- transportFailure() ??
418
- noStructuralSubmit();
459
+ input.failureOverride?.() ??
460
+ transportFailure() ??
461
+ noStructuralSubmit(),
462
+ classification,
463
+ );
419
464
  const isTransport = failure.kind === "transport";
420
465
  disposeOnce();
421
466
  return {
@@ -435,6 +480,8 @@ export async function runChildSession(input: {
435
480
  const failure = {
436
481
  kind: "artifact",
437
482
  code: "invalid-structural-result",
483
+ stage: "child-finalization",
484
+ details: submitDetails(classification),
438
485
  } as const;
439
486
  disposeOnce();
440
487
  return {
@@ -471,24 +518,27 @@ export async function runChildSession(input: {
471
518
  ? "cancelled"
472
519
  : "failed";
473
520
  const classification = classifySession();
474
- const failure: ChildFailure = timedOut
475
- ? {
476
- kind: "transport",
477
- code: "child-timeout",
478
- stage: "child-timeout",
479
- }
480
- : failureKind === "cancelled"
481
- ? { kind: "cancelled", code: "cancelled" }
482
- : session === undefined
483
- ? {
484
- kind: "environment",
485
- code: "child-session-create-failed",
486
- stage: "child-session-create",
487
- }
488
- : (submit.getFailure() ??
489
- input.failureOverride?.() ??
490
- transportFailure() ??
491
- noStructuralSubmit());
521
+ const failure: ChildFailure = withSubmitDetails(
522
+ timedOut
523
+ ? {
524
+ kind: "transport",
525
+ code: "child-timeout",
526
+ stage: "child-timeout",
527
+ }
528
+ : failureKind === "cancelled"
529
+ ? { kind: "cancelled", code: "cancelled" }
530
+ : session === undefined
531
+ ? {
532
+ kind: "environment",
533
+ code: "child-session-create-failed",
534
+ stage: "child-session-create",
535
+ }
536
+ : (submit.getFailure() ??
537
+ input.failureOverride?.() ??
538
+ transportFailure() ??
539
+ noStructuralSubmit()),
540
+ classification,
541
+ );
492
542
  const isTransport = failure.kind === "transport";
493
543
  disposeOnce();
494
544
  return {