@ikon85/agent-workflow-kit 0.32.0 → 0.33.0

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 (33) hide show
  1. package/.agents/skills/census-update/SKILL.md +34 -3
  2. package/.agents/skills/kit-update/SKILL.md +18 -4
  3. package/.agents/skills/orchestrate-wave/SKILL.md +54 -54
  4. package/.agents/skills/orchestrate-wave/references/builder-contract.md +16 -3
  5. package/.agents/skills/orchestrate-wave/references/dispatch-subagents.md +79 -0
  6. package/.agents/skills/orchestrate-wave/references/dispatch-workflow.md +58 -0
  7. package/.agents/skills/orchestrate-wave/references/report-contracts.md +42 -0
  8. package/.agents/skills/setup-workflow/census.md +14 -7
  9. package/.claude/skills/census-update/SKILL.md +34 -3
  10. package/.claude/skills/kit-update/SKILL.md +18 -4
  11. package/.claude/skills/orchestrate-wave/SKILL.md +54 -54
  12. package/.claude/skills/orchestrate-wave/references/builder-contract.md +16 -3
  13. package/.claude/skills/orchestrate-wave/references/dispatch-subagents.md +79 -0
  14. package/.claude/skills/orchestrate-wave/references/dispatch-workflow.md +58 -0
  15. package/.claude/skills/orchestrate-wave/references/report-contracts.md +42 -0
  16. package/.claude/skills/setup-workflow/census.md +14 -7
  17. package/README.md +61 -1
  18. package/agent-workflow-kit.package.json +105 -13
  19. package/docs/adr/0002-capability-gated-orchestration.md +70 -0
  20. package/package.json +1 -1
  21. package/scripts/readiness.mjs +48 -14
  22. package/scripts/test_census_update_contract.test.mjs +14 -0
  23. package/scripts/test_orchestrate_wave_contract.py +136 -0
  24. package/scripts/test_worktree_setup_base_guard.py +140 -0
  25. package/scripts/worktree-lifecycle/setup.py +40 -0
  26. package/src/cli.mjs +2 -2
  27. package/src/commands/update.mjs +21 -3
  28. package/src/lib/bundle.mjs +10 -0
  29. package/src/lib/capabilityMatrix.mjs +94 -0
  30. package/src/lib/reconcileReconReports.mjs +111 -0
  31. package/src/lib/reportValidator.mjs +186 -0
  32. package/src/lib/updateCandidate.mjs +78 -4
  33. package/src/lib/waveClaim.mjs +134 -0
@@ -81,10 +81,10 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
81
81
  - **Plan-level error** (integration/verify reveals a wrong LOCKED decision, not a
82
82
  slice bug): STOP the wave. No improvised redesign AFK — keep worktrees intact,
83
83
  report findings + options.
84
- - **On ANY wave STOP/abort:** if this run planted the active-wave claim, remove
85
- exactly that claim as part of shutdown. Never delete a claim marker observed
86
- during a preflight collision, nor any sibling/foreign wave marker those are
87
- owned by another run. A stale marker owned by this run would block a safe retry.
84
+ - **On ANY wave STOP/abort:** if this run planted the active-wave claim, release
85
+ it via `releaseWaveClaim` with this run's owner as part of shutdown it
86
+ refuses a foreign payload. Never delete a claim marker observed during a
87
+ preflight collision. A stale own marker would block a safe retry.
88
88
  - **Routing = one axis: how expensive is a wrong result to catch?** Mechanically
89
89
  caught (test/screenshot/lint) → default tier at medium/low effort; plausible-but-
90
90
  wrong / subtle logic / architecture → top tier at high effort + main-thread
@@ -95,6 +95,24 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
95
95
  first red test). The same axis sets how hard you re-verify. Borderline → default
96
96
  tier + re-verify beats blanket top tier.
97
97
 
98
+ ## Orchestration mechanics
99
+
100
+ Pass only host-supplied inventory through `capabilityAdapter.claude` or `.codex`,
101
+ then call the selector. It returns exactly one target; missing or `unknown` evidence
102
+ degrades A → B → C. A model claim is not evidence; do not emulate a missing primitive.
103
+
104
+ - **Path A:** requires the literal `Workflow` tool, callable and permitted, plus
105
+ individually proven named phases, run identity, runtime output validation,
106
+ journal, and resume. Then read [its recipe](references/dispatch-workflow.md).
107
+ - **Path B:** requires proven native spawn, wait, and aggregate plus effective
108
+ concurrency and thread capacity ≥2. Then read [its recipe](references/dispatch-subagents.md).
109
+ - **Path C:** keep recon and building direct and serial in the main thread. Produce
110
+ the same FILE → SLICES evidence, create each worktree from the integrated base,
111
+ apply the builder contract, validate the result, then continue. Load no reference.
112
+
113
+ Phases 0 and 3–6 always remain in the main thread. Visible fan-out progress may
114
+ replace the ~30-second heartbeat; otherwise the standing heartbeat remains required.
115
+
98
116
  ## Phase 0 — Setup
99
117
 
100
118
  1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
@@ -106,15 +124,15 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
106
124
  preflight's single degraded summary is the only warning. Never guess a project
107
125
  command, tunnel, login, or verify recipe.
108
126
  3. **Preflight — refuse a wave already in flight, otherwise claim it.** Before
109
- dispatch, inspect all three same-machine collision signals: **(a)** an existing
110
- `wave-active/<anchor>` tag; **(b)** any slice branch ahead of the wave's current
111
- base (`git rev-list --count <base>..<slice-branch>` > 0); **(c)** uncommitted
112
- changes in any slice worktree (`git -C <worktree> status --porcelain` non-empty).
113
- A hit not created by this run means another session may be building the wave:
114
- **STOP**, report the exact tag/branch/worktree, and do not touch it. If clean,
115
- record that this run owns the claim and plant a LOCAL annotated tag:
116
- `git tag -a wave-active/<anchor> -m "orchestrating since <UTC timestamp>;
117
- slices: <slice-branches>"`. It is local coordination state — never push it.
127
+ dispatch, inspect the two same-machine work signals: **(a)** any slice branch
128
+ ahead of the wave's current base (`git rev-list --count <base>..<slice-branch>`
129
+ > 0); **(b)** uncommitted changes in any slice worktree (`git -C <worktree>
130
+ status --porcelain` non-empty). Acquire the claim itself through `claimWave`
131
+ from `src/lib/waveClaim.mjs`: a compare-and-set on the `wave-active/<anchor>`
132
+ LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
133
+ `acquired: false` or a work signal you did not create means another session
134
+ owns the wave **STOP**, report the returned `claim.owner` plus the exact
135
+ branch/worktree, touch nothing. Local coordination state — never push the tag.
118
136
  4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
119
137
  points there). Bring its branch to current `main`:
120
138
  `git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
@@ -132,17 +150,10 @@ preflight clean + this run's local claim planted · wave branch ff'd to
132
150
 
133
151
  ## Phase 1 — Disjointness recon (the load-bearing step)
134
152
 
135
- Zero merge conflicts later depends entirely on getting this right.
136
-
137
- - Delegate to a read-only investigator agent: for EACH slice the exact file path of
138
- every named component + resolve ambiguous targets, then a **FILE → SLICES** table
139
- listing every file that appears in ≥2 slices.
140
- - Build the **overlap graph**. Identify the **conflict hub** (the slice whose new
141
- artifacts other slices reuse). **Build the hub first**, merge it, THEN the
142
- dependents stop conflicting.
143
- - Cut into **waves of fully file-disjoint slices**. Edited-by-≥2 = serialize across
144
- waves; only-shared-via-import = safe. A new primitive edited by one slice but
145
- *consumed* by others is NOT a conflict.
153
+ Phase 1 uses the selected orchestration mechanics. Resolve every named component,
154
+ produce the **FILE → SLICES** table and overlap graph, then build the conflict hub
155
+ before its dependents. Cut fully file-disjoint waves; shared imports are safe, but
156
+ files edited by multiple slices serialize across waves.
146
157
  - **Native blocking edges are the frontier authority.** Read the anchor's
147
158
  buildable frontier from the tracker's native issue dependencies:
148
159
  `python3 scripts/board-sync.py frontier <anchor#>` → `FREI` / `BLOCKED by #…` /
@@ -151,15 +162,11 @@ Zero merge conflicts later depends entirely on getting this right.
151
162
  body text or table order alone. The frontier must AGREE with your Phase-1
152
163
  dependency order; a contradiction is a plan finding to reconcile before dispatch,
153
164
  not a detail.
154
- - **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch — the
155
- plan is authority.** `to-issues` cuts slices independently, so a shared
156
- append-only file (a query-key registry, a barrel, a shared types module) is often
157
- claimed by *every* slice, with duplicate/clashing adds. **The hub slice OWNS the
158
- shared-mutable file: it pre-adds ALL the wave's keys/types/helpers; dependents
159
- CONSUME only and never touch it.** Embed verbatim in each dependent's contract:
160
- "X already exists in `<file>` — do NOT add it, consume only." (Real case: all 14
161
- sub-issues claimed the same registry adds + 4 contradictions — hub expanded to
162
- own all 20 keys, batch merged conflict-free.)
165
+ - **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch.** Safe
166
+ declaration-only registries may be predeclared by one hub; eager/validated
167
+ registries that read targets must serialize helper-owning slices through
168
+ dependency edges, each appending only its own existing artifact after creation.
169
+ Both preserve one owner per shared edit and the no-conflict invariant.
163
170
  - **Retirement slices require a valid topological deletion order.** Before
164
171
  dispatching slices that delete a legacy cluster, map every to-delete module's
165
172
  production importers and build the cluster's internal import graph. Order the
@@ -168,25 +175,19 @@ Zero merge conflicts later depends entirely on getting this right.
168
175
  deletions form a cycle, separate each-slice-green steps are impossible: combine
169
176
  the whole cycle into ONE atomic slice instead of landing dangling imports.
170
177
 
171
- **Done when:** FILE→SLICES table exists · every ≥2-slice file has exactly ONE
172
- owning slice · disjoint waves cut in dependency order · every dependent contract
173
- carries its verbatim consume-only lines.
178
+ **Done when:** FILE→SLICES table exists · each shared file has either one
179
+ declaration-only owner with verbatim consume-only dependents, or an explicit serialized
180
+ owner sequence for eager/validated additions where each owner appends only its own existing artifact · disjoint waves cut in dependency order.
174
181
 
175
182
  ## Phase 2 — Dispatch one wave in parallel (isolated worktree per implementer)
176
183
 
177
- Phase 2+3 repeat **per disjoint wave** from Phase 1 the conflict-hub wave first.
178
- Within ONE wave, all slices dispatch at once. **Dispatch only `FREI` slices**
179
- re-read the native frontier (`frontier <anchor#>`) before each wave; a
180
- gate-before-build edge clears only when its blocker actually lands (never
181
- "unblock" by editing body text remove the edge via `dep-remove` if the plan
182
- genuinely changed). Two per-slice calls first: **(a)
183
- inline vs delegate** a tiny mechanical bit (a rename, a 1-2-line tweak) you do
184
- yourself — and **(b) tier + effort** (Standing rules → Routing). For each
185
- delegated slice:
186
-
187
- - **One worktree per agent** off the wave-branch HEAD, own index so parallel agents
188
- never share a git index. Use your project's worktree-setup command (`§Setup`),
189
- else plain `git worktree add <path> -b feat/<anchor>-<slug>`.
184
+ Phase 2 uses the selected orchestration mechanics, repeating with Phase 3 per
185
+ disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
186
+ `frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
187
+ Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
188
+ Standing rules. Tiny mechanical work may stay inline.
189
+ For Path A/B, create one worktree per agent from wave HEAD, using `§Setup` or
190
+ `git worktree add <path> -b feat/<anchor>-<slug>`.
190
191
  - **Build the prompt from [`references/builder-contract.md`](references/builder-contract.md)**
191
192
  — fill the slots with the slice's VERBATIM What+AC, plan decision, recon
192
193
  file:line map and consume-only lines; never paraphrase (paraphrase drift has
@@ -201,8 +202,7 @@ package tests + green fast gate (`§Builder Commands`) — or a STOP item you re
201
202
 
202
203
  ## Phase 3 — Serial integration
203
204
 
204
- In the wave worktree: `git merge --no-ff <slice-branch>` per slice (disjoint
205
- conflict-free). After EACH wave, on the integrated branch:
205
+ In the wave worktree, `git merge --no-ff <slice-branch>` per slice. After EACH wave:
206
206
 
207
207
  - Typecheck both packages + the **FULL suite** — catches sibling/consumer test
208
208
  breaks the agent ownership didn't cover (hardcoded count/tab asserts). Exact
@@ -307,9 +307,9 @@ written · merge order documented.
307
307
  your own processes, targeted by the worktree's assigned ports, never blind).
308
308
  Remove temp verify scripts (a login helper, DB-check scripts).
309
309
  - **Remove only this run's claim marker.** If this run planted
310
- `wave-active/<anchor>`, delete that exact local tag after success or abort. Never
311
- delete a claim marker observed during a preflight collision or any other
312
- `wave-active/*` marker; ownership, not a broad pattern, authorizes cleanup.
310
+ `wave-active/<anchor>`, call `releaseWaveClaim` with this run's owner after
311
+ success or abort; its owner check, not a broad `wave-active/*` pattern,
312
+ authorizes cleanup, and a foreign marker is left untouched.
313
313
  - **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions
314
314
  log, gitignored at worktree-root) and propagate each build-time assumption marker
315
315
  to the sibling issue it carries. A hand-driven multi-PR / migration landing does
@@ -56,13 +56,26 @@ invocation for each in this prompt so the builder cannot guess a wrong one.
56
56
  completed command result. Never end your turn while a command is still running.
57
57
 
58
58
  ## Report back (concise)
59
- Files touched · decisions taken · test results (exact completed command results
60
- and exit status) · commit SHA · STOP items · what the orchestrator should visually
61
- verify.
59
+ Return exactly ONE JSON object against the builder report contract no prose
60
+ around it, no second object. Cover: files touched · decisions taken · test
61
+ results (exact completed command results and exit status) · commit SHA · STOP
62
+ items · what the orchestrator should visually verify.
62
63
  ```
63
64
 
64
65
  Orchestrator notes:
65
66
 
67
+ - **The report contract is identical on every orchestration path.** Whether the
68
+ builder was dispatched by a scripted workflow, by native subagents, or run
69
+ directly and serially, it reports the same shape. `src/lib/reportValidator.mjs`
70
+ is the source of truth; [`references/report-contracts.md`](report-contracts.md)
71
+ is its machine-checked mirror for hosts that must inline a schema. Fill the
72
+ report section above with the builder schema from whichever of the two the
73
+ host can reach — never a hand-written variant.
74
+ - **Validation is always the main thread's.** Schema-validate the returned
75
+ object, then call `semanticVerify` with independently collected Git facts. A
76
+ builder's own claim of success is a hypothesis; a payload that does not parse
77
+ or fails either check is a missing report, not a PASS.
78
+
66
79
  - `{{CONSUME_ONLY_LINES}}` come from the Phase-1 reconciliation, e.g.
67
80
  "X already exists in `<file>` — do NOT add it, consume only."
68
81
  - For dependent slices, fill hub artifact paths from the hub agent's report
@@ -0,0 +1,79 @@
1
+ # Path B — Native subagent dispatch
2
+
3
+ Load this recipe only when the capability selector returns Path B. That result
4
+ requires proven native spawn, wait, and aggregate primitives plus effective
5
+ concurrency and thread capacity ≥2. Route from proven capabilities only, never
6
+ from a surface name, and do not emulate a missing primitive.
7
+
8
+ This recipe is **dormant on the current Codex host.** A verify spike against
9
+ codex-cli 0.144.6 (2026-07-21) proved native start plus bounded wait, and an
10
+ effective concurrency of 4, but the host exposes tool entries carrying only a
11
+ name and a description: no tool schema, no callable or permitted flags, no
12
+ thread capacity. The adapter therefore emits `unknown` for those fields and the
13
+ selector fails closed to Path C. Only a future host that supplies the complete
14
+ normalized inventory selects this path.
15
+
16
+ ## Main-thread preparation
17
+
18
+ 1. Read the canonical `RECON_REPORT_SCHEMA` and `BUILDER_REPORT_SCHEMA` values
19
+ from `src/lib/reportValidator.mjs`. They are the same contract every
20
+ orchestration path reports against.
21
+ 2. Embed the relevant schema verbatim in each subagent prompt, together with the
22
+ instruction to return **exactly ONE JSON object** and nothing else — no
23
+ prose, no fences, no second object. The host does not enforce output shape,
24
+ so the contract lives in the prompt and the check lives in the main thread.
25
+ 3. Acquire the wave claim and create every worktree from the integrated base
26
+ through `claimWave` in `src/lib/waveClaim.mjs` before any spawn. Claim and
27
+ worktree creation stay serial in the main thread; only the agents fan out.
28
+
29
+ ## Round 1 — Recon
30
+
31
+ Spawn **one read-only explorer per slice**, all in one batch so they run
32
+ concurrently, then join them with an **explicit wait** on the spawned set —
33
+ never a sleep, a poll loop, or an implicit continue. Aggregate only after the
34
+ wait returns.
35
+
36
+ Each explorer returns one recon report. Validate every returned payload against
37
+ the recon schema in the main thread: a payload that does not parse, carries
38
+ extra top-level keys, or fails the schema **is not a PASS** — it is a missing
39
+ report. Re-spawn that single explorer with the failure quoted back to it; never
40
+ accept a prose summary in place of the object.
41
+
42
+ ## Main-thread reconcile boundary
43
+
44
+ Pass the complete, validated recon set to `reconcileReconReports`. A
45
+ reconciliation failure stops the wave. A successful result is the only boundary
46
+ that permits builders to start; use its overlap graph and dependency edges to
47
+ cut safe dispatch batches. Multiple editors are safe only when dependency
48
+ reachability totally orders them; shared-mutable files still require exactly one
49
+ edit owner.
50
+
51
+ Every orchestration path crosses this same main-thread reconciliation boundary.
52
+ Reconciliation is never delegated to a subagent.
53
+
54
+ ## Round 2 — Build
55
+
56
+ For the current reconciled batch, spawn **one builder per slice**, again as one
57
+ concurrent batch joined by an explicit wait. Give each builder the verbatim
58
+ builder contract, its reconciled allowlist, and its required commands. The host
59
+ exposes no per-agent role, model, or reasoning selector, so routing falls back
60
+ to the parent session configuration — record the tier you intended in the
61
+ prompt itself rather than assuming the host honoured it.
62
+
63
+ Each builder returns exactly one builder report. Validate it against the builder
64
+ schema and then run `semanticVerify` on it in the main thread. A subagent's own
65
+ claim of success is a hypothesis, never the gate.
66
+
67
+ ## B1 fan-out is out of scope
68
+
69
+ The **B1** shape — a single fan-out over a work list (`spawn_agents_on_csv`)
70
+ plus a host-enforced per-agent `output_schema` — is explicitly excluded. The
71
+ same spike found the callable spawn schema exposes only `task_name`, `message`,
72
+ and `fork_turns`: no work-list fan-out and no output-schema parameter. This
73
+ recipe therefore documents the **B2** shape only: explicit per-slice spawns
74
+ joined by an explicit wait, with validation owned by the main thread.
75
+
76
+ Re-opening B1 requires its own version-pinned verify spike — tracked as an open
77
+ spike issue on the kit's own tracker — before any recipe or adapter change.
78
+ Never infer the capability from a release note; prove it against the pinned
79
+ runtime first.
@@ -0,0 +1,58 @@
1
+ # Path A — Scripted Workflow dispatch
2
+
3
+ Load this recipe only when the capability selector returns Path A. That result
4
+ requires the literal `Workflow` tool and every required primitive. Route from
5
+ proven capabilities only, never from a surface name, and do not emulate
6
+ Workflow. The current Codex host lacks complete capability evidence and selects
7
+ Path C; a future host selects whichever path its evidence proves.
8
+
9
+ ## Main-thread preparation
10
+
11
+ 1. Read the canonical `RECON_REPORT_SCHEMA` and `BUILDER_REPORT_SCHEMA` values
12
+ from `src/lib/reportValidator.mjs`.
13
+ 2. Serialize each value as an inline schema literal in its generated Workflow
14
+ script. Workflow scripts cannot import modules, so never put an `import()`,
15
+ `require`, `process`, or `fetch` workaround in them.
16
+ 3. Build deterministic run arguments. Pass run identity, slice IDs, prompts,
17
+ models, effort levels, and timestamps through `args`; never call
18
+ `Date.now()` or `Math.random()` in a script.
19
+
20
+ ## Run 1 — Recon
21
+
22
+ Declare the named recon phase in `meta.phases`. Within it, make one `agent()`
23
+ call per slice, with explicit `model`, `effort`, and `phase` options. Give every
24
+ call the inline recon schema so the Workflow runtime rejects prose or malformed
25
+ output before aggregation.
26
+
27
+ Use the run identity supplied in `args` and retain the Workflow-managed
28
+ `journal.jsonl`. The main thread waits for the Recon run to finish and collects
29
+ its schema-valid reports. It must not dispatch a builder yet.
30
+
31
+ ## Main-thread reconcile boundary
32
+
33
+ Pass the complete Recon-run result to `reconcileReconReports`. A reconciliation
34
+ failure stops the wave. A successful result is the only boundary that permits
35
+ the Build run to start; use its overlap graph and dependency edges to cut safe
36
+ dispatch batches. Multiple editors are safe only when dependency reachability
37
+ totally orders them; shared-mutable files still require exactly one edit owner.
38
+
39
+ Every orchestration path, including Paths B and C, must cross this same
40
+ main-thread reconciliation boundary. Reconciliation is not Workflow-script
41
+ logic.
42
+
43
+ ## Run 2 — Build
44
+
45
+ Generate a separate Build run with its own named entry in `meta.phases`. For the
46
+ current reconciled batch, make one `agent()` call per slice with explicit
47
+ `model`, `effort`, and `phase` options and the inline builder schema. Preserve
48
+ the reconciled allowlist and required commands in each verbatim builder prompt;
49
+ the main thread still performs `semanticVerify` on every returned report.
50
+
51
+ ## Resume exactly once
52
+
53
+ Resume an interrupted Recon or Build run with its recorded `resumeFromRunId`
54
+ and the same deterministic `args`. Workflow returns cached results for completed
55
+ agents: accept those results and dispatch only unfinished calls. Never create a
56
+ replacement run for completed work, and never replay a completed builder. This
57
+ makes each builder phase execute exactly once while the retained
58
+ `journal.jsonl` remains the recovery and progress record.
@@ -0,0 +1,42 @@
1
+ # Wave Report Contracts
2
+
3
+ `src/lib/reportValidator.mjs` is the source of truth. The JSON blocks below are
4
+ machine-checked mirrors for hosts that must inline a schema and cannot import the
5
+ module. Do not edit a block without changing the exported constant first.
6
+
7
+ ## Recon report
8
+
9
+ Required fields: <!-- fields:recon -->sliceId, plannedFiles, dependencyEdges
10
+
11
+ `plannedFiles[].role` is `edit`, `consume`, or `sharedMutable`.
12
+ `dependencyEdges` records directed slice dependencies as `from`/`to` IDs.
13
+
14
+ <!-- schema:recon:start -->
15
+ ```json
16
+ {"type":"object","required":["sliceId","plannedFiles","dependencyEdges"],"additionalProperties":false,"properties":{"sliceId":{"type":"string","pattern":"^[0-9]+$"},"plannedFiles":{"type":"array","items":{"type":"object","required":["path","role"],"additionalProperties":false,"properties":{"path":{"type":"string"},"role":{"type":"string","enum":["edit","consume","sharedMutable"]}}}},"dependencyEdges":{"type":"array","items":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"string","pattern":"^[0-9]+$"},"to":{"type":"string","pattern":"^[0-9]+$"}}}}}}
17
+ ```
18
+ <!-- schema:recon:end -->
19
+
20
+ ## Builder report
21
+
22
+ Required fields: <!-- fields:builder -->status, filesTouched, testDecisions, commands, commitSha, stopItems, visualVerify
23
+
24
+ `status` discriminates the `oneOf`: PASS requires a full Git object ID and an
25
+ empty `stopItems`; STOP requires at least one stop item and permits a null SHA.
26
+ Schema validation intentionally accepts nonzero command exits. The orchestrator
27
+ must additionally call `semanticVerify` before accepting PASS.
28
+
29
+ <!-- schema:builder:start -->
30
+ ```json
31
+ {"type":"object","required":["status","filesTouched","testDecisions","commands","commitSha","stopItems","visualVerify"],"additionalProperties":false,"properties":{"status":{"type":"string","enum":["pass","stop"]},"filesTouched":{"type":"array","items":{"type":"string"}},"testDecisions":{"type":"array","items":{"type":"string"}},"commands":{"type":"array","items":{"type":"object","required":["command","exitCode","summary"],"additionalProperties":false,"properties":{"command":{"type":"string"},"exitCode":{"type":"integer"},"summary":{"type":"string"}}}},"commitSha":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{40}$|^[0-9a-f]{64}$"},{"type":"null"}]},"stopItems":{"type":"array","items":{"type":"string"}},"visualVerify":{"type":"string"}},"oneOf":[{"required":["status","commitSha","stopItems"],"properties":{"status":{"const":"pass"},"commitSha":{"type":"string","pattern":"^[0-9a-f]{40}$|^[0-9a-f]{64}$"},"stopItems":{"type":"array","maxItems":0}}},{"required":["status","commitSha","stopItems"],"properties":{"status":{"const":"stop"},"commitSha":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{40}$|^[0-9a-f]{64}$"},{"type":"null"}]},"stopItems":{"type":"array","minItems":1}}}]}
32
+ ```
33
+ <!-- schema:builder:end -->
34
+
35
+ ## Semantic facts
36
+
37
+ Call `semanticVerify(report, { gitFacts, allowlist, requiredCommands })` with
38
+ independently collected Git facts: `objectFormat` (`sha1` or `sha256`), the
39
+ resolved `commitSha`, `baseIsAncestorOfCommit`, and `changedFiles`. The ancestry
40
+ fact means the integration base is an ancestor of the builder commit. The helper
41
+ verifies the full SHA against the repository object format and resolved commit, diff subset,
42
+ required command presence, command exits for PASS, and PASS/STOP exclusivity.
@@ -66,13 +66,20 @@ delegates this route to the shipped `census-update` contract and its focused
66
66
  `scripts/test_census_update_contract.test.mjs` proof; it does not reproduce
67
67
  activation, snapshots, or enforcement. Setup itself never calls `activateCensus`.
68
68
 
69
- Disable follows the ordered contract: remove the kit-owned hook, remove the
70
- kit-owned gate, then atomically replace only the profile's `enabled` value with
71
- `false`, preserving unknown keys, and verify `disabled` through
72
- `resolveCensusState`. Enforcement removal must finish before any profile
73
- mutation. Treat the choice document, local scanners, their tests, the profile,
74
- and the active snapshot as consumer-owned evidence. List those files and ask
75
- for separate deletion approval; without that approval, retain them.
69
+ Activation owns durable enforcement: every focused test declared by the active
70
+ profile must remain transitively reachable through one shared project-local
71
+ census check entry point from both local CI and pre-push. `census-update`
72
+ reconciles that narrow kit-owned census wiring idempotently and requires an
73
+ executable wiring proof before it can report `current`; setup does not pre-wire
74
+ the optional bootstrap state.
75
+
76
+ Disable follows the ordered contract: remove only the kit-owned census wiring
77
+ (including the kit-owned hook and gate block), then atomically replace only the
78
+ profile's `enabled` value with `false`, preserving unknown keys, and verify
79
+ `disabled` through `resolveCensusState`. Enforcement removal must finish before
80
+ any profile mutation. Treat the choice document, local scanners, their tests,
81
+ the profile, and the active snapshot as consumer-owned evidence. List those
82
+ files and ask for separate deletion approval; without that approval, retain them.
76
83
  Setup never deletes consumer-owned files as part of disable.
77
84
 
78
85
  ## Setup report
package/README.md CHANGED
@@ -305,7 +305,10 @@ any language works — map each role once, rename an option with one profile edi
305
305
  `init` records a sha256 of every file it installs. That's the line between the
306
306
  two: **edit any skill or script freely** — `update` detects your edits and backs
307
307
  them up rather than clobbering them. Your **project layer** (`docs/agents/*`, the
308
- board profile, `CLAUDE.md`) is created once and never touched by `update`.
308
+ board profile, `CLAUDE.md`, `AGENTS.md`) remains consumer-owned. `update` may
309
+ only apply a previewed, schema-driven, idempotent compatibility migration that
310
+ fills missing evidence without rewriting an existing value; it verifies and
311
+ rolls that migration back with the rest of the candidate.
309
312
 
310
313
  ## Updating & removing
311
314
 
@@ -346,8 +349,65 @@ concurrency-safe. Do not run manifest-mutating commands concurrently. Flags:
346
349
  `--force` (overwrite pre-existing untracked files on `init`), `--yes` / `-y`
347
350
  (accept non-interactive update decisions).
348
351
 
352
+ ## Upgrade notes
353
+
354
+ ### 0.33.0 — capability-gated orchestration
355
+
356
+ `kit-update` reconciles this release for you. These notes matter only if you
357
+ maintain a **local fork of `orchestrate-wave`**: the blocks below changed
358
+ behaviour, so a forked copy must re-apply them by hand or it keeps orchestrating
359
+ the old way. Decision record:
360
+ [`docs/adr/0002-capability-gated-orchestration.md`](docs/adr/0002-capability-gated-orchestration.md).
361
+
362
+ - **Capability matrix, fail-closed.** The dispatch mechanic is selected from
363
+ host-supplied capability evidence, degrading A → B → C. Missing or `unknown`
364
+ evidence never proves a capability, and Path C (direct, serial) is always
365
+ available.
366
+ - **No emulation of a missing primitive.** A host without a scripted workflow
367
+ runtime gets the simpler recipe, never a hand-rolled imitation of one.
368
+ - **Codex Path B is native subagents.** Explicit per-slice spawns joined by an
369
+ explicit wait — dormant until a host supplies the complete normalized
370
+ inventory.
371
+ - **JSON-schema reports plus independent verification.** Every path returns
372
+ schema-valid recon and builder reports and crosses the same main-thread
373
+ boundary; a builder's own PASS is a hypothesis until `semanticVerify` confirms
374
+ it against independently collected Git facts.
375
+ - **Per-batch, post-hub worktree provisioning.** Worktrees are created serially
376
+ in the main thread from the integrated base after the hub lands, under an
377
+ atomic compare-and-set wave claim; reuse on a stale base now STOPs.
378
+ - **Heartbeat during long gates.** Long-running gates report status rather than
379
+ waiting silently.
380
+
349
381
  ## Release notes
350
382
 
383
+ ### 0.33.0
384
+
385
+ - added: `.agents/skills/orchestrate-wave/references/dispatch-subagents.md`
386
+ - added: `.agents/skills/orchestrate-wave/references/dispatch-workflow.md`
387
+ - added: `.agents/skills/orchestrate-wave/references/report-contracts.md`
388
+ - added: `.claude/skills/orchestrate-wave/references/dispatch-subagents.md`
389
+ - added: `.claude/skills/orchestrate-wave/references/dispatch-workflow.md`
390
+ - added: `.claude/skills/orchestrate-wave/references/report-contracts.md`
391
+ - added: `src/lib/capabilityMatrix.mjs`
392
+ - added: `src/lib/reconcileReconReports.mjs`
393
+ - added: `src/lib/reportValidator.mjs`
394
+ - added: `src/lib/waveClaim.mjs`
395
+ - changed: `.agents/skills/orchestrate-wave/SKILL.md`
396
+ - changed: `.agents/skills/orchestrate-wave/references/builder-contract.md`
397
+ - changed: `.claude/skills/orchestrate-wave/SKILL.md`
398
+ - changed: `.claude/skills/orchestrate-wave/references/builder-contract.md`
399
+ - changed: `scripts/worktree-lifecycle/setup.py`
400
+
401
+ ### 0.32.1
402
+
403
+ - changed: `.agents/skills/census-update/SKILL.md`
404
+ - changed: `.agents/skills/kit-update/SKILL.md`
405
+ - changed: `.agents/skills/setup-workflow/census.md`
406
+ - changed: `.claude/skills/census-update/SKILL.md`
407
+ - changed: `.claude/skills/kit-update/SKILL.md`
408
+ - changed: `.claude/skills/setup-workflow/census.md`
409
+ - changed: `scripts/readiness.mjs`
410
+
351
411
  ### 0.32.0
352
412
 
353
413
  - changed: `.agents/skills/audit-skills/SKILL.md`