@haposoft/cafekit 0.16.7 → 0.18.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 (231) hide show
  1. package/README.md +14 -22
  2. package/bin/__tests__/codex-hooks-ownership.test.js +2 -2
  3. package/bin/__tests__/codex-hooks.test.js +169 -272
  4. package/bin/__tests__/codex-native.test.js +100 -202
  5. package/bin/__tests__/develop-contract.test.js +122 -1413
  6. package/bin/__tests__/docs-sync-on-demand.test.js +93 -0
  7. package/bin/__tests__/grok-envelope.test.js +0 -56
  8. package/bin/__tests__/hook-payload.test.js +4 -6
  9. package/bin/__tests__/legacy-authority-decoupled.test.js +154 -0
  10. package/bin/__tests__/legacy-hooks-retired.test.js +221 -0
  11. package/bin/__tests__/omp-bridge.test.js +20 -17
  12. package/bin/__tests__/omp-hooks.test.js +0 -19
  13. package/bin/__tests__/optional-skill-inventory.test.js +112 -4
  14. package/bin/__tests__/orca-session.test.js +0 -2
  15. package/bin/__tests__/package-inventory.test.js +90 -925
  16. package/bin/__tests__/runtime-dir.test.js +0 -3
  17. package/bin/__tests__/runtime-schema.test.js +3 -2
  18. package/bin/__tests__/skill-routing-source.test.js +27 -15
  19. package/bin/__tests__/spec-narrowing.test.js +30 -161
  20. package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -437
  21. package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
  22. package/bin/__tests__/ui-ux-skill.test.js +101 -0
  23. package/bin/__tests__/usage-hook-retired.test.js +114 -0
  24. package/bin/__tests__/validator-grounding.test.js +18 -2949
  25. package/bin/lib/managed-writer.js +2 -3
  26. package/bin/phases/codex-runtime.js +27 -0
  27. package/bin/phases/copy-payload.js +13 -28
  28. package/bin/phases/omp-runtime.js +25 -0
  29. package/package.json +2 -3
  30. package/src/claude/CLAUDE.md +3 -10
  31. package/src/claude/agents/brainstormer.md +7 -3
  32. package/src/claude/agents/code-auditor.md +44 -56
  33. package/src/claude/agents/debugger.md +8 -88
  34. package/src/claude/agents/deployer.md +3 -5
  35. package/src/claude/agents/docs-keeper.md +6 -14
  36. package/src/claude/agents/git-ops.md +2 -4
  37. package/src/claude/agents/implementer.md +12 -16
  38. package/src/claude/agents/inspector.md +4 -3
  39. package/src/claude/agents/project-manager.md +9 -17
  40. package/src/claude/agents/researcher.md +9 -3
  41. package/src/claude/agents/spec-maker.md +15 -15
  42. package/src/claude/agents/test-runner.md +8 -11
  43. package/src/claude/agents/ui-ux-designer.md +0 -1
  44. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -1
  45. package/src/claude/hooks/__tests__/spec-gate.test.js +244 -333
  46. package/src/claude/hooks/__tests__/spec-state-touched.test.js +160 -0
  47. package/src/claude/hooks/__tests__/state.test.js +68 -0
  48. package/src/claude/hooks/__tests__/statusline.test.js +140 -11
  49. package/src/claude/hooks/agent.cjs +2 -1
  50. package/src/claude/hooks/lib/hook-payload.cjs +2 -2
  51. package/src/claude/hooks/rules.cjs +2 -1
  52. package/src/claude/hooks/session.cjs +0 -1
  53. package/src/claude/hooks/spec-gate.cjs +17 -83
  54. package/src/claude/hooks/spec-state.cjs +142 -39
  55. package/src/claude/hooks/state.cjs +21 -2
  56. package/src/claude/migration-manifest.json +42 -22
  57. package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
  58. package/src/claude/output-styles/coding-level-1-junior.md +3 -3
  59. package/src/claude/output-styles/coding-level-2-mid.md +3 -3
  60. package/src/claude/output-styles/coding-level-3-senior.md +2 -2
  61. package/src/claude/output-styles/coding-level-4-lead.md +5 -5
  62. package/src/claude/output-styles/coding-level-5-god.md +6 -6
  63. package/src/claude/rules/ai-dev-rules.md +2 -3
  64. package/src/claude/rules/hook-protocols.md +8 -15
  65. package/src/claude/rules/manage-docs.md +9 -23
  66. package/src/claude/rules/orchestrator.md +3 -4
  67. package/src/claude/rules/review-audit-self-decision.md +3 -3
  68. package/src/claude/rules/skill-domain-routing.md +1 -3
  69. package/src/claude/rules/skill-workflow-routing.md +4 -5
  70. package/src/claude/rules/state-sync.md +3 -12
  71. package/src/claude/rules/workflow.md +11 -19
  72. package/src/claude/runtime.schema.json +5 -3
  73. package/src/claude/scripts/generate-skill-catalog.cjs +7 -6
  74. package/src/claude/scripts/provenance.cjs +23 -5
  75. package/src/claude/scripts/spec-receipt.cjs +24 -121
  76. package/src/claude/scripts/spec-resolver.cjs +41 -458
  77. package/src/claude/scripts/workflow-policy.cjs +3 -1801
  78. package/src/claude/settings/settings.json +1 -32
  79. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  80. package/src/claude/skills/{question → ask}/SKILL.md +9 -75
  81. package/src/claude/skills/brainstorm/SKILL.md +43 -131
  82. package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
  83. package/src/claude/skills/code-review/SKILL.md +29 -81
  84. package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -8
  85. package/src/claude/skills/debug/SKILL.md +29 -149
  86. package/src/claude/skills/develop/SKILL.md +26 -83
  87. package/src/claude/skills/develop/references/parallel-waves.md +0 -8
  88. package/src/claude/skills/develop/references/quality-gate.md +15 -13
  89. package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
  90. package/src/claude/skills/docs/SKILL.md +2 -2
  91. package/src/claude/skills/docs/references/update-workflow.md +1 -1
  92. package/src/claude/skills/fix/SKILL.md +153 -0
  93. package/src/claude/skills/{hotfix → fix}/references/diagnosis-protocol.md +2 -2
  94. package/src/claude/skills/{hotfix → fix}/references/parallel-patterns.md +2 -2
  95. package/src/claude/skills/{hotfix → fix}/references/prevention-gate.md +3 -3
  96. package/src/claude/skills/{hotfix → fix}/references/review-cycle.md +1 -1
  97. package/src/claude/skills/git/SKILL.md +48 -9
  98. package/src/claude/skills/git/references/commit-protocols.md +35 -16
  99. package/src/claude/skills/git/references/worktree-blueprint.md +42 -6
  100. package/src/claude/skills/orca/SKILL.md +9 -8
  101. package/src/claude/skills/research/SKILL.md +17 -46
  102. package/src/claude/skills/scout/SKILL.md +61 -0
  103. package/src/claude/skills/{inspect → scout}/references/internal-inspection.md +26 -10
  104. package/src/claude/skills/specs/SKILL.md +22 -29
  105. package/src/claude/skills/specs/references/review.md +8 -6
  106. package/src/claude/skills/specs/references/templates.md +34 -41
  107. package/src/claude/skills/sync/SKILL.md +16 -45
  108. package/src/claude/skills/sync/references/rebind-and-audit.md +59 -0
  109. package/src/claude/skills/sync/references/sync-protocols.md +4 -13
  110. package/src/claude/skills/test/SKILL.md +39 -104
  111. package/src/claude/skills/test/references/execution-strategy.md +93 -21
  112. package/src/claude/skills/test/references/failure-triage.md +1 -1
  113. package/src/claude/skills/ui-ux/LICENSE +21 -0
  114. package/src/claude/skills/ui-ux/SKILL.md +497 -0
  115. package/src/claude/skills/ui-ux/references/brand-tokens.md +90 -0
  116. package/src/claude/skills/ui-ux/references/budgets.md +113 -0
  117. package/src/claude/skills/ui-ux/references/checklist.md +271 -0
  118. package/src/claude/skills/ui-ux/references/components/accordion.md +246 -0
  119. package/src/claude/skills/ui-ux/references/components/avatar.md +153 -0
  120. package/src/claude/skills/ui-ux/references/components/banner.md +43 -0
  121. package/src/claude/skills/ui-ux/references/components/breadcrumb.md +201 -0
  122. package/src/claude/skills/ui-ux/references/components/button.md +142 -0
  123. package/src/claude/skills/ui-ux/references/components/card.md +113 -0
  124. package/src/claude/skills/ui-ux/references/components/charts.md +376 -0
  125. package/src/claude/skills/ui-ux/references/components/chat.md +132 -0
  126. package/src/claude/skills/ui-ux/references/components/choice-controls.md +369 -0
  127. package/src/claude/skills/ui-ux/references/components/comment-thread.md +17 -0
  128. package/src/claude/skills/ui-ux/references/components/description-list.md +116 -0
  129. package/src/claude/skills/ui-ux/references/components/empty-state.md +98 -0
  130. package/src/claude/skills/ui-ux/references/components/file-upload.md +107 -0
  131. package/src/claude/skills/ui-ux/references/components/inline-edit.md +128 -0
  132. package/src/claude/skills/ui-ux/references/components/input.md +161 -0
  133. package/src/claude/skills/ui-ux/references/components/list-row.md +56 -0
  134. package/src/claude/skills/ui-ux/references/components/loading.md +198 -0
  135. package/src/claude/skills/ui-ux/references/components/logo.md +147 -0
  136. package/src/claude/skills/ui-ux/references/components/otp-input.md +43 -0
  137. package/src/claude/skills/ui-ux/references/components/quantity-input.md +100 -0
  138. package/src/claude/skills/ui-ux/references/components/range-slider.md +16 -0
  139. package/src/claude/skills/ui-ux/references/components/small-controls.md +340 -0
  140. package/src/claude/skills/ui-ux/references/components/sortable-header.md +86 -0
  141. package/src/claude/skills/ui-ux/references/components/tag-input.md +14 -0
  142. package/src/claude/skills/ui-ux/references/components/timeline.md +38 -0
  143. package/src/claude/skills/ui-ux/references/components/tree.md +30 -0
  144. package/src/claude/skills/ui-ux/references/design-process.md +650 -0
  145. package/src/claude/skills/ui-ux/references/layouts/app-kanban.html +303 -0
  146. package/src/claude/skills/ui-ux/references/layouts/app.md +1369 -0
  147. package/src/claude/skills/ui-ux/references/layouts/form.md +430 -0
  148. package/src/claude/skills/ui-ux/references/layouts/overlay.md +552 -0
  149. package/src/claude/skills/ui-ux/references/layouts/pricing.md +204 -0
  150. package/src/claude/skills/ui-ux/references/locked-rules.md +35 -0
  151. package/src/claude/skills/ui-ux/references/principles.md +408 -0
  152. package/src/claude/skills/ui-ux/references/refactor.md +245 -0
  153. package/src/claude/skills/ui-ux/references/responsive.md +195 -0
  154. package/src/claude/skills/ui-ux/references/review.md +528 -0
  155. package/src/claude/skills/ui-ux/references/rules-color.md +623 -0
  156. package/src/claude/skills/ui-ux/references/rules-form.md +235 -0
  157. package/src/claude/skills/ui-ux/references/rules-state.md +680 -0
  158. package/src/claude/skills/ui-ux/references/rules-type.md +369 -0
  159. package/src/claude/skills/ui-ux/references/styles.md +311 -0
  160. package/src/claude/skills/ui-ux/references/system.md +219 -0
  161. package/src/claude/skills/ui-ux/references/tailwind-v4-traps.md +237 -0
  162. package/src/claude/skills/ui-ux/references/tokens.css +362 -0
  163. package/src/claude/skills/ui-ux/scripts/lint-skill.mjs +216 -0
  164. package/src/claude/skills/ui-ux/scripts/package.json +9 -0
  165. package/src/claude/skills/ui-ux/scripts/probe.mjs +4447 -0
  166. package/src/claude/skills/ui-ux-pro-max/SKILL.md +25 -80
  167. package/src/claude/skills/web-testing/SKILL.md +2 -20
  168. package/src/claude/status.cjs +149 -144
  169. package/src/codex/AGENTS.md +8 -13
  170. package/src/codex/hooks/agent.cjs +2 -1
  171. package/src/codex/hooks/lib/spec-receipt.cjs +4 -32
  172. package/src/codex/hooks/lib/spec-utils.cjs +6 -52
  173. package/src/codex/hooks/rules.cjs +2 -1
  174. package/src/codex/hooks/session.cjs +0 -2
  175. package/src/codex/hooks/spec-gate.cjs +13 -81
  176. package/src/codex/hooks/spec-state.cjs +37 -41
  177. package/src/codex/hooks.json +0 -20
  178. package/src/codex/rules/state-sync.md +3 -12
  179. package/src/common/AGENTS.md +6 -12
  180. package/src/omp/extensions/cafekit-bridge.mjs +6 -6
  181. package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
  182. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
  183. package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
  184. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
  185. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
  186. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
  187. package/src/claude/hooks/__tests__/completion-authority.test.js +0 -990
  188. package/src/claude/hooks/__tests__/semantic-review-authority.test.js +0 -259
  189. package/src/claude/hooks/completion-authority-check.cjs +0 -56
  190. package/src/claude/hooks/completion-authority-state.cjs +0 -527
  191. package/src/claude/hooks/completion-authority.cjs +0 -163
  192. package/src/claude/hooks/lib/context.cjs +0 -616
  193. package/src/claude/hooks/lib/detect.cjs +0 -474
  194. package/src/claude/hooks/semantic-review-authority.cjs +0 -154
  195. package/src/claude/hooks/task-scaffold-guard.cjs +0 -114
  196. package/src/claude/hooks/usage.cjs +0 -197
  197. package/src/claude/scripts/change-firewall.cjs +0 -1748
  198. package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
  199. package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
  200. package/src/claude/scripts/spec-final-state.cjs +0 -290
  201. package/src/claude/scripts/spec-ground.cjs +0 -650
  202. package/src/claude/scripts/spec-readiness.cjs +0 -425
  203. package/src/claude/scripts/spec-scaffold.cjs +0 -2317
  204. package/src/claude/scripts/spec-semantic-model.cjs +0 -396
  205. package/src/claude/scripts/validate-spec-output.cjs +0 -3941
  206. package/src/claude/skills/code-review/references/verification-gate.md +0 -46
  207. package/src/claude/skills/delegate/SKILL.md +0 -124
  208. package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
  209. package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
  210. package/src/claude/skills/hotfix/SKILL.md +0 -289
  211. package/src/claude/skills/inspect/SKILL.md +0 -142
  212. package/src/claude/skills/loop/SKILL.md +0 -114
  213. package/src/claude/skills/loop/references/bounded-loop-protocol.md +0 -104
  214. package/src/claude/skills/loop/references/metric-and-guard-contract.md +0 -76
  215. package/src/claude/skills/route/SKILL.md +0 -94
  216. package/src/claude/skills/route/references/agent-timing.md +0 -46
  217. package/src/claude/skills/route/references/chaining-patterns.md +0 -53
  218. package/src/claude/skills/route/references/task-taxonomy.md +0 -48
  219. package/src/claude/skills/specs/templates/design.md +0 -82
  220. package/src/claude/skills/specs/templates/requirements-init.md +0 -8
  221. package/src/claude/skills/specs/templates/requirements.md +0 -42
  222. package/src/claude/skills/specs/templates/spec-state.json +0 -56
  223. package/src/claude/skills/specs/templates/task.md +0 -47
  224. package/src/codex/hooks/completion-authority-check.cjs +0 -67
  225. package/src/codex/hooks/completion-authority-state.cjs +0 -527
  226. package/src/codex/hooks/completion-authority.cjs +0 -109
  227. package/src/codex/hooks/semantic-review-authority.cjs +0 -130
  228. package/src/codex/hooks/task-scaffold-guard.cjs +0 -63
  229. /package/src/claude/skills/{question → ask}/templates/question.md +0 -0
  230. /package/src/claude/skills/{hotfix → fix}/references/escalation-tactics.md +0 -0
  231. /package/src/claude/skills/{hotfix → fix}/references/workflow-specialized.md +0 -0
@@ -34,15 +34,14 @@ Keep implementation simple, scoped, and verifiable.
34
34
 
35
35
  ## Skill And Tooling Use
36
36
 
37
- - Activate relevant skills before specialized work.
38
- - If a skill plausibly matches the task, prefer its workflow and references over an ad hoc plan.
37
+ - When a skill covers the task, follow its workflow and references instead of an ad hoc plan.
39
38
  - Use documentation lookup when current external docs matter.
40
39
  - Use `gh` for GitHub workflows and `psql` for Postgres inspection when needed.
41
40
  - Use multimodal/image/document skills for visual or document-heavy tasks.
42
41
 
43
42
  ## Git Hygiene
44
43
 
45
- - Lint before commit.
44
+ - Lint before commit when the project has a linter.
46
45
  - Run required tests before push.
47
46
  - Keep commits focused.
48
47
  - Use conventional commits.
@@ -4,28 +4,21 @@ Hooks are instruction boundaries. Do not bypass or work around them.
4
4
 
5
5
  ## Privacy Block Hook
6
6
 
7
- When a tool call is blocked by the privacy hook, the output contains a JSON marker between:
7
+ When a tool call touches a sensitive file, or the hook cannot classify it safely,
8
+ the privacy hook returns a permission decision of `ask` with the reason, and the
9
+ host asks the user to approve or deny that one call. Do not ask again yourself.
10
+ On a host whose hook can only deny, the call is blocked; ask the user instead of
11
+ retrying it another way.
8
12
 
9
- ```text
10
- @@PRIVACY_PROMPT_START@@
11
- ...
12
- @@PRIVACY_PROMPT_END@@
13
- ```
14
-
15
- Required flow:
16
-
17
- 1. Parse the JSON payload from the marker.
18
- 2. Ask the user for approval using the available user-question tool and the prompt/options from the payload.
19
- 3. If approved, retry only the blocked action.
20
- 4. If denied, continue without reading that file or performing that blocked action.
13
+ - If approved, the call runs; do not widen it to other files.
14
+ - If denied, continue without reading that file or performing that blocked action.
21
15
 
22
16
  Never use another command, path, encoding, or side channel to access a privacy-blocked file without explicit approval.
23
17
 
24
18
  ## State And Spec Hooks
25
19
 
26
20
  - If a hook reports state drift, run the appropriate sync/audit flow before continuing.
27
- - If a hook rejects task completion, keep the task `in_progress` or `blocked` until proof exists.
28
- - Do not mark a task `done` unless the matching task file contains a valid verification receipt.
21
+ - If a hook rejects task completion, keep the task `in_progress` or `blocked` until proof exists; the receipt contract lives in `state-sync.md`.
29
22
 
30
23
  ## Hook Failure Handling
31
24
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Living Documents
4
4
 
5
- The project maintains these core documents in `./docs`:
5
+ When the project keeps these core documents in `./docs`, keep them current (a project may have only some of them):
6
6
 
7
7
  | Document | Purpose |
8
8
  |----------|---------|
@@ -14,8 +14,6 @@ The project maintains these core documents in `./docs`:
14
14
  ### Freshness Rule
15
15
 
16
16
  - Before updating any doc, check its last modified date
17
- - If a doc hasn't been updated in >2 weeks while development is active, flag it for review
18
- - The `docs-keeper` agent should proactively scan for stale docs during weekly reviews
19
17
 
20
18
  ## When to Update
21
19
 
@@ -26,7 +24,6 @@ The `docs-keeper` agent is responsible for keeping these documents current. Trig
26
24
  - A significant feature ships or a critical bug is resolved
27
25
  - Security patches are applied or dependencies change
28
26
  - Project scope or timeline shifts
29
- - Weekly progress reviews are due
30
27
 
31
28
  ### Update Discipline
32
29
 
@@ -43,7 +40,7 @@ Use [Keep a Changelog](https://keepachangelog.com/) convention:
43
40
  ## [version] - YYYY-MM-DD
44
41
 
45
42
  ### Added
46
- - Feature description (#PR-number)
43
+ - Feature description (#PR-number when there is one)
47
44
 
48
45
  ### Fixed
49
46
  - Bug fix description (#issue-number)
@@ -74,38 +71,27 @@ specs/
74
71
 
75
72
  Task files are direct children beside `plan.md`; do not place them in a task
76
73
  subdirectory.
77
- The plan records the C1 scope decision, explicit exclusions, acceptance
74
+ The plan records the GATE-SCOPE scope decision, explicit exclusions, acceptance
78
75
  criteria, and task mapping. Each task owns one usable outcome, bounded paths,
79
76
  dependencies, acceptance, and a runnable Verification Plan.
80
77
 
81
78
  ### Gates and execution handoff
82
79
 
83
- - C1: the user chooses EXPAND, KEEP, or CUT before the plan is written.
84
- - C2: the user accepts, rejects, or revises deduplicated adversarial findings.
80
+ - GATE-SCOPE: the user chooses EXPAND, KEEP, or CUT before the plan is written.
81
+ - GATE-REVIEW: the user accepts, rejects, or revises deduplicated adversarial findings.
85
82
  - Specs stops after planning; implementation begins only through a new explicit
86
83
  Develop invocation.
87
- - C3: after execution, current receipts and limitations are shown and the user
84
+ - GATE-DONE: after execution, current receipts and limitations are shown and the user
88
85
  decides whether the feature is complete.
89
86
 
90
87
  ### Task state and proof
91
88
 
92
- Each task contains exactly one `Status:` field. The final inline `## Receipt`
93
- is canonical proof and must contain the exact command, `Exit: 0`,
94
- `Verification: PASS`, runtime-derived Base and Head values, and non-empty
95
- fenced current output before the task becomes done.
89
+ Task status, the inline `## Receipt` and its proof contract are defined in
90
+ `state-sync.md`.
96
91
 
97
92
  Sync only observed state with surgical edits. Re-read the changed task after
98
93
  every update; never infer missing proof, approval, or readiness. When a done
99
94
  task changes user-facing behavior, architecture, API contracts, operations, or
100
95
  project status, classify docs impact and update only affected existing docs.
101
96
 
102
- Comply with the overarching rules in `./rules/ai-dev-rules.md`.
103
-
104
- ## Legacy specification layout
105
-
106
- Existing features containing `spec.json`, nested `tasks/task-R*.md`, or other
107
- legacy kernel artifacts keep their installed adapters and original layout.
108
- Preserve `task_registry`, `semantic_model`, `planning_depth`, lane,
109
- `execution_tier`, machine authority, typed topology, separate receipts, and
110
- feature closeout files. Do not migrate them as part of unrelated documentation
111
- work.
97
+ Comply with the overarching rules in `ai-dev-rules.md`.
@@ -22,10 +22,9 @@ Example prompt:
22
22
 
23
23
  ## Resource Constraints
24
24
 
25
- - Each subagent has a **200K token context window** — scope tasks to fit comfortably within it
26
- - Spawning many parallel agents degrades system performance — check available CPU/memory before scaling out. For parallel implementation waves the cap is 3 concurrent agents by default, never more than 5 (each agent carries the 200K budget above)
25
+ - Each subagent has its own context window — scope tasks to fit comfortably within it
26
+ - Spawning many parallel agents degrades system performance — check available CPU/memory before scaling out. For parallel implementation waves the cap is 3 concurrent agents by default, never more than 5 (each agent carries its own context window)
27
27
  - Prefer fewer, well-scoped agents over many overlapping ones
28
- - Include system resource info (from hook injection) when delegating tasks so subagents can self-regulate
29
28
 
30
29
  ---
31
30
 
@@ -132,7 +131,7 @@ Docs: [docs path]
132
131
 
133
132
  | ❌ Vague | ✅ Precise |
134
133
  |----------|-----------|
135
- | "Pick up where we left off" | "Add the `/users` POST endpoint per `phase-02.md`" |
134
+ | "Pick up where we left off" | "Add the `/users` POST endpoint per `task-02-api.md`" |
136
135
  | "Fix the issues we talked about" | "Add null-check in `auth.ts:45` — root cause: missing input validation" |
137
136
  | "Explore the codebase" | "Read `src/api/routes.ts`, then add the missing handler" |
138
137
  | Dumping 50+ lines of chat history | A 5-line summary with file paths |
@@ -12,10 +12,10 @@ When rejecting an audit concern, name the verification source briefly.
12
12
 
13
13
  ## User Decisions
14
14
 
15
- Do not silently undo an explicit user decision. This covers the C1 scope choice,
16
- C2 finding dispositions, and C3 completion judgement, along with thresholds,
15
+ Do not silently undo an explicit user decision. This covers the GATE-SCOPE scope choice,
16
+ GATE-REVIEW finding dispositions, and GATE-DONE completion judgement, along with thresholds,
17
17
  selected libraries, feature scope, schema shape, pricing, timelines, compliance
18
- choices, and UX trade-offs. Those gates are defined in `workflow.md`; this rule
18
+ choices, and UX trade-offs. Those gates are defined in `state-sync.md`; this rule
19
19
  governs only how a later review may treat them.
20
20
 
21
21
  If an audit suggests reversing a user decision, present:
@@ -27,6 +27,4 @@ an entry condition for the primary. If zero valid capabilities match, continue
27
27
  inline when safe or name the gap. If multiple catalog entries expose the same
28
28
  public identity, do not auto-route; require explicit user disambiguation.
29
29
 
30
- Never infer an optional document capability from this rule. Never select the
31
- explicit-only numeric optimization capability unless the user invokes it with
32
- its required bounded metric/guard contract.
30
+ Never infer an optional document capability from this rule.
@@ -9,9 +9,9 @@ workflow.
9
9
  1. If the user names a valid installed skill, use it directly.
10
10
  2. If one obvious low-risk installed skill covers the intent, use it directly.
11
11
  3. For direct factual conversation, answer directly or use the installed
12
- evidence-answer capability; do not invoke Route or agents for ceremony.
13
- 4. For ambiguous, multi-step, multi-domain, or elevated/high-risk work, use the
14
- installed Route capability to classify and compose the shortest valid chain.
12
+ evidence-answer capability; do not spawn agents for ceremony.
13
+ 4. For ambiguous, multi-step, multi-domain, or elevated/high-risk work, classify
14
+ it yourself and compose the shortest valid chain below.
15
15
 
16
16
  Resolve every abstract link against the current runtime catalog. An absent,
17
17
  invalid, folder-mismatched, duplicate, or retired entry is not routable. Continue
@@ -28,5 +28,4 @@ owner, entry condition, and observable exit per retained link. Diagnosis does
28
28
  not authorize repair; implementation does not authorize commit, push, deploy,
29
29
  publish, or release; no route expands the user's existing authority.
30
30
 
31
- Use `skill-domain-routing.md` to resolve domain capability slots. The numeric
32
- optimization capability remains explicit-only and must never be auto-routed.
31
+ Use `skill-domain-routing.md` to resolve domain capability slots.
@@ -51,19 +51,10 @@ proves only the boundary it executed.
51
51
 
52
52
  ## Human gates and workflow ownership
53
53
 
54
- - C1 records the user's scope decision before the plan is written.
55
- - C2 records the user's disposition of deduplicated adversarial findings.
54
+ - GATE-SCOPE records the user's scope decision before the plan is written.
55
+ - GATE-REVIEW records the user's disposition of deduplicated adversarial findings.
56
56
  - Develop starts only after a new explicit user invocation and executes one
57
57
  unblocked task at a time.
58
58
  - Sync changes only observed file state and never starts implementation.
59
- - C3 occurs after current receipts and limitations are shown; the user decides
59
+ - GATE-DONE occurs after current receipts and limitations are shown; the user decides
60
60
  whether the requested feature is complete.
61
-
62
- ## Legacy compatibility
63
-
64
- Existing packets containing `spec.json`, nested `tasks/task-R*.md`, or other
65
- legacy kernel artifacts stay on their installed adapters. Preserve their
66
- `task_registry`, `semantic_model`, `planning_depth`, lane,
67
- `execution_tier`, typed topology, separate receipts, and feature closeout
68
- contract. Do not migrate that machine authority or storage shape while syncing
69
- an unrelated process-first packet.
@@ -6,16 +6,16 @@ Use the CafeKit loop: **Understand -> Plan -> Execute -> Verify -> Sync**.
6
6
 
7
7
  - Read `./README.md` before feature planning or coding.
8
8
  - Read the active spec/task file when one exists.
9
- - Read and activate any CafeKit skill that likely applies before taking action.
9
+ - Use a CafeKit skill when its description matches the request; how to choose is in `skill-workflow-routing.md`.
10
10
  - Inspect only the code needed to understand the affected area.
11
- - Use `inspect` or focused search when structure is unclear.
11
+ - Use `cf:scout` or focused search when structure is unclear.
12
12
 
13
13
  ## 2. Plan
14
14
 
15
15
  - For non-trivial features, use `/cf:specs` to challenge the minimum scope,
16
- open C1, and create `specs/<feature>/plan.md` with flat
16
+ open GATE-SCOPE, and create `specs/<feature>/plan.md` with flat
17
17
  `task-NN-*.md` files beside it.
18
- - After adversarial review, open C2 and apply only the findings the user accepts
18
+ - After adversarial review, open GATE-REVIEW and apply only the findings the user accepts
19
19
  or revises. Specs never starts implementation.
20
20
  - Start implementation only after a new explicit `/cf:develop` invocation,
21
21
  then select one unblocked task at a time.
@@ -24,16 +24,18 @@ Use the CafeKit loop: **Understand -> Plan -> Execute -> Verify -> Sync**.
24
24
  - `Outcome`
25
25
  - `Scope`
26
26
  - `Ownership`
27
+ - `Steps`
27
28
  - `Acceptance`
28
29
  - `Dependencies`
29
30
  - `Verification Plan`
31
+ - `Failure Protocol`
30
32
  - If these are missing or too vague to verify, route back to spec correction.
31
33
 
32
34
  ## 3. Execute
33
35
 
34
36
  - Implement only the active scope.
35
37
  - Modify existing files directly; do not create duplicate "enhanced" variants.
36
- - Keep named contracts from `design.md` intact.
38
+ - Keep named contracts from the plan and task intact.
37
39
  - Do not use placeholder wiring, process-local stand-ins, or fake adapters as completion proof.
38
40
 
39
41
  ## 4. Verify
@@ -53,16 +55,15 @@ Use the CafeKit loop: **Understand -> Plan -> Execute -> Verify -> Sync**.
53
55
  sole writer of task Status and proof.
54
56
  - Keep exactly one `Status:` field. Write or replace the task's final inline
55
57
  `## Receipt` before setting `Status: done`.
56
- - A canonical Receipt contains the exact command, `Exit: 0`,
57
- `Verification: PASS`, runtime-derived Base and Head values, and non-empty
58
- fenced current output. Never invent, copy, or infer missing proof.
58
+ - The canonical Receipt is defined in `state-sync.md`. Never invent, copy, or
59
+ infer missing proof.
59
60
  - When the binding to Base and Head applies, and what the gate does and does not
60
61
  detect, are stated once in `state-sync.md`.
61
62
  - Re-read each edited task and reconcile its plan row, dependencies, acceptance
62
63
  mapping, status, and receipt without rewriting unrelated bytes.
63
- - Run docs checkpoint when a completed task affects public docs or architecture docs.
64
+ - Update affected existing docs when a completed task changes public or architecture docs.
64
65
  - After all requested work has current proof, show evidence and limitations at
65
- C3. The user decides whether the feature is complete.
66
+ GATE-DONE. The user decides whether the feature is complete.
66
67
 
67
68
  ## Production Or CI Issues
68
69
 
@@ -73,12 +74,3 @@ Use the CafeKit loop: **Understand -> Plan -> Execute -> Verify -> Sync**.
73
74
  5. Review before syncing or shipping.
74
75
 
75
76
  Do not patch symptoms before diagnosis unless the issue is a trivial syntax/type/lint failure with an obvious local cause.
76
-
77
- ## Legacy compatibility
78
-
79
- When an existing feature contains `spec.json`, nested `tasks/task-R*.md`, or
80
- other legacy kernel artifacts, keep using the installed adapter. Preserve its
81
- `task_registry`, `semantic_model`, `planning_depth`, lane,
82
- `execution_tier`, typed boundaries, separate receipts, and final feature
83
- receipt. Do not project that machine authority or storage shape into a new
84
- process-first packet.
@@ -58,7 +58,8 @@
58
58
  "scaffold_guard": {
59
59
  "type": "boolean",
60
60
  "default": true,
61
- "description": "Require task files to be generated by the scaffold script. Set false to write them by hand."
61
+ "deprecated": true,
62
+ "description": "Not honoured. The task-scaffold guard that read this key was removed; the key is kept so existing runtime.json files stay valid."
62
63
  },
63
64
  "tollgate": {
64
65
  "type": "boolean",
@@ -75,12 +76,13 @@
75
76
  "usage": {
76
77
  "type": "object",
77
78
  "additionalProperties": false,
78
- "description": "Usage and quota reporting.",
79
+ "deprecated": true,
80
+ "description": "Not honoured. The usage hook that read this key was removed; the statusline takes quota from the rate_limits Claude Code sends. Kept so existing runtime.json files stay valid.",
79
81
  "properties": {
80
82
  "enabled": {
81
83
  "type": "boolean",
82
84
  "default": true,
83
- "description": "Set false to stop fetching quota data for the statusline."
85
+ "description": "Not honoured. Nothing fetches quota data any more."
84
86
  }
85
87
  }
86
88
  },
@@ -15,12 +15,13 @@ const RETIRED_DIRECTORIES = new Set([
15
15
  'mobile-development',
16
16
  'devops',
17
17
  'react-best-practices',
18
+ 'inspect',
19
+ 'hotfix',
20
+ 'question',
21
+ 'loop',
22
+ 'route',
23
+ 'delegate',
18
24
  ]);
19
- const PUBLIC_SUFFIX_BY_DIRECTORY = {
20
- hotfix: 'fix',
21
- inspect: 'scout',
22
- question: 'ask',
23
- };
24
25
 
25
26
  function usage() {
26
27
  console.log(`Usage:
@@ -124,7 +125,7 @@ function publicIdentity(name) {
124
125
  }
125
126
 
126
127
  function expectedIdentity(directory) {
127
- return `cf:${PUBLIC_SUFFIX_BY_DIRECTORY[directory] || directory}`;
128
+ return `cf:${directory}`;
128
129
  }
129
130
 
130
131
  function diagnostic(code, directory, message) {
@@ -228,13 +228,30 @@ function identity(input) {
228
228
  return { root, specsRoot, specFile, feature, session, mode };
229
229
  }
230
230
 
231
+ // A Stop hook checks every done receipt against one checkout. Without a memo each
232
+ // receipt re-read the whole repository twice, so the gate grew with the number of
233
+ // done tasks (minutes on a large specs root). The memo is opt-in and lives only in
234
+ // the enabling process; every other caller still captures a fresh snapshot.
235
+ const snapshotMemo = new Map();
236
+ let snapshotMemoEnabled = false;
237
+ function enableSnapshotMemo() { snapshotMemoEnabled = true; }
238
+
239
+ function captureSnapshot(root, specsRoot) {
240
+ const key = `${root}\0${specsRoot}`;
241
+ if (snapshotMemoEnabled && snapshotMemo.has(key)) return snapshotMemo.get(key);
242
+ const base = gitBase(root, specsRoot);
243
+ const first = manifest(root, specsRoot);
244
+ const head = manifestDigest(first);
245
+ const second = manifest(root, specsRoot);
246
+ if (JSON.stringify(first) !== JSON.stringify(second) || gitBase(root, specsRoot) !== base) fail('worktree_race', 'checkout changed during provenance capture');
247
+ const snapshot = { base, head };
248
+ if (snapshotMemoEnabled) snapshotMemo.set(key, snapshot);
249
+ return snapshot;
250
+ }
251
+
231
252
  function deriveRuntimeProvenance(input) {
232
253
  const current = identity(input);
233
- const base = gitBase(current.root, current.specsRoot);
234
- const first = manifest(current.root, current.specsRoot);
235
- const head = manifestDigest(first);
236
- const second = manifest(current.root, current.specsRoot);
237
- if (JSON.stringify(first) !== JSON.stringify(second) || gitBase(current.root, current.specsRoot) !== base) fail('worktree_race', 'checkout changed during provenance capture');
254
+ const { base, head } = captureSnapshot(current.root, current.specsRoot);
238
255
  const stable = {
239
256
  schema_version: CONTEXT_SCHEMA_VERSION,
240
257
  project_root: current.root,
@@ -328,6 +345,7 @@ module.exports = {
328
345
  createReceiptBinding,
329
346
  deriveRuntimeContext: deriveRuntimeProvenance,
330
347
  deriveRuntimeProvenance,
348
+ enableSnapshotMemo,
331
349
  isTrustedRuntimeContext,
332
350
  recomputeRuntimeContext: recomputeRuntimeProvenance,
333
351
  recomputeRuntimeProvenance,
@@ -6,12 +6,6 @@ const path = require('path');
6
6
  const { spawnSync } = require('child_process');
7
7
  const { annotatedMarkdownLines } = require('./spec-resolver.cjs');
8
8
 
9
- const EVIDENCE_HEADINGS = new Set([
10
- 'Evidence',
11
- 'Task Test Plan & Verification Evidence',
12
- 'Verification & Evidence',
13
- ]);
14
-
15
9
  function inside(root, target) {
16
10
  const relative = path.relative(path.resolve(root), path.resolve(target));
17
11
  return relative === '' || (relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
@@ -40,34 +34,6 @@ function safeRead(root, relativePath) {
40
34
  }
41
35
  }
42
36
 
43
- function canonicalTaskReceiptPath(taskPath) {
44
- if (typeof taskPath !== 'string') return null;
45
- const match = taskPath.match(/^tasks\/(task-[A-Za-z0-9][A-Za-z0-9._-]*\.md)$/);
46
- return match ? `receipts/${match[1]}` : null;
47
- }
48
-
49
- function evidenceBody(text, policy = {}) {
50
- const lines = String(text || '').split('\n');
51
- let start = -1;
52
- let level = 0;
53
- for (let index = 0; index < lines.length; index += 1) {
54
- const match = lines[index].match(/^(#{2,3})\s+(.+?)\s*$/);
55
- if (match && EVIDENCE_HEADINGS.has(match[2])) {
56
- start = index + 1;
57
- level = match[1].length;
58
- break;
59
- }
60
- }
61
- if (start < 0) return null;
62
- let end = lines.length;
63
- for (let index = start; index < lines.length; index += 1) {
64
- const heading = lines[index].match(/^(#{1,6})\s+/);
65
- const tap = typeof policy.isTapMetadataHeading === 'function' && policy.isTapMetadataHeading(lines[index]);
66
- if (heading && heading[1].length <= level && !tap) { end = index; break; }
67
- }
68
- return lines.slice(start, end).join('\n');
69
- }
70
-
71
37
  function workflowReceiptBody(text, policy = {}) {
72
38
  const lines = annotatedMarkdownLines(text);
73
39
  const starts = [];
@@ -149,11 +115,18 @@ function workflowVerificationCommand(taskText) {
149
115
  if (current) current.push(line);
150
116
  }
151
117
  if (sections.length !== 1) return null;
152
- const commands = sections[0]
153
- .map((line) => line.match(/^\s*-\s+(?:\*\*Command\*\*|Command)\s*:\s*(.*?)\s*$/i))
154
- .filter(Boolean)
118
+ // Only a top-level `- Command:` counts: an indented one belongs to another field such as a
119
+ // Counterexample, and one under a `###` sub-heading is a side step that must not outrank
120
+ // the main block. When commands exist only under sub-headings, they are used as before.
121
+ const commandOf = (line) => line.match(/^-\s+(?:\*\*Command\*\*|Command)\s*:\s*(.*?)\s*$/i);
122
+ const firstSub = sections[0].findIndex((line) => /^###\s+/.test(line));
123
+ const main = (firstSub === -1 ? sections[0] : sections[0].slice(0, firstSub)).map(commandOf).filter(Boolean);
124
+ const commands = (main.length ? main : sections[0].map(commandOf).filter(Boolean))
155
125
  .map((match) => normalizedCommand(match[1]));
156
- return commands.length === 1 ? commands[0] : null;
126
+ // A plan may declare several commands when its proof takes more than one step. The last
127
+ // is canonical: earlier ones are prerequisites, and binding the Receipt to any of them
128
+ // would let a task close on its cheapest step. None declared still fails closed.
129
+ return commands.length >= 1 ? commands[commands.length - 1] : null;
157
130
  }
158
131
 
159
132
  function workflowCommandFailures(taskText, body) {
@@ -167,20 +140,6 @@ function workflowCommandFailures(taskText, body) {
167
140
  : ['command_identity'];
168
141
  }
169
142
 
170
- function plannedField(taskText, name) {
171
- const plan = String(taskText || '').split(/^##\s+Verification Plan\s*$/m)[1];
172
- if (!plan) return null;
173
- const value = fieldValues(plan.split(/^##\s+/m)[0], `- **${name}**`)[0];
174
- return value ? value.replace(/^`|`$/g, '').trim() : null;
175
- }
176
-
177
- function identity(body) {
178
- const names = ['Verification', 'Command', 'Commands', 'Exit', 'Result', 'Base', 'Head', 'base_sha', 'head_sha'];
179
- const fields = names.flatMap((name) => fieldValues(body, name).map((value) => [name.toLowerCase(), value.trim()]));
180
- const artifacts = String(body || '').split('\n').filter((line) => /^\s*Artifacts?\s*:|^\s*Artifact\s+produced\b/i.test(line)).map((line) => line.trim());
181
- return crypto.createHash('sha256').update(JSON.stringify({ fields, artifacts })).digest('hex');
182
- }
183
-
184
143
  function tryGitBytes(root, args) {
185
144
  const result = spawnSync('git', ['-C', root, ...args], { encoding: 'buffer', maxBuffer: 64 * 1024 * 1024 });
186
145
  if (result.error || result.status !== 0) return null;
@@ -240,57 +199,6 @@ function canonicalFailures(body, task, runtimeContext, policy, { bindProvenance
240
199
  return policy.validateCanonicalReceipt(body, options);
241
200
  }
242
201
 
243
- function separateMetadataFailures(body, taskPath, taskText) {
244
- const failures = [];
245
- const basename = path.posix.basename(taskPath);
246
- if (fieldValues(body, 'Task').length !== 1 || fieldValues(body, 'Task')[0] !== basename) failures.push('task_identity');
247
- if (fieldValues(body, 'Task path').length !== 1 || fieldValues(body, 'Task path')[0] !== taskPath) failures.push('task_identity');
248
- if (!concrete(fieldValues(body, 'Expected')[0]) || !concrete(fieldValues(body, 'Observed')[0])) failures.push('expected_observed');
249
- const plannedCommand = plannedField(taskText, 'Command');
250
- const actualCommand = fieldValues(body, 'Command')[0] || fieldValues(body, 'Commands')[0];
251
- if (plannedCommand && !/^N\/A\b/i.test(plannedCommand) && actualCommand !== plannedCommand) failures.push('command_identity');
252
- for (const name of ['Negative path', 'Reachability']) {
253
- const planned = plannedField(taskText, name);
254
- if (planned && !/^(?:N\/A|none|not relevant)\b/i.test(planned) && !concrete(fieldValues(body, name)[0])) failures.push(name.toLowerCase().replace(' ', '_'));
255
- }
256
- return [...new Set(failures)];
257
- }
258
-
259
- function readTaskProof(featureDir, taskPath, policy = {}) {
260
- const receiptPath = canonicalTaskReceiptPath(taskPath);
261
- if (typeof taskPath !== 'string' || !/^tasks\/[^/]+\.md$/.test(taskPath)) return { status: 'unsafe', taskPath, receiptPath: null };
262
- const taskFile = safeRead(featureDir, taskPath);
263
- if (taskFile.status !== 'ok') return { status: taskFile.status, taskPath, receiptPath };
264
- const taskText = taskFile.bytes.toString('utf8');
265
- const separate = receiptPath ? safeRead(featureDir, receiptPath) : { status: 'missing' };
266
- const legacyBody = evidenceBody(taskText, policy);
267
- if (separate.status === 'unsafe') return { status: 'unsafe', taskPath, receiptPath, taskFile };
268
- if (separate.status === 'ok') {
269
- const body = separate.bytes.toString('utf8');
270
- return { status: 'ok', source: 'separate', body, receiptBytes: separate.bytes, receiptFile: separate, taskFile, taskText, taskPath, receiptPath, legacyBody };
271
- }
272
- if (legacyBody !== null) return { status: 'ok', source: 'legacy', body: legacyBody, receiptBytes: Buffer.from(legacyBody), taskFile, taskText, taskPath, receiptPath, legacyBody };
273
- return { status: 'missing', taskPath, receiptPath, taskFile, taskText };
274
- }
275
-
276
- function checkTaskReceipt(featureDir, taskPath, task, runtimeContext, policy) {
277
- const proof = readTaskProof(featureDir, taskPath, policy);
278
- const failures = [];
279
- if (proof.status !== 'ok') return { ...proof, failures: [proof.status === 'unsafe' ? 'unsafe_path' : 'missing_receipt'] };
280
- const status = proof.taskText.split('\n').find((line) => /^\s*(?:\*\*)?Status(?:\*\*)?\s*:/i.test(line));
281
- if (!status || !/\bdone\b/i.test(status)) failures.push('task_status');
282
- failures.push(...canonicalFailures(proof.body, task, runtimeContext, policy));
283
- if (proof.source === 'separate') {
284
- failures.push(...separateMetadataFailures(proof.body, taskPath, proof.taskText));
285
- if (proof.legacyBody !== null
286
- && /^\s*Verification:\s*PASS\s*$/m.test(proof.legacyBody)
287
- && identity(proof.legacyBody) !== identity(proof.body)) failures.push('receipt_conflict');
288
- }
289
- const completedAt = task && task.completed_at;
290
- if (typeof completedAt !== 'string' || !/^\d{4}-\d{2}-\d{2}T/.test(completedAt) || Number.isNaN(Date.parse(completedAt))) failures.push('completed_at');
291
- return { ...proof, failures: [...new Set(failures)] };
292
- }
293
-
294
202
  function checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, policy) {
295
203
  const safeTaskPath = typeof taskPath === 'string' && /^task-[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(taskPath);
296
204
  if (!safeTaskPath) return { status: 'unsafe', taskPath, failures: ['unsafe_path'] };
@@ -354,12 +262,22 @@ const RECEIPT_FIX_HINTS = Object.freeze([
354
262
  ]);
355
263
 
356
264
  /**
357
- * Turn receipt check codes into one instruction naming what to change.
265
+ * Turn receipt check codes into one instruction naming what to change. When the receipt
266
+ * body is available, a provenance failure is refined: telling someone to add lines they
267
+ * already wrote sends them looking in the wrong place, and the common cause is a pair
268
+ * typed by hand — git short SHAs — rather than the pair this runtime derives.
358
269
  */
359
- function receiptFixHint(failures) {
270
+ function receiptFixHint(failures, body) {
360
271
  const codes = new Set(Array.isArray(failures) ? failures : []);
361
272
  const hints = RECEIPT_FIX_HINTS.filter(([code]) => codes.has(code)).map(([, hint]) => hint);
362
273
  if (hints.length === 0) return null;
274
+ if (codes.has('provenance') && typeof body === 'string'
275
+ && fieldValues(body, 'Base').length > 0 && fieldValues(body, 'Head').length > 0) {
276
+ const index = hints.length - 1;
277
+ hints[index] = 'the `Base:` and `Head:` lines are present but are not the pair this runtime derives'
278
+ + ' — re-derive them (`Base` is a 40-character commit id, `Head` a 64-character tree digest);'
279
+ + ' git short SHAs typed by hand never match';
280
+ }
363
281
  return hints.length === 1 ? hints[0] : `${hints.slice(0, -1).join('; ')}; and ${hints[hints.length - 1]}`;
364
282
  }
365
283
 
@@ -409,32 +327,17 @@ function checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession, policy
409
327
  for (const taskPath of doneTasks) {
410
328
  const proof = checkWorkflowTaskReceipt(candidate.featureDir, taskPath, runtimeContext, policy);
411
329
  if (proof.failures.length > 0) {
412
- failures.push({ featureName: candidate.featureName, taskPath, failures: proof.failures });
330
+ failures.push({ featureName: candidate.featureName, taskPath, failures: proof.failures, body: proof.body });
413
331
  }
414
332
  }
415
333
  }
416
334
  return { failures };
417
335
  }
418
336
 
419
- function checkFeatureReceipt(featureDir, runtimeContext, policy) {
420
- const receipt = safeRead(featureDir, 'feature-receipt.md');
421
- if (receipt.status !== 'ok') return { status: receipt.status, failures: [receipt.status === 'unsafe' ? 'unsafe_path' : 'missing_receipt'] };
422
- const body = receipt.bytes.toString('utf8');
423
- const failures = canonicalFailures(body, {}, runtimeContext, policy);
424
- if (fieldValues(body, 'Feature').length !== 1 || fieldValues(body, 'Feature')[0] !== path.basename(featureDir)) failures.push('feature_identity');
425
- if (!concrete(fieldValues(body, 'Expected')[0]) || !concrete(fieldValues(body, 'Observed')[0])) failures.push('expected_observed');
426
- return { status: 'ok', source: 'feature', body, receiptBytes: receipt.bytes, receiptFile: receipt, failures: [...new Set(failures)] };
427
- }
428
-
429
337
  module.exports = {
430
- canonicalTaskReceiptPath,
431
- checkFeatureReceipt,
432
- checkTaskReceipt,
433
338
  checkWorkflowReceiptSet,
434
339
  checkWorkflowTaskReceipt,
435
340
  receiptFixHint,
436
- evidenceBody,
437
- readTaskProof,
438
341
  safeRead,
439
342
  workflowDependencyProofState,
440
343
  workflowReceiptBody,