@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.
- package/.agents/skills/census-update/SKILL.md +34 -3
- package/.agents/skills/kit-update/SKILL.md +18 -4
- package/.agents/skills/orchestrate-wave/SKILL.md +54 -54
- package/.agents/skills/orchestrate-wave/references/builder-contract.md +16 -3
- package/.agents/skills/orchestrate-wave/references/dispatch-subagents.md +79 -0
- package/.agents/skills/orchestrate-wave/references/dispatch-workflow.md +58 -0
- package/.agents/skills/orchestrate-wave/references/report-contracts.md +42 -0
- package/.agents/skills/setup-workflow/census.md +14 -7
- package/.claude/skills/census-update/SKILL.md +34 -3
- package/.claude/skills/kit-update/SKILL.md +18 -4
- package/.claude/skills/orchestrate-wave/SKILL.md +54 -54
- package/.claude/skills/orchestrate-wave/references/builder-contract.md +16 -3
- package/.claude/skills/orchestrate-wave/references/dispatch-subagents.md +79 -0
- package/.claude/skills/orchestrate-wave/references/dispatch-workflow.md +58 -0
- package/.claude/skills/orchestrate-wave/references/report-contracts.md +42 -0
- package/.claude/skills/setup-workflow/census.md +14 -7
- package/README.md +61 -1
- package/agent-workflow-kit.package.json +105 -13
- package/docs/adr/0002-capability-gated-orchestration.md +70 -0
- package/package.json +1 -1
- package/scripts/readiness.mjs +48 -14
- package/scripts/test_census_update_contract.test.mjs +14 -0
- package/scripts/test_orchestrate_wave_contract.py +136 -0
- package/scripts/test_worktree_setup_base_guard.py +140 -0
- package/scripts/worktree-lifecycle/setup.py +40 -0
- package/src/cli.mjs +2 -2
- package/src/commands/update.mjs +21 -3
- package/src/lib/bundle.mjs +10 -0
- package/src/lib/capabilityMatrix.mjs +94 -0
- package/src/lib/reconcileReconReports.mjs +111 -0
- package/src/lib/reportValidator.mjs +186 -0
- package/src/lib/updateCandidate.mjs +78 -4
- package/src/lib/waveClaim.mjs +134 -0
|
@@ -72,6 +72,35 @@ proof is still open for state resolution even when Git tracking lets the base
|
|
|
72
72
|
scan enumerate it. Overrides are report input only and are never passed into
|
|
73
73
|
scanning, fingerprinting, verification, or state resolution.
|
|
74
74
|
|
|
75
|
+
## Durable enforcement
|
|
76
|
+
|
|
77
|
+
An activated census is a durable consumer contract, not a one-time activation
|
|
78
|
+
check. Before activating a candidate or reporting an unchanged census as
|
|
79
|
+
`current`, derive the complete set of every `localScanners[].test` from the
|
|
80
|
+
profile and inspect the repository's documented local CI and pre-push paths.
|
|
81
|
+
|
|
82
|
+
Reuse one existing shared project-local census check entry point when the
|
|
83
|
+
repository has one. Otherwise add the smallest such entry point through the
|
|
84
|
+
repository's established script mechanism; do not create a second census
|
|
85
|
+
engine or duplicate scanner logic. It must execute every declared focused test,
|
|
86
|
+
and both local CI and pre-push must transitively reach that same entry point.
|
|
87
|
+
Add or extend an executable wiring test that fails when either durable path or
|
|
88
|
+
any declared scanner test becomes unreachable; matching prose or a bare grep is
|
|
89
|
+
not sufficient proof.
|
|
90
|
+
|
|
91
|
+
Keep enforcement reconciliation idempotent. An already complete wiring graph
|
|
92
|
+
is a no-write result. Mark only the narrow gate block added for this lifecycle
|
|
93
|
+
with the repository's existing managed marker, or with
|
|
94
|
+
`agent-workflow-kit:census` when no marker convention exists; that block is the
|
|
95
|
+
kit-owned census wiring. Preserve surrounding consumer-owned gate logic.
|
|
96
|
+
|
|
97
|
+
Missing or partial durable wiring is a failed candidate verification. If the
|
|
98
|
+
repository has no safe documented gate seam, ask one bounded wiring question
|
|
99
|
+
and stop before activation. On a scanner-test or wiring-proof failure, report
|
|
100
|
+
`failed`, discard the candidate when safe, and confirm that the previous active
|
|
101
|
+
census bytes are unchanged. Never report `current` from activation-time test
|
|
102
|
+
success alone.
|
|
103
|
+
|
|
75
104
|
## Workflow
|
|
76
105
|
|
|
77
106
|
1. **Check.** Read the local profile and active census, if present. Report a
|
|
@@ -95,8 +124,9 @@ scanning, fingerprinting, verification, or state resolution.
|
|
|
95
124
|
and a focused passing test for that pattern. Run that test before rescanning.
|
|
96
125
|
6. **Verify a candidate.** Build the candidate from the fresh scan and recorded
|
|
97
126
|
decisions. Fail verification when any surface or behavior remains `offen`,
|
|
98
|
-
when a required local scanner test fails,
|
|
99
|
-
|
|
127
|
+
when a required local scanner test fails, when durable enforcement or its
|
|
128
|
+
executable wiring test is incomplete, or when the candidate fingerprints do
|
|
129
|
+
not describe the current repository.
|
|
100
130
|
7. **Activate.** Call `activateCensus` with a real verifier so it stages, verifies,
|
|
101
131
|
and atomically swaps under its local lock. On `CensusTransactionError`, report
|
|
102
132
|
`updating` or `failed` and keep the previous active census authoritative.
|
|
@@ -137,4 +167,5 @@ Return only the useful audit trail:
|
|
|
137
167
|
- surface coverage `X of Y`;
|
|
138
168
|
- separate behavior overview;
|
|
139
169
|
- visible `nicht relevant` justifications and active override, if any; <!-- language-census: ok -->
|
|
140
|
-
- local scanner tests run
|
|
170
|
+
- local scanner tests run, durable local-CI/pre-push reachability, and the
|
|
171
|
+
transaction/no-write result.
|
|
@@ -43,11 +43,25 @@ release contain the same artifact.
|
|
|
43
43
|
data, infer an external fact, or manufacture `pending`/`not-applicable` to
|
|
44
44
|
make a capability appear ready.
|
|
45
45
|
|
|
46
|
+
Readiness-schema adoption also keeps the Claude and Codex instruction
|
|
47
|
+
surfaces compatible. When exactly one applicable instruction surface has a
|
|
48
|
+
non-empty `## Prod` section and another has no such section, the staged
|
|
49
|
+
candidate mirrors the same section body into the missing surface. This
|
|
50
|
+
narrow migration is previewed as `migrated`, destination-race checked,
|
|
51
|
+
idempotent, and covered by the same verification and rollback transaction.
|
|
52
|
+
It may create a missing instruction file, but it never rewrites an existing
|
|
53
|
+
`## Prod` body. Empty, malformed, or divergent sections are named as
|
|
54
|
+
conflicts and leave every consumer file untouched. This migration belongs
|
|
55
|
+
to `kit update`; do not rerun `setup-workflow` after an ordinary update.
|
|
56
|
+
Readiness JSON diagnoses only the affected path and problem category
|
|
57
|
+
(`missing-file`, `missing-section`, `empty-section`, or
|
|
58
|
+
`divergent-section`); it never echoes consumer content.
|
|
59
|
+
|
|
46
60
|
3. Read the terminal report. `aktuell` proves a second run found no upstream
|
|
47
|
-
delta. A conflict report names and counts
|
|
48
|
-
consumer file untouched. Follow its
|
|
49
|
-
conflict manually; never auto-merge,
|
|
50
|
-
the incoming copy.
|
|
61
|
+
delta or pending readiness migration. A conflict report names and counts
|
|
62
|
+
every category and leaves every consumer file untouched. Follow its
|
|
63
|
+
recommendation and resolve each named conflict manually; never auto-merge,
|
|
64
|
+
delete a local edit, or silently choose the incoming copy.
|
|
51
65
|
|
|
52
66
|
Read all four availability categories alongside the file delta: newly
|
|
53
67
|
available skill core, newly degraded optional blocks, newly blocked skill
|
|
@@ -73,10 +73,10 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
|
|
|
73
73
|
- **Plan-level error** (integration/verify reveals a wrong LOCKED decision, not a
|
|
74
74
|
slice bug): STOP the wave. No improvised redesign AFK — keep worktrees intact,
|
|
75
75
|
report findings + options.
|
|
76
|
-
- **On ANY wave STOP/abort:** if this run planted the active-wave claim,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
- **On ANY wave STOP/abort:** if this run planted the active-wave claim, release
|
|
77
|
+
it via `releaseWaveClaim` with this run's owner as part of shutdown — it
|
|
78
|
+
refuses a foreign payload. Never delete a claim marker observed during a
|
|
79
|
+
preflight collision. A stale own marker would block a safe retry.
|
|
80
80
|
- **Routing = one axis: how expensive is a wrong result to catch?** Mechanically
|
|
81
81
|
caught (test/screenshot/lint) → default tier at medium/low effort; plausible-but-
|
|
82
82
|
wrong / subtle logic / architecture → top tier at high effort + main-thread
|
|
@@ -87,6 +87,24 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
|
|
|
87
87
|
first red test). The same axis sets how hard you re-verify. Borderline → default
|
|
88
88
|
tier + re-verify beats blanket top tier.
|
|
89
89
|
|
|
90
|
+
## Orchestration mechanics
|
|
91
|
+
|
|
92
|
+
Pass only host-supplied inventory through `capabilityAdapter.claude` or `.codex`,
|
|
93
|
+
then call the selector. It returns exactly one target; missing or `unknown` evidence
|
|
94
|
+
degrades A → B → C. A model claim is not evidence; do not emulate a missing primitive.
|
|
95
|
+
|
|
96
|
+
- **Path A:** requires the literal `Workflow` tool, callable and permitted, plus
|
|
97
|
+
individually proven named phases, run identity, runtime output validation,
|
|
98
|
+
journal, and resume. Then read [its recipe](references/dispatch-workflow.md).
|
|
99
|
+
- **Path B:** requires proven native spawn, wait, and aggregate plus effective
|
|
100
|
+
concurrency and thread capacity ≥2. Then read [its recipe](references/dispatch-subagents.md).
|
|
101
|
+
- **Path C:** keep recon and building direct and serial in the main thread. Produce
|
|
102
|
+
the same FILE → SLICES evidence, create each worktree from the integrated base,
|
|
103
|
+
apply the builder contract, validate the result, then continue. Load no reference.
|
|
104
|
+
|
|
105
|
+
Phases 0 and 3–6 always remain in the main thread. Visible fan-out progress may
|
|
106
|
+
replace the ~30-second heartbeat; otherwise the standing heartbeat remains required.
|
|
107
|
+
|
|
90
108
|
## Phase 0 — Setup
|
|
91
109
|
|
|
92
110
|
1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
|
|
@@ -98,15 +116,15 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
|
|
|
98
116
|
preflight's single degraded summary is the only warning. Never guess a project
|
|
99
117
|
command, tunnel, login, or verify recipe.
|
|
100
118
|
3. **Preflight — refuse a wave already in flight, otherwise claim it.** Before
|
|
101
|
-
dispatch, inspect
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
dispatch, inspect the two same-machine work signals: **(a)** any slice branch
|
|
120
|
+
ahead of the wave's current base (`git rev-list --count <base>..<slice-branch>`
|
|
121
|
+
> 0); **(b)** uncommitted changes in any slice worktree (`git -C <worktree>
|
|
122
|
+
status --porcelain` non-empty). Acquire the claim itself through `claimWave`
|
|
123
|
+
from `src/lib/waveClaim.mjs`: a compare-and-set on the `wave-active/<anchor>`
|
|
124
|
+
LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
|
|
125
|
+
`acquired: false` or a work signal you did not create means another session
|
|
126
|
+
owns the wave — **STOP**, report the returned `claim.owner` plus the exact
|
|
127
|
+
branch/worktree, touch nothing. Local coordination state — never push the tag.
|
|
110
128
|
4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
|
|
111
129
|
points there). Bring its branch to current `main`:
|
|
112
130
|
`git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
|
|
@@ -124,17 +142,10 @@ preflight clean + this run's local claim planted · wave branch ff'd to
|
|
|
124
142
|
|
|
125
143
|
## Phase 1 — Disjointness recon (the load-bearing step)
|
|
126
144
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
listing every file that appears in ≥2 slices.
|
|
132
|
-
- Build the **overlap graph**. Identify the **conflict hub** (the slice whose new
|
|
133
|
-
artifacts other slices reuse). **Build the hub first**, merge it, THEN the
|
|
134
|
-
dependents stop conflicting.
|
|
135
|
-
- Cut into **waves of fully file-disjoint slices**. Edited-by-≥2 = serialize across
|
|
136
|
-
waves; only-shared-via-import = safe. A new primitive edited by one slice but
|
|
137
|
-
*consumed* by others is NOT a conflict.
|
|
145
|
+
Phase 1 uses the selected orchestration mechanics. Resolve every named component,
|
|
146
|
+
produce the **FILE → SLICES** table and overlap graph, then build the conflict hub
|
|
147
|
+
before its dependents. Cut fully file-disjoint waves; shared imports are safe, but
|
|
148
|
+
files edited by multiple slices serialize across waves.
|
|
138
149
|
- **Native blocking edges are the frontier authority.** Read the anchor's
|
|
139
150
|
buildable frontier from the tracker's native issue dependencies:
|
|
140
151
|
`python3 scripts/board-sync.py frontier <anchor#>` → `FREI` / `BLOCKED by #…` /
|
|
@@ -143,15 +154,11 @@ Zero merge conflicts later depends entirely on getting this right.
|
|
|
143
154
|
body text or table order alone. The frontier must AGREE with your Phase-1
|
|
144
155
|
dependency order; a contradiction is a plan finding to reconcile before dispatch,
|
|
145
156
|
not a detail.
|
|
146
|
-
- **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
CONSUME only and never touch it.** Embed verbatim in each dependent's contract:
|
|
152
|
-
"X already exists in `<file>` — do NOT add it, consume only." (Real case: all 14
|
|
153
|
-
sub-issues claimed the same registry adds + 4 contradictions — hub expanded to
|
|
154
|
-
own all 20 keys, batch merged conflict-free.)
|
|
157
|
+
- **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch.** Safe
|
|
158
|
+
declaration-only registries may be predeclared by one hub; eager/validated
|
|
159
|
+
registries that read targets must serialize helper-owning slices through
|
|
160
|
+
dependency edges, each appending only its own existing artifact after creation.
|
|
161
|
+
Both preserve one owner per shared edit and the no-conflict invariant.
|
|
155
162
|
- **Retirement slices require a valid topological deletion order.** Before
|
|
156
163
|
dispatching slices that delete a legacy cluster, map every to-delete module's
|
|
157
164
|
production importers and build the cluster's internal import graph. Order the
|
|
@@ -160,25 +167,19 @@ Zero merge conflicts later depends entirely on getting this right.
|
|
|
160
167
|
deletions form a cycle, separate each-slice-green steps are impossible: combine
|
|
161
168
|
the whole cycle into ONE atomic slice instead of landing dangling imports.
|
|
162
169
|
|
|
163
|
-
**Done when:** FILE→SLICES table exists ·
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
**Done when:** FILE→SLICES table exists · each shared file has either one
|
|
171
|
+
declaration-only owner with verbatim consume-only dependents, or an explicit serialized
|
|
172
|
+
owner sequence for eager/validated additions where each owner appends only its own existing artifact · disjoint waves cut in dependency order.
|
|
166
173
|
|
|
167
174
|
## Phase 2 — Dispatch one wave in parallel (isolated worktree per implementer)
|
|
168
175
|
|
|
169
|
-
Phase 2
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
yourself — and **(b) tier + effort** (Standing rules → Routing). For each
|
|
177
|
-
delegated slice:
|
|
178
|
-
|
|
179
|
-
- **One worktree per agent** off the wave-branch HEAD, own index so parallel agents
|
|
180
|
-
never share a git index. Use your project's worktree-setup command (`§Setup`),
|
|
181
|
-
else plain `git worktree add <path> -b feat/<anchor>-<slug>`.
|
|
176
|
+
Phase 2 uses the selected orchestration mechanics, repeating with Phase 3 per
|
|
177
|
+
disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
|
|
178
|
+
`frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
|
|
179
|
+
Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
|
|
180
|
+
Standing rules. Tiny mechanical work may stay inline.
|
|
181
|
+
For Path A/B, create one worktree per agent from wave HEAD, using `§Setup` or
|
|
182
|
+
`git worktree add <path> -b feat/<anchor>-<slug>`.
|
|
182
183
|
- **Build the prompt from [`references/builder-contract.md`](references/builder-contract.md)**
|
|
183
184
|
— fill the slots with the slice's VERBATIM What+AC, plan decision, recon
|
|
184
185
|
file:line map and consume-only lines; never paraphrase (paraphrase drift has
|
|
@@ -193,8 +194,7 @@ package tests + green fast gate (`§Builder Commands`) — or a STOP item you re
|
|
|
193
194
|
|
|
194
195
|
## Phase 3 — Serial integration
|
|
195
196
|
|
|
196
|
-
In the wave worktree
|
|
197
|
-
conflict-free). After EACH wave, on the integrated branch:
|
|
197
|
+
In the wave worktree, `git merge --no-ff <slice-branch>` per slice. After EACH wave:
|
|
198
198
|
|
|
199
199
|
- Typecheck both packages + the **FULL suite** — catches sibling/consumer test
|
|
200
200
|
breaks the agent ownership didn't cover (hardcoded count/tab asserts). Exact
|
|
@@ -299,9 +299,9 @@ written · merge order documented.
|
|
|
299
299
|
your own processes, targeted by the worktree's assigned ports, never blind).
|
|
300
300
|
Remove temp verify scripts (a login helper, DB-check scripts).
|
|
301
301
|
- **Remove only this run's claim marker.** If this run planted
|
|
302
|
-
`wave-active/<anchor>`,
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
`wave-active/<anchor>`, call `releaseWaveClaim` with this run's owner after
|
|
303
|
+
success or abort; its owner check, not a broad `wave-active/*` pattern,
|
|
304
|
+
authorizes cleanup, and a foreign marker is left untouched.
|
|
305
305
|
- **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions
|
|
306
306
|
log, gitignored at worktree-root) and propagate each build-time assumption marker
|
|
307
307
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
@@ -72,6 +72,35 @@ proof is still open for state resolution even when Git tracking lets the base
|
|
|
72
72
|
scan enumerate it. Overrides are report input only and are never passed into
|
|
73
73
|
scanning, fingerprinting, verification, or state resolution.
|
|
74
74
|
|
|
75
|
+
## Durable enforcement
|
|
76
|
+
|
|
77
|
+
An activated census is a durable consumer contract, not a one-time activation
|
|
78
|
+
check. Before activating a candidate or reporting an unchanged census as
|
|
79
|
+
`current`, derive the complete set of every `localScanners[].test` from the
|
|
80
|
+
profile and inspect the repository's documented local CI and pre-push paths.
|
|
81
|
+
|
|
82
|
+
Reuse one existing shared project-local census check entry point when the
|
|
83
|
+
repository has one. Otherwise add the smallest such entry point through the
|
|
84
|
+
repository's established script mechanism; do not create a second census
|
|
85
|
+
engine or duplicate scanner logic. It must execute every declared focused test,
|
|
86
|
+
and both local CI and pre-push must transitively reach that same entry point.
|
|
87
|
+
Add or extend an executable wiring test that fails when either durable path or
|
|
88
|
+
any declared scanner test becomes unreachable; matching prose or a bare grep is
|
|
89
|
+
not sufficient proof.
|
|
90
|
+
|
|
91
|
+
Keep enforcement reconciliation idempotent. An already complete wiring graph
|
|
92
|
+
is a no-write result. Mark only the narrow gate block added for this lifecycle
|
|
93
|
+
with the repository's existing managed marker, or with
|
|
94
|
+
`agent-workflow-kit:census` when no marker convention exists; that block is the
|
|
95
|
+
kit-owned census wiring. Preserve surrounding consumer-owned gate logic.
|
|
96
|
+
|
|
97
|
+
Missing or partial durable wiring is a failed candidate verification. If the
|
|
98
|
+
repository has no safe documented gate seam, ask one bounded wiring question
|
|
99
|
+
and stop before activation. On a scanner-test or wiring-proof failure, report
|
|
100
|
+
`failed`, discard the candidate when safe, and confirm that the previous active
|
|
101
|
+
census bytes are unchanged. Never report `current` from activation-time test
|
|
102
|
+
success alone.
|
|
103
|
+
|
|
75
104
|
## Workflow
|
|
76
105
|
|
|
77
106
|
1. **Check.** Read the local profile and active census, if present. Report a
|
|
@@ -95,8 +124,9 @@ scanning, fingerprinting, verification, or state resolution.
|
|
|
95
124
|
and a focused passing test for that pattern. Run that test before rescanning.
|
|
96
125
|
6. **Verify a candidate.** Build the candidate from the fresh scan and recorded
|
|
97
126
|
decisions. Fail verification when any surface or behavior remains `offen`,
|
|
98
|
-
when a required local scanner test fails,
|
|
99
|
-
|
|
127
|
+
when a required local scanner test fails, when durable enforcement or its
|
|
128
|
+
executable wiring test is incomplete, or when the candidate fingerprints do
|
|
129
|
+
not describe the current repository.
|
|
100
130
|
7. **Activate.** Call `activateCensus` with a real verifier so it stages, verifies,
|
|
101
131
|
and atomically swaps under its local lock. On `CensusTransactionError`, report
|
|
102
132
|
`updating` or `failed` and keep the previous active census authoritative.
|
|
@@ -137,4 +167,5 @@ Return only the useful audit trail:
|
|
|
137
167
|
- surface coverage `X of Y`;
|
|
138
168
|
- separate behavior overview;
|
|
139
169
|
- visible `nicht relevant` justifications and active override, if any; <!-- language-census: ok -->
|
|
140
|
-
- local scanner tests run
|
|
170
|
+
- local scanner tests run, durable local-CI/pre-push reachability, and the
|
|
171
|
+
transaction/no-write result.
|
|
@@ -43,11 +43,25 @@ release contain the same artifact.
|
|
|
43
43
|
data, infer an external fact, or manufacture `pending`/`not-applicable` to
|
|
44
44
|
make a capability appear ready.
|
|
45
45
|
|
|
46
|
+
Readiness-schema adoption also keeps the Claude and Codex instruction
|
|
47
|
+
surfaces compatible. When exactly one applicable instruction surface has a
|
|
48
|
+
non-empty `## Prod` section and another has no such section, the staged
|
|
49
|
+
candidate mirrors the same section body into the missing surface. This
|
|
50
|
+
narrow migration is previewed as `migrated`, destination-race checked,
|
|
51
|
+
idempotent, and covered by the same verification and rollback transaction.
|
|
52
|
+
It may create a missing instruction file, but it never rewrites an existing
|
|
53
|
+
`## Prod` body. Empty, malformed, or divergent sections are named as
|
|
54
|
+
conflicts and leave every consumer file untouched. This migration belongs
|
|
55
|
+
to `kit update`; do not rerun `setup-workflow` after an ordinary update.
|
|
56
|
+
Readiness JSON diagnoses only the affected path and problem category
|
|
57
|
+
(`missing-file`, `missing-section`, `empty-section`, or
|
|
58
|
+
`divergent-section`); it never echoes consumer content.
|
|
59
|
+
|
|
46
60
|
3. Read the terminal report. `aktuell` proves a second run found no upstream
|
|
47
|
-
delta. A conflict report names and counts
|
|
48
|
-
consumer file untouched. Follow its
|
|
49
|
-
conflict manually; never auto-merge,
|
|
50
|
-
the incoming copy.
|
|
61
|
+
delta or pending readiness migration. A conflict report names and counts
|
|
62
|
+
every category and leaves every consumer file untouched. Follow its
|
|
63
|
+
recommendation and resolve each named conflict manually; never auto-merge,
|
|
64
|
+
delete a local edit, or silently choose the incoming copy.
|
|
51
65
|
|
|
52
66
|
Read all four availability categories alongside the file delta: newly
|
|
53
67
|
available skill core, newly degraded optional blocks, newly blocked skill
|