@haposoft/cafekit 0.16.0-rc.6 → 0.16.0-rc.8

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 (87) hide show
  1. package/README.md +21 -58
  2. package/bin/__tests__/change-firewall.semantic-firewall.test.js +4 -5
  3. package/bin/__tests__/codex-hooks.test.js +382 -0
  4. package/bin/__tests__/codex-native.test.js +579 -80
  5. package/bin/__tests__/develop-contract.test.js +155 -76
  6. package/bin/__tests__/installer-safety.test.js +19 -154
  7. package/bin/__tests__/package-inventory.test.js +494 -26
  8. package/bin/__tests__/release-preflight.semantic-firewall.test.js +2 -2
  9. package/bin/__tests__/validator-grounding.test.js +11 -11
  10. package/bin/install.js +2 -7
  11. package/bin/lib/context.js +0 -45
  12. package/bin/lib/copy-utils.js +1 -1
  13. package/bin/lib/i18n.js +0 -3
  14. package/bin/lib/manifest.js +1 -1
  15. package/bin/phases/claude-runtime.js +1 -3
  16. package/bin/phases/codex-runtime.js +4 -2
  17. package/bin/phases/copy-payload.js +3 -15
  18. package/bin/phases/post-install.js +5 -17
  19. package/bin/phases/root-config.js +2 -3
  20. package/bin/phases/select-platform.js +2 -5
  21. package/bin/phases/summary.js +0 -1
  22. package/package.json +2 -5
  23. package/src/claude/CLAUDE.md +19 -6
  24. package/src/claude/agents/project-manager.md +41 -9
  25. package/src/claude/agents/spec-maker.md +82 -155
  26. package/src/claude/gitignore +1 -1
  27. package/src/claude/hooks/__tests__/spec-gate.test.js +238 -0
  28. package/src/claude/hooks/__tests__/state.test.js +249 -3
  29. package/src/claude/hooks/lib/context.cjs +1 -1
  30. package/src/claude/hooks/lib/detect.cjs +1 -1
  31. package/src/claude/hooks/spec-gate.cjs +44 -9
  32. package/src/claude/hooks/spec-state.cjs +51 -13
  33. package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
  34. package/src/claude/migration-manifest.json +17 -3
  35. package/src/claude/rules/manage-docs.md +43 -24
  36. package/src/claude/rules/state-sync.md +57 -62
  37. package/src/claude/rules/workflow.md +30 -13
  38. package/src/claude/scripts/change-firewall.cjs +2 -2
  39. package/src/claude/scripts/generate-skill-catalog.cjs +0 -1
  40. package/src/claude/scripts/spec-receipt.cjs +196 -1
  41. package/src/claude/scripts/spec-resolver.cjs +428 -0
  42. package/src/claude/skills/develop/SKILL.md +89 -125
  43. package/src/claude/skills/develop/references/parallel-waves.md +75 -162
  44. package/src/claude/skills/develop/references/quality-gate.md +61 -121
  45. package/src/claude/skills/develop/references/subagent-patterns.md +31 -38
  46. package/src/claude/skills/question/SKILL.md +1 -1
  47. package/src/claude/skills/specs/SKILL.md +152 -204
  48. package/src/claude/skills/specs/references/review.md +124 -243
  49. package/src/claude/skills/specs/references/templates.md +202 -0
  50. package/src/claude/skills/sync/SKILL.md +66 -90
  51. package/src/claude/skills/sync/references/sync-protocols.md +62 -83
  52. package/src/codex/AGENTS.md +20 -7
  53. package/src/codex/hooks/lib/spec-receipt.cjs +18 -0
  54. package/src/codex/hooks/lib/spec-utils.cjs +25 -0
  55. package/src/codex/hooks/spec-gate.cjs +46 -16
  56. package/src/codex/hooks/spec-state.cjs +54 -16
  57. package/src/codex/rules/state-sync.md +57 -61
  58. package/src/common/AGENTS.md +8 -1
  59. package/bin/__tests__/opencode-spec-gate.test.js +0 -799
  60. package/bin/lib/opencode-install.js +0 -899
  61. package/bin/phases/opencode-runtime.js +0 -38
  62. package/src/claude/skills/specs/references/archive-workflow.md +0 -74
  63. package/src/claude/skills/specs/references/ask-user-question-gates.md +0 -70
  64. package/src/claude/skills/specs/references/codebase-analysis.md +0 -102
  65. package/src/claude/skills/specs/references/cross-spec-dependency.md +0 -76
  66. package/src/claude/skills/specs/references/research-strategy.md +0 -107
  67. package/src/claude/skills/specs/references/scope-inquiry.md +0 -107
  68. package/src/claude/skills/specs/references/translation-mirror.md +0 -83
  69. package/src/claude/skills/specs/rules/design-discovery-full.md +0 -45
  70. package/src/claude/skills/specs/rules/design-discovery-light.md +0 -28
  71. package/src/claude/skills/specs/rules/design-principles.md +0 -138
  72. package/src/claude/skills/specs/rules/design-review.md +0 -55
  73. package/src/claude/skills/specs/rules/ears-format.md +0 -42
  74. package/src/claude/skills/specs/rules/phase-decision-matrix.md +0 -56
  75. package/src/claude/skills/specs/rules/task-scoring-rubric.md +0 -52
  76. package/src/claude/skills/specs/rules/tasks-generation.md +0 -189
  77. package/src/opencode/AGENTS.md +0 -41
  78. package/src/opencode/plugins/docs-sync.ts +0 -175
  79. package/src/opencode/plugins/inspect-block.ts +0 -164
  80. package/src/opencode/plugins/privacy-block.ts +0 -182
  81. package/src/opencode/plugins/rules.ts +0 -155
  82. package/src/opencode/plugins/session.ts +0 -179
  83. package/src/opencode/plugins/spec-gate.ts +0 -457
  84. package/src/opencode/plugins/spec-state.ts +0 -311
  85. package/src/opencode/plugins/state.ts +0 -253
  86. package/src/opencode/plugins/task-scaffold-guard.ts +0 -161
  87. package/src/opencode/plugins/usage.ts +0 -178
@@ -1,103 +1,79 @@
1
1
  ---
2
2
  name: hapo:sync
3
- description: "Dumb-proof status tracker and file synchronizer. Updates spec.json, task_registry, and tasks/*.md without breaking structural schemas. Includes Auto-Audit."
3
+ description: "Synchronize process-first task Status and inline Receipts without inventing proof; also preserves existing legacy Specs state."
4
4
  user-invocable: true
5
- when_to_use: "Invoke to synchronize spec state, docs, or task tracking after changes."
5
+ when_to_use: "Invoke after implementation or verification changes a task's real state, or to audit a feature packet for drift."
6
6
  category: utilities
7
7
  keywords: [sync, state, tracking, consistency]
8
- argument-hint: "<feature_name> <task_id|task-file> <status> [blocker] | phase <feature_name> <next_phase> | audit <feature_name>"
8
+ argument-hint: "<feature> <task-file> <pending|in_progress|paused|blocked|done|sync-finalize> [blocker] | audit <feature>"
9
9
  metadata:
10
10
  author: haposoft
11
- version: "1.0.0"
11
+ version: "3.0.0"
12
12
  ---
13
- # Sync (State Tracking Protocol)
13
+ # Sync — file-state synchronization
14
14
 
15
- This skill safely bridges the gap between active development state and physical documentation files (`spec.json` + `task_registry` + `tasks/task-R*.md`). Instead of relying on risky raw AI edits, this skill executes precise contextual replacements.
15
+ Synchronize only observed state. For the primary process-first layout, the
16
+ single `Status:` field and inline `## Receipt` in each flat task file are the
17
+ state. Never infer proof, approval, review independence, or product readiness.
16
18
 
17
- ## v2.1 authority-aware synchronization
19
+ ## Commands
18
20
 
19
- Read canonical policy before mutating state. Lane is a derived view:
20
-
21
- ```bash
22
- node .claude/scripts/workflow-policy.cjs --classify-lane --task-json '<task JSON>' --json
21
+ ```text
22
+ /hapo:sync <feature> <task-NN-slug.md> in_progress
23
+ /hapo:sync <feature> <task-NN-slug.md> blocked "reason"
24
+ /hapo:sync <feature> <task-NN-slug.md> done
25
+ /hapo:sync <feature> <task-NN-slug.md> sync-finalize
26
+ /hapo:sync audit <feature>
23
27
  ```
24
28
 
25
- - Direct may have no spec/state/registry; sync only concrete targeted evidence
26
- and never invents proof, readiness, approval, or audit state.
27
- - Standard stores one bounded spec; final integration creates one canonical
28
- feature receipt. A combined closeout review is required only when the
29
- persisted policy says an independent audit is needed.
30
- - Critical requires strict durable evidence and the persisted capability obligations; choose available actors or the main session according to required capability and independence, never a fixed actor sequence.
31
- - Authoring states are only `draft`, `validated`, or `absent`. Legacy approval
32
- fields are readable but inert.
33
- - Preserve `classified_minimum`. Reclassification happens before persistence;
34
- after persistence, the same-feature baseline is monotonic and no downgrade is
35
- supported until a trusted issuer exists.
36
- - `spec.json` is machine authority. Task status/checkboxes, dependencies, and
37
- ownership Markdown are projections. Typed `coordination.boundaries` are the
38
- only topology authority.
39
-
40
- ## Supported Commands
41
- ### 1. Task Synchronization
42
- Update a specific task's status and automatically check its relevant sub-checkboxes.
43
-
44
- **Usage:** `/hapo:sync <feature_name> <task_id|task-file> <status> ["optional blocker msg"]`
45
- - Example 1: `/hapo:sync auth R0-02 done`
46
- - Example 2: `/hapo:sync payment task-R1-03-chunks-api.md blocked "API Endpoint Down"`
47
-
48
- ### 2. Phase Advancement
49
- Advance the entire project to the next logical phase.
50
-
51
- **Usage:** `/hapo:sync phase <feature_name> <next_phase>`
52
- - Example: `/hapo:sync phase shopping_cart test`
53
-
54
- ### 3. State Audit
55
- Scans the `spec.json` against all physical `task-R*.md` files to detect mismatches between `task_files`, `task_registry`, and markdown task headers, then repairs them.
56
-
57
- **Usage:** `/hapo:sync audit <feature_name>`
58
- - Example: `/hapo:sync audit auth`
59
-
60
- ## Directives
61
-
62
- 1. **Precision Edits:** Never overwrite the entire `spec.json` string blindly. Update only the required keys, while keeping JSON valid.
63
- 2. **Machine + Human Sync:** Every task status update MUST modify both `spec.json.task_registry[...]` and the matching markdown task file header/status section.
64
- 3. **Markdown Integrity:** Task Markdown is a plan plus `**Status:**`. Update
65
- Status and `Changes` checkboxes only when their implementation is real; never
66
- insert Base/Head, verdicts, command outcomes, or receipt proof into the plan.
67
- 4. **Verification Receipt Rule:** `done` is illegal without a valid canonical
68
- `receipts/<task-basename>.md`, or a readable legacy `## Evidence` receipt.
69
- Prefer the separate receipt; if both exist and proof identity conflicts,
70
- refuse completion. If proof is missing, keep the task `in_progress` or
71
- `blocked`.
72
- 5. **Task Docs Hook:** When `hapo:sync` marks a task as `done`, assess actual documentation impact and report `Docs impact: major|minor|none`; do not create a docs update request when impact is `none`.
73
- 6. **Topology Rule:** Never infer dependency or parallel state from `(P)`,
74
- `task_triggers`, `Related Files`, or prose; project typed boundaries instead.
75
-
76
- ### 4. Explicit Flash Finalization
77
-
78
- **Usage:** `/hapo:sync <feature_name> <task_id|task-file> sync-finalize` (the adapter must call `workflow-policy.cjs --sync-finalize --task-json <current-task> --verdict PASS --proof <canonical-receipt> --json`)
79
-
80
- This is the only operation allowed to turn the current `FLASH_UNVERIFIED` task into `done` and unblock dependencies. The policy derives promotion from that current state and explicit proof; `readyForSync`, `flashTransition`, and `promotionReceipt` supplied by the caller are not proof. A normal `done` request cannot bypass flash promotion or stale `FLASH_UNVERIFIED` state.
81
-
82
- The current state must be the exact stored form: `status: "in_progress"`,
83
- `receipt: "FLASH_UNVERIFIED"`, `dependencyBlocked: true`, `unblocks: false`, a
84
- concrete blocker, and no caller promotion fields. The canonical proof must be
85
- bound by the runtime adapter with `policy.createReceiptBinding({ base, head })`
86
- and must match both receipt anchors; arbitrary valid-length Base/Head values do
87
- not authorize finalization.
88
-
89
- ### Flash implementation state
90
-
91
- Executable policy source: `.claude/scripts/workflow-policy.cjs` (source: `src/claude/scripts/workflow-policy.cjs`). Trusted sync-finalize invokes `promoteFlashTask` only after the exact task Verification Plan and reachability return PASS; test PASS itself only supplies canonical proof and leaves the persisted task blocked in progress. FAIL, BLOCKED, and NO_TESTS remain blocked in progress.
92
-
93
- `FLASH_UNVERIFIED` is storage for implemented-but-unverified work, not a completion status. Store it as `status: "in_progress"` with `dependencyBlocked: true`, `unblocks: false`, a concrete blocker, and no promotion fields; do not unblock dependencies. `/hapo:test` may produce canonical proof, but the supported sync-finalize boundary must receive explicit `--verdict PASS` and `--proof`, require the runtime Base/Head binding, revalidate the receipt/artifact, derive the transition, and only then set `done`. FAIL, BLOCKED, NO_TESTS, marker-only proof, minimal state, and pre-promoted caller JSON remain `in_progress`.
94
-
95
- After the last task is done, sync does not synthesize proof. Test/Develop must
96
- run final integration and create `feature-receipt.md` once. Task-bearing
97
- completion requires all task receipts plus the feature receipt. Taskless
98
- Compact/Full completion requires the feature receipt only; its absence before
99
- final closeout is normal. No receipt grants or infers approval, readiness, or
100
- audit status.
101
-
102
- ## References
103
- Read `references/sync-protocols.md` for exact Search/Replace regex patterns and JSON schema expectations before acting on the files.
29
+ Resolve one regular direct-child task inside `specs/<feature>/`. Reject path
30
+ escape, symlink, ambiguity, missing `plan.md`, duplicate Status fields, and
31
+ unsupported status values.
32
+
33
+ ## Task synchronization
34
+
35
+ 1. Read the task Outcome, Acceptance, Dependencies, Verification Plan, current
36
+ Status, and Receipt before editing.
37
+ 2. Starting or resuming changes only Status to `in_progress`. Update only
38
+ checkboxes whose implementation is real.
39
+ 3. Blocking changes Status to `blocked` and records a concrete blocker; it does
40
+ not create proof.
41
+ 4. Done requires a current inline Receipt with `Verification: PASS`, exact
42
+ Command, `Exit: 0`, runtime-bound Base/Head, non-empty fenced output, and any
43
+ required negative/reachability/artifact proof.
44
+ 5. Write or replace the Receipt before changing Status to `done`. Missing,
45
+ stale, contradictory, placeholder, failure, or zero-test evidence keeps the
46
+ task `in_progress` or `blocked`.
47
+ 6. Re-read the file after the surgical edit and confirm exactly one Status and
48
+ one Receipt section.
49
+
50
+ `sync-finalize` is the only promotion path for `FLASH_UNVERIFIED`. It requires
51
+ fresh canonical PASS proof, revalidates Base/Head and artifacts, clears the
52
+ flash blocker, then derives `done`. Caller-supplied promotion booleans and a
53
+ marker alone have no authority.
54
+
55
+ ## Audit
56
+
57
+ Scan only `specs/<feature>/task-*.md` beside `plan.md`. Compare plan task rows,
58
+ task filenames, dependencies, Status, acceptance mapping, and Receipts. Report
59
+ missing files, unknown rows, cycles, duplicate fields, done-without-proof,
60
+ proof-on-unfinished-task, and overlapping ownership.
61
+
62
+ Repair deterministic formatting drift only. A semantic conflict, missing
63
+ evidence, or ownership decision requires user or implementation input; do not
64
+ pick a winner. After any edit, report exact files changed and unresolved items.
65
+
66
+ Read `references/sync-protocols.md` for surgical update and audit rules.
67
+
68
+ ## Docs impact
69
+
70
+ When a task becomes done, report `Docs impact: none|minor|major`. Create no docs
71
+ work for `none`; update only affected existing docs for minor or major.
72
+
73
+ ## Legacy workflow compatibility
74
+
75
+ If `specs/<feature>/spec.json` exists, use the legacy adapter instead: preserve
76
+ its machine authority, `task_registry`, nested `tasks/task-R*.md`, timestamps,
77
+ typed topology, separate receipts, `workflow_policy`, `planning_depth`, lane,
78
+ and `execution_tier`. Keep JSON and Markdown synchronized, retain the exact
79
+ legacy sync-finalize contract, and require its feature receipt at closeout.
@@ -1,83 +1,62 @@
1
- # Sync Protocols
2
-
3
- The following guidelines dictate exactly how `hapo:sync` should interact with files to prevent data corruption.
4
-
5
- **Flash implementation state:** `FLASH_UNVERIFIED` MUST remain the exact stored form: `status: "in_progress"`, `dependencyBlocked: true`, `unblocks: false`, a concrete blocker, and no `readyForSync`, `flashTransition`, or `promotionReceipt` fields. It never unblocks dependencies. The supported sync-finalize adapter must pass the current task, `--verdict PASS`, and canonical `--proof` to `workflow-policy.cjs`; the policy derives promotion, requires a runtime `createReceiptBinding({ base, head })` match for both receipt anchors, revalidates receipt/artifact requirements, and rejects caller-supplied promotion fields before setting `done`. FAIL, BLOCKED, NO_TESTS, marker-only proof, minimal state, and pre-promoted caller JSON stay `in_progress`.
6
-
7
- **Policy state rule:** read the v2.1 policy input before sync. Direct/Standard/
8
- Critical are derived views. Preserve `classified_minimum`, risks, and explicit
9
- override receipt. Authoring states are only `draft`, `validated`, or `absent`;
10
- legacy approval fields are inert.
11
-
12
- **Authority rule:** `spec.json` is machine authority. Markdown is a projection.
13
- Typed `coordination.boundaries` own dependency, ownership, transition, proof,
14
- and parallel semantics; never infer them from `(P)`, `task_triggers`, `Related
15
- Files`, or prose.
16
-
17
- ## 1. Updating `spec.json`
18
-
19
- * **JSON Modification Rule:** Do not output whole files. Load the JSON,
20
- update only lifecycle fields and the relevant registry entry, then write
21
- valid JSON without changing semantic topology.
22
- * **Task Registry Rule:** Resolve the incoming task reference to a single relative path in `task_registry`. Accept either:
23
- - compact task ID like `R0-02`
24
- - full filename like `task-R0-02-extension-shell.md`
25
- - full relative path like `tasks/task-R0-02-extension-shell.md`
26
- * **Status Update:** If a task changes to `blocked`, the matching `task_registry[path].status` must become `"blocked"`, `task_registry[path].blocker` must record the reason, and `spec.json.status` / `spec.json.blocker` must reflect the top-level block if work is globally blocked.
27
- * **Timestamp Rule:** Update `task_registry[path].started_at`, `completed_at`, and `last_updated_at` consistently with the new state. Also refresh `spec.json.updated_at`.
28
- * **Done-State Rule:** Never set `task_registry[path].status = "done"` unless `receipts/<task-basename>.md` is valid, or a legacy `## Evidence` receipt is valid. Write proof to the separate receipt first; never add execution evidence to a new-format task plan.
29
- * **Receipt Integrity Rule:** A valid task receipt includes task identity/path, exact commands and outcomes, expected versus observed behavior, applicable negative/reachability/artifact proof, and Base/Head binding. If separate and legacy receipts both exist with conflicting proof identity, refuse `done`. `PRECHECK_FAIL`, `FAIL`, `UNVERIFIED`, placeholders, and contract substitutions are not eligible.
30
- * **Contract Fidelity Rule:** If the task file notes or evidence show that a named framework/auth/runtime choice from the spec was silently replaced, sync MUST refuse `done` until the spec is amended or the implementation is corrected.
31
- * **Task Docs Rule:** After a task is moved to `done`, assess actual documentation impact and report `Docs impact: major|minor|none`. Only affected docs receive a follow-up checkpoint.
32
-
33
- ## 2. Updating `tasks/task-**.md`
34
-
35
- The structure of `tasks/task.md` relies heavily on exact keyword markers. Follow these surgical protocols against `tasks/task-R*.md`:
36
-
37
- ### A. Completing a Task
38
- When `/hapo:sync <feature> <task-id> done`:
39
- 1. Find: `**Status:** pending` (or `in_progress` / `blocked`).
40
- 2. Resolve `receipts/<task-basename>.md` first, with legacy `## Evidence` as fallback. If neither has valid proof, STOP and refuse to mark the task done.
41
- 3. Refuse completion if the receipt contains any non-passing marker such as `PRECHECK_FAIL`, `FAIL`, `UNVERIFIED`, or an explicit note that the implementation substituted a named contract with a placeholder/custom simplification.
42
- 4. Replace with: `**Status:** done`.
43
- 5. Update only implemented checkboxes under `## Changes`; never append receipt fields to the task plan.
44
- 6. Surface `Docs impact: major|minor|none`; if impact is not `none`, name the affected docs and the follow-up checkpoint.
45
-
46
- ### B. Blocking a Task
47
- When `/hapo:sync <feature> <task-id> blocked "API error"`:
48
- 1. Find: `**Status:** <anything>`.
49
- 2. Replace with: `**Status:** blocked`.
50
- 3. Record the reason and timestamp in `task_registry[path].blocker`; do not add
51
- a non-canonical task section.
52
-
53
- ### C. Starting / Resuming a Task
54
- When `/hapo:sync <feature> <task-id> in_progress`:
55
- 1. Find: `**Status:** pending` (or `blocked`).
56
- 2. Replace with: `**Status:** in_progress`.
57
- 3. Do NOT pre-check completion boxes.
58
- 4. Stamp `task_registry[path].started_at` if missing and refresh `last_updated_at`.
59
-
60
- ## 3. Audit Protocol
61
-
62
- When `/hapo:sync audit <feature>` is activated:
63
- 1. **Load Truth:** Read `specs/<feature>/spec.json`.
64
- 2. **Scan Directory:** Loop through `specs/<feature>/tasks/`.
65
- 3. **Compare Constraints:** Rebuild `task_files` from disk, ensure every file exists in `task_registry`, and compare markdown `**Status:**` headers against `task_registry[path].status`.
66
- 4. **Reconciliation Rules:**
67
- - Missing registry entry → create it
68
- - Missing disk file referenced in registry → remove or flag it
69
- - Markdown says `done` but registry not done → registry wins only if a canonical separate or legacy receipt exists; otherwise downgrade markdown or flag conflict
70
- - Registry says `done` but markdown still pending → update markdown only if a canonical separate or legacy receipt exists
71
- - Either side says `done` but neither receipt source has concrete proof → downgrade to `in_progress` or flag conflict instead of preserving fake completion
72
- - Both receipt sources exist with conflicting proof identity → fail closed and require manual reconciliation
73
- - Either side says `done` but the receipt contains `PRECHECK_FAIL`, `FAIL`, `UNVERIFIED`, or explicit contract-substitution notes → downgrade to `in_progress` or flag conflict
74
- 5. **Correction Alert:** Output a brief markdown alert detailing mismatches fixed and any unresolved conflicts requiring manual review.
75
- 6. **Task Docs Alert:** If audit reveals tasks newly marked `done`, include the actual docs impact; do not emit a generic docs-sync request when no docs are affected.
76
-
77
- ## 4. Feature closeout
78
-
79
- - Before all tasks are done, missing `feature-receipt.md` is normal.
80
- - After all tasks are done, require final integration execution and one valid
81
- `feature-receipt.md`; never derive it from task status alone.
82
- - A taskless Compact/Full spec uses the same final feature receipt and does not
83
- require a synthetic registry entry.
1
+ # Sync protocols
2
+
3
+ Use surgical edits and verify bytes after writing. Never replace a whole packet
4
+ to change one task state.
5
+
6
+ ## Resolve safely
7
+
8
+ 1. Canonicalize `specs/<feature>/` under the configured specs root.
9
+ 2. Require regular non-symlink `plan.md` and flat `task-*.md` files.
10
+ 3. Match the requested task by exact basename; reject aliases and ambiguity.
11
+ 4. Require exactly one `Status: pending|in_progress|paused|blocked|done` line.
12
+ 5. Read dependencies and acceptance IDs before choosing a transition.
13
+
14
+ ## Transitions
15
+
16
+ - `pending|paused|blocked -> in_progress`: change Status only; preserve a real
17
+ blocker in history or remove it only when its prerequisite changed.
18
+ - `* -> blocked`: write a concrete reason and keep existing proof unchanged.
19
+ - `in_progress -> done`: validate the current inline Receipt first, then change
20
+ Status. Never perform this order in reverse.
21
+ - `done -> in_progress`: allowed when proof becomes stale or implementation
22
+ changes; retain the stale receipt only when clearly labelled non-authoritative.
23
+
24
+ For Flash, keep `Status: in_progress`, `FLASH_UNVERIFIED`, and blocker
25
+ `awaiting /hapo:test <feature>`. Only sync-finalize with fresh canonical proof
26
+ may replace that marker and set done.
27
+
28
+ ## Receipt update
29
+
30
+ The primary Receipt is the final `## Receipt` section in the task file. It must
31
+ contain one Verification PASS, one exact Command, one successful Exit, one
32
+ runtime-bound Base/Head pair, and non-empty fenced current output. Preserve
33
+ additional concrete negative, reachability, and artifact evidence.
34
+
35
+ Reject duplicate Receipt headings, placeholders, copied output, conflicting
36
+ success/failure markers, zero executed tests when tests are required, stale
37
+ provenance, and path or artifact mismatch.
38
+
39
+ ## Audit reconciliation
40
+
41
+ - Plan row without task file: report missing; do not synthesize scope.
42
+ - Task file without plan row: report unknown; do not silently adopt it.
43
+ - Done without valid Receipt: downgrade only when the repair is deterministic,
44
+ otherwise block and request direction.
45
+ - Receipt on unfinished task: preserve it only if it is clearly historical;
46
+ otherwise report the conflict.
47
+ - Missing or cyclic dependency: block affected tasks.
48
+ - Overlapping write ownership in one proposed wave: serialize or request an
49
+ ownership decision.
50
+ - Acceptance ID not mapped both ways: report traceability drift.
51
+
52
+ After a repair, re-read every changed file and print a concise mismatch/fix/
53
+ unresolved summary. Never claim execution proof from the audit itself.
54
+
55
+ ## Legacy workflow compatibility
56
+
57
+ For `spec.json` packets, resolve exact `task_registry` paths and synchronize
58
+ registry timestamps plus nested task Markdown. Validate the canonical separate
59
+ receipt (with legacy inline Evidence only as the supported fallback), reject
60
+ conflicting proof identities, preserve classified minimum and planning_depth,
61
+ and use the installed legacy policy for lane, execution_tier, Flash promotion,
62
+ and final feature closeout.
@@ -8,12 +8,25 @@
8
8
  - CafeKit agents live in `.codex/agents/*.toml` and are auto-discovered after the repository is trusted.
9
9
  - Runtime support lives in `.codex/rules/`, `.codex/scripts/`, `.codex/references/`, and `.codex/runtime.json`.
10
10
  - Project hooks live in `.codex/hooks.json`; review trusted hooks with `/hooks`.
11
- - Specs v2 keeps `planning_depth` (`None`/`Compact`/`Full`) independent from `assurance_level` (`Routine`/`Elevated`/`Strict`). Any risk has an Elevated automatic floor; Strict is opt-in only for an explicit user/project independent-audit requirement or a user-confirmed scope-specific audit decision, never a keyword or severity label. Run the artifact router before discovery: None has no durable spec; Compact/Full share the bounded `spec.json` + `requirements.md` + `design.md` core. Research requires material unresolved uncertainty, an external-current fact, or an explicit request; tasks require typed coordination topology. Full/Strict never create either automatically.
12
- - In v2.1, `spec.json` is machine authority and Markdown is a human projection. Task plans have exactly seven sections: `Outcome`, `Scope`, `Anchors and Ownership`, `Changes`, `Acceptance`, `Dependencies`, `Verification Plan`; the only ownership table is `ID | Type | Target | Role | Access | Action`.
13
- - Promote canonical `semantic_model` only through the explicit installed machine semantic-sync step. A semantic Markdown edit requires resynchronization and round-trip validation; never hand-author the machine shape.
14
- - `coordination.boundaries` typed as ownership/dependency/transition/proof/parallel is topology authority. Legacy trigger fields, priority markers, related-file lists, approval fields, and prose are inert compatibility inputs, never canonical authoring.
15
- - Canonical lifecycle is exactly `in_progress`, `paused`, `blocked`, or `done`. Technical readiness differs from closeout; authors cannot self-declare readiness, review authority, execution proof, or final `done`.
16
- - Validator exit 0 proves implemented structural checks only, not semantic quality or execution PASS.
11
+ - New Specs work uses the process-first flow. `$hapo-specs` opens C1, writes
12
+ `specs/<feature>/plan.md` with flat `task-NN-*.md` files beside it, then opens
13
+ C2 after adversarial review. It never starts implementation.
14
+ - Start implementation only through a new explicit `$hapo-develop` invocation.
15
+ Execute one unblocked task at a time; each task has exactly one `Status:`
16
+ field and the controller is its sole state-and-proof writer.
17
+ - Use `$hapo-sync` for surgical updates to observed file state. A done task
18
+ requires a canonical final inline `## Receipt` with the exact command,
19
+ `Exit: 0`, `Verification: PASS`, runtime-derived Base and Head values, and
20
+ non-empty fenced current output.
21
+ - At C3, show current receipts and unresolved limitations. The user decides
22
+ completion; no command, review, or host state may invent approval or proof.
23
+
24
+ ### Legacy Specs compatibility
25
+
26
+ Existing packets containing `spec.json`, nested tasks, or legacy kernel
27
+ artifacts keep their installed adapter, `task_registry`, `semantic_model`,
28
+ `planning_depth`, lane, `execution_tier`, machine authority, separate receipts,
29
+ and closeout contract. Do not migrate them during unrelated process-first work.
17
30
 
18
31
  ## Codex caveats
19
32
 
@@ -25,4 +38,4 @@
25
38
 
26
39
  Codex's native project instruction surface is root `AGENTS.md`. Combined installs keep this Codex block there because no separate Codex project entrypoint is configured by CafeKit. Other runtimes may read the same root file; this shared-root trade-off is intentional and must not be treated as filesystem isolation.
27
40
 
28
- **Ownership / ignore contract (fail-safe):** This Codex block is owned by Codex CLI only. If you are Claude Code, OpenCode, or any other runtime, ignore this entire Codex block and consume only CORE plus your native block. If you cannot determine which block is yours, treat the file as CORE-only. Do not treat another runtime's block as instructions.
41
+ **Ownership / ignore contract (fail-safe):** This Codex block is owned by Codex CLI only. If you are Claude Code or any other runtime, ignore this entire Codex block and consume only CORE plus your native block. If you cannot determine which block is yours, treat the file as CORE-only. Do not treat another runtime's block as instructions.
@@ -69,6 +69,22 @@ function checkReceiptDetails(featureDir, taskPath, task, runtimeContext) {
69
69
  if (!policy) return { failures: ['shared_validator'], status: 'missing' };
70
70
  return receiptHelper().checkTaskReceipt(featureDir, taskPath, task, runtimeContext, policy);
71
71
  }
72
+ function checkWorkflowReceiptDetails(featureDir, taskPath, runtimeContext) {
73
+ const policy = getSharedPolicy();
74
+ const receipt = receiptHelper();
75
+ if (!policy || typeof receipt.checkWorkflowTaskReceipt !== 'function') {
76
+ return { failures: ['shared_validator'], status: 'missing' };
77
+ }
78
+ return receipt.checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, policy);
79
+ }
80
+ function checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession) {
81
+ const policy = getSharedPolicy();
82
+ const receipt = receiptHelper();
83
+ if (!policy || typeof receipt.checkWorkflowReceiptSet !== 'function') {
84
+ return { failures: [{ featureName: '<set>', taskPath: '<set>', failures: ['shared_validator'] }] };
85
+ }
86
+ return receipt.checkWorkflowReceiptSet(candidates, projectRoot, runtimeSession, policy);
87
+ }
72
88
  function checkReceipt(featureDir, taskPath, task, runtimeContext) {
73
89
  const map = {
74
90
  unsafe_path: 'a', missing_receipt: 'b', task_status: 'a', completed_at: 'd',
@@ -91,6 +107,8 @@ module.exports = {
91
107
  checkFeatureReceipt,
92
108
  checkReceipt,
93
109
  checkReceiptDetails,
110
+ checkWorkflowReceiptDetails,
111
+ checkWorkflowReceiptSet,
94
112
  evidenceBody,
95
113
  getSharedPolicy,
96
114
  getSharedValidate,
@@ -100,6 +100,29 @@ function resolveActiveSpec(projectRoot, runtime, explicitFeature, explicitPath)
100
100
  });
101
101
  }
102
102
 
103
+ function resolveWorkflowCandidate(projectRoot, runtime, explicitFeature, explicitPath) {
104
+ const resolver = sharedResolver();
105
+ if (typeof resolver.resolveWorkflowCandidate !== 'function') {
106
+ return resolveActiveSpec(projectRoot, runtime, explicitFeature, explicitPath);
107
+ }
108
+ if (projectRoot && typeof projectRoot === 'object') {
109
+ return resolver.resolveWorkflowCandidate(projectRoot);
110
+ }
111
+ return resolver.resolveWorkflowCandidate({
112
+ projectRoot,
113
+ runtime,
114
+ explicitFeature,
115
+ explicitPath,
116
+ });
117
+ }
118
+
119
+ function refineWorkflowGateResolution(resolved) {
120
+ const resolver = sharedResolver();
121
+ return typeof resolver.refineWorkflowGateResolution === 'function'
122
+ ? resolver.refineWorkflowGateResolution(resolved)
123
+ : resolved;
124
+ }
125
+
103
126
  function findActiveSpec(projectRoot, runtime) {
104
127
  const resolved = resolveActiveSpec(projectRoot, runtime);
105
128
  if (!resolved) return null;
@@ -122,6 +145,8 @@ module.exports = {
122
145
  findAllActiveSpecs,
123
146
  findAllSpecCandidates,
124
147
  resolveActiveSpec,
148
+ resolveWorkflowCandidate,
149
+ refineWorkflowGateResolution,
125
150
  specsDirectory,
126
151
  taskStatusMap,
127
152
  };
@@ -12,6 +12,8 @@ const {
12
12
  const {
13
13
  checkFeatureReceipt,
14
14
  checkReceiptDetails,
15
+ checkWorkflowReceiptDetails,
16
+ checkWorkflowReceiptSet,
15
17
  loadSharedPolicy,
16
18
  } = require('./lib/spec-receipt.cjs');
17
19
  const { taskStatusMap } = require('./lib/spec-utils.cjs');
@@ -46,13 +48,33 @@ try {
46
48
  throw new Error('shared workflow policy lacks completion authority functions');
47
49
  }
48
50
  const resolver = require('./lib/spec-utils.cjs');
49
- const resolved = FINAL_STATE.resolveCandidate({
50
- resolver,
51
- projectRoot,
52
- runtime,
53
- payload,
54
- });
51
+ let resolved = typeof resolver.resolveWorkflowCandidate === 'function'
52
+ ? resolver.resolveWorkflowCandidate({ projectRoot, runtime, target: payload, includeCompleted: true })
53
+ : FINAL_STATE.resolveCandidate({ resolver, projectRoot, runtime, payload });
54
+ if (typeof resolver.refineWorkflowGateResolution === 'function') {
55
+ resolved = resolver.refineWorkflowGateResolution(resolved);
56
+ }
55
57
  if (!resolved) process.exit(0);
58
+ if (resolved.layoutKind === 'process-v3-completed-set') {
59
+ const configuredGate = runtime.spec?.completion_gate;
60
+ if (configuredGate !== undefined && configuredGate !== true) {
61
+ emitBlock('Completion gate: runtime.spec.completion_gate is a worker-writable flag, not an authorization; no completion-gate bypass is supported. Remove the flag and satisfy the gate.');
62
+ process.exit(0);
63
+ }
64
+ const checked = checkWorkflowReceiptSet(
65
+ resolved.candidates,
66
+ projectRoot,
67
+ sessionIdentity(payload),
68
+ );
69
+ if (checked.failures.length === 0) process.exit(0);
70
+ const lines = [`Completion gate: ${checked.failures.length} done task(s) lack a verification receipt.`];
71
+ for (const failure of checked.failures) {
72
+ lines.push(`- \`${failure.featureName}/${failure.taskPath}\`: failed check(s) ${failure.failures.join(', ')}`);
73
+ lines.push(` Write a runtime-bound \`## Receipt\` with the planned command in \`specs/${failure.featureName}/${failure.taskPath}\`.`);
74
+ }
75
+ emitBlock(lines.slice(0, 8).join('\n'));
76
+ process.exit(0);
77
+ }
56
78
  if (resolved.error === 'multiple_active' || resolved.error === 'multiple_persisted') {
57
79
  process.stdout.write(`${JSON.stringify({
58
80
  decision: 'block',
@@ -76,10 +98,12 @@ try {
76
98
  }
77
99
  if (resolved.error) process.exit(0);
78
100
  const active = resolved;
79
- const lifecyclePhase = active.spec.current_phase || active.spec.phase;
80
- const explicitCloseout = ['done', 'completed', 'complete'].includes(active.spec.status)
101
+ const activeSpec = active.spec || {};
102
+ const processWorkflow = active.layoutKind === 'process-v3';
103
+ const lifecyclePhase = activeSpec.current_phase || activeSpec.phase;
104
+ const explicitCloseout = ['done', 'completed', 'complete'].includes(activeSpec.status)
81
105
  || ['closeout', 'completion', 'completed', 'complete'].includes(lifecyclePhase);
82
- if (active.spec.schema_version === '2.1') {
106
+ if (!processWorkflow && activeSpec.schema_version === '2.1') {
83
107
  const finalState = FINAL_STATE.evaluateCloseout({
84
108
  policy: POLICY,
85
109
  projectRoot,
@@ -95,7 +119,7 @@ try {
95
119
  const runtimeContext = POLICY.deriveRuntimeContext({
96
120
  projectRoot,
97
121
  specsRoot: active.specsDir,
98
- specFile: active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
122
+ specFile: active.stateFile || active.specFile || path.join(active.specsDir, active.featureName, 'spec.json'),
99
123
  featureName: active.featureName,
100
124
  runtimeSession: sessionIdentity(payload),
101
125
  });
@@ -104,8 +128,10 @@ try {
104
128
  emitBlock('Completion gate: runtime.spec.completion_gate is a worker-writable flag, not an authorization; no completion-gate bypass is supported. Remove the flag and satisfy the gate.');
105
129
  process.exit(0);
106
130
  }
107
- const registry = active.spec.task_registry || {};
108
- const currentStatuses = taskStatusMap(active.spec);
131
+ const registry = active.taskRegistry || activeSpec.task_registry || {};
132
+ const currentStatuses = processWorkflow
133
+ ? Object.fromEntries(Object.entries(registry).map(([taskPath, task]) => [taskPath, task?.status || 'pending']))
134
+ : taskStatusMap(activeSpec);
109
135
  const cacheFile = path.join(
110
136
  projectRoot,
111
137
  '.codex',
@@ -137,7 +163,7 @@ try {
137
163
  const previous = cacheExists && cacheEntries[runtimeContext.context_id]
138
164
  ? cacheEntries[runtimeContext.context_id].tasks || {}
139
165
  : {};
140
- const staleFlashTasks = Object.entries(registry)
166
+ const staleFlashTasks = processWorkflow ? [] : Object.entries(registry)
141
167
  .filter(([, task]) => POLICY.isStaleFlashDone(task))
142
168
  .map(([taskPath]) => taskPath);
143
169
  if (staleFlashTasks.length > 0) {
@@ -154,7 +180,9 @@ try {
154
180
  const receiptBodies = new Map();
155
181
  const failures = allDoneTasks
156
182
  .map((taskPath) => {
157
- const proof = checkReceiptDetails(featureDir, taskPath, registry[taskPath], runtimeContext);
183
+ const proof = processWorkflow
184
+ ? checkWorkflowReceiptDetails(featureDir, taskPath, runtimeContext)
185
+ : checkReceiptDetails(featureDir, taskPath, registry[taskPath], runtimeContext);
158
186
  if (proof.body) receiptBodies.set(taskPath, proof.body);
159
187
  return {
160
188
  taskPath,
@@ -163,7 +191,7 @@ try {
163
191
  })
164
192
  .filter((result) => result.failures.length);
165
193
 
166
- const featureCloseoutRequired = explicitCloseout && allDoneTasks.length > 0;
194
+ const featureCloseoutRequired = !processWorkflow && explicitCloseout && allDoneTasks.length > 0;
167
195
  const featureReceipt = featureCloseoutRequired
168
196
  ? checkFeatureReceipt(featureDir, runtimeContext)
169
197
  : null;
@@ -200,7 +228,9 @@ try {
200
228
  lines.push(`- \`${result.taskPath}\`: failed check(s) ${result.failures.join(', ')}`);
201
229
  lines.push(result.taskPath === 'feature-receipt.md'
202
230
  ? ` Run final integration proof, then write \`specs/${active.featureName}/feature-receipt.md\`.`
203
- : ` Write canonical proof to \`specs/${active.featureName}/receipts/${path.posix.basename(result.taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
231
+ : processWorkflow
232
+ ? ` Write a runtime-bound \`## Receipt\` with command output in \`specs/${active.featureName}/${path.posix.basename(result.taskPath)}\`.`
233
+ : ` Write canonical proof to \`specs/${active.featureName}/receipts/${path.posix.basename(result.taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
204
234
  }
205
235
  if (completionBlocked) {
206
236
  lines.push(`- Completion decision unfinished: ${completion.blocker || 'required workflow proof is missing.'}`);