@event4u/agent-config 13.0.0 → 14.1.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +195 -315
- package/README.md +1 -1
- package/dist/agent-src/commands/evals/roadmap.json +8 -0
- package/dist/agent-src/commands/fix/ci.md +39 -1
- package/dist/agent-src/commands/pr/create.md +65 -4
- package/dist/agent-src/commands/roadmap/next.md +28 -5
- package/dist/agent-src/commands/work.md +16 -0
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +47 -0
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +94 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +30 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +21 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +55 -8
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +42 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +29 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +33 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +25 -8
- package/dist/agent-src/rules/ui-audit-gate.md +25 -8
- package/dist/agent-src/scripts/gate_execute.ts +395 -0
- package/dist/agent-src/scripts/resume_probe.ts +422 -0
- package/dist/agent-src/scripts/roadmap_gates.ts +138 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +53 -2
- package/dist/agent-src/skills/ai-council/SKILL.md +61 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +116 -0
- package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +27 -0
- package/dist/agent-src/skills/experiment-loop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/experiment-loop/references/pivot-ladder.md +54 -0
- package/dist/agent-src/skills/experiment-loop/references/protocol.md +61 -0
- package/dist/agent-src/skills/experiment-loop/references/register-format.md +66 -0
- package/dist/agent-src/skills/roadmap-management/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +8 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +43 -3
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-N7FEST6D.js → chunk-7PZ4FSZB.js} +351 -174
- package/dist/cli-delegate/{chunk-3B72LSZL.js → chunk-F3YUF7SA.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +336 -112
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +40 -18
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +2128 -1326
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1764 -899
- package/dist/router.json +1 -1
- package/dist/scripts/condense.js +1 -1
- package/dist/scripts/condense.js.map +1 -1
- package/dist/ui/assets/{index-B0aMJnuz.js → index-C1pBRm1f.js} +2 -2
- package/dist/ui/assets/index-C1pBRm1f.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
- package/src/agent-src/scripts/gate_execute.ts +395 -0
- package/src/agent-src/scripts/resume_probe.ts +422 -0
- package/src/agent-src/scripts/roadmap_gates.ts +138 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +53 -2
- package/src/config/ci-local-parity.yml +13 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +111 -5
- package/src/config/gate-violation-baselines.json +5 -5
- package/src/config/rule-activation-census.json +41 -0
- package/src/config/rule-stub-ceilings.json +52 -0
- package/src/scripts/_dispatch.bash +4 -0
- package/src/scripts/_lib/evaluator_contract.ts +159 -0
- package/src/scripts/_lib/gate_ledger.ts +5 -1
- package/src/scripts/_lib/gh_transient.ts +80 -0
- package/src/scripts/_lib/release_material.ts +16 -5
- package/src/scripts/_lib/review_independence.ts +111 -0
- package/src/scripts/_lib/session_register.ts +14 -0
- package/src/scripts/_lib/skill_catalogue.ts +20 -0
- package/src/scripts/_lib/skill_catalogue_series.ts +411 -0
- package/src/scripts/_lib/turn_end_refusals.ts +482 -0
- package/src/scripts/ai_council/_py_json.ts +96 -0
- package/src/scripts/ai_council/cli_call_budget.ts +357 -0
- package/src/scripts/ai_council/clients.ts +80 -143
- package/src/scripts/ai_council/config.ts +25 -11
- package/src/scripts/ai_council/probe_store.ts +196 -0
- package/src/scripts/ai_council/qualification.ts +425 -0
- package/src/scripts/ai_council/qualification_wiring.ts +243 -0
- package/src/scripts/ai_council/quorum_wiring.ts +211 -0
- package/src/scripts/ai_team/team_dispatch.ts +40 -6
- package/src/scripts/build_archive_index.ts +62 -3
- package/src/scripts/capture_skill_catalogue.ts +264 -4
- package/src/scripts/check_evaluator_schema.ts +249 -0
- package/src/scripts/check_gate_coverage.ts +93 -0
- package/src/scripts/check_pr_ci_current.ts +492 -0
- package/src/scripts/check_review_schema.ts +195 -0
- package/src/scripts/check_rule_activation_census.ts +451 -0
- package/src/scripts/check_rule_stub_ceiling.ts +1128 -0
- package/src/scripts/condense.ts +1 -1
- package/src/scripts/council_cli.ts +141 -191
- package/src/scripts/dispatch_r2_reviewer.ts +8 -1
- package/src/scripts/git_authorization_hook.ts +186 -1
- package/src/scripts/hook_manifest.yaml +72 -5
- package/src/scripts/hooks/block_unauthorized_git.ts +62 -6
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +43 -1
- package/src/scripts/hooks/interruption_ledger_hook.ts +256 -0
- package/src/scripts/hooks/ship_diff_volume_hook.ts +180 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +119 -26
- package/src/scripts/hooks_doctor.ts +112 -0
- package/src/scripts/interruption_report.ts +443 -0
- package/src/scripts/lint_evidence_artifacts.ts +359 -0
- package/src/scripts/lint_roadmap_blockers.ts +65 -0
- package/src/scripts/lint_roadmap_complexity.ts +7 -1
- package/src/scripts/release.ts +38 -53
- package/src/scripts/rule_activation_census.ts +292 -0
- package/src/scripts/schemas/evaluator-output.schema.json +60 -0
- package/src/scripts/schemas/review-findings.schema.json +31 -0
- package/src/scripts/self_review_gate.ts +6 -0
- package/src/scripts/session_register_hook.ts +30 -1
- package/src/scripts/sync_pr_branch.ts +271 -0
- package/src/scripts/test_council_qualification.ts +213 -0
- package/dist/ui/assets/index-B0aMJnuz.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml) [](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml) [](https://www.npmjs.com/package/@event4u/agent-config) [](https://glama.ai/mcp/servers/event4u-app/agent-config) [](https://mcptoplist.com/server/glama%2Fevent4u-app%2Fagent-config)
|
|
6
6
|
|
|
7
|
-
[](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/commands/) [](docs/guidelines/) [](dist/agent-src/personas/) [](dist/agent-src/personas/advisors/)
|
|
8
8
|
|
|
9
9
|
**Try it in 30 seconds** — drop one read-only subagent into any repo and watch it gate "done": `@production-validator check this branch is actually done`. No wizard, no lock-in, nothing else installed — the [30-second wedge ↓](#quickstart) is the whole first step. Start at the proof, not the catalog: **[event4u-app.github.io/agent-config/proof/](https://event4u-app.github.io/agent-config/proof/)**.
|
|
10
10
|
|
|
@@ -29,6 +29,14 @@
|
|
|
29
29
|
{
|
|
30
30
|
"prompt": "plan out this feature step by step",
|
|
31
31
|
"expected": "feature"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"prompt": "process road-to-user-out-of-the-loop.md to completion",
|
|
35
|
+
"expected": "roadmap"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"prompt": "either roadmap it or turn it into a feature plan, your pick",
|
|
39
|
+
"expected": "roadmap"
|
|
32
40
|
}
|
|
33
41
|
]
|
|
34
42
|
}
|
|
@@ -80,8 +80,46 @@ reason to settle first.
|
|
|
80
80
|
- Re-run the failing tool locally (inside the PHP container) to confirm the fix.
|
|
81
81
|
- If multiple tools failed, fix and verify each one.
|
|
82
82
|
|
|
83
|
+
### 5. Land it when the CI being fixed belongs to an open PR
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
"FIX THE CI" NAMES A REMOTE STATE. A LOCAL-ONLY FIX LEAVES THE RED CHECK
|
|
87
|
+
EXACTLY AS RED, WHICH MAKES THE INSTRUCTION A NO-OP.
|
|
88
|
+
COMMIT, PUSH, THEN RE-VERIFY ON THE PUSHED HEAD.
|
|
89
|
+
A GREEN LOCAL RUN IS NOT THE VERDICT. A GREEN CI RUN ON AN EARLIER COMMIT
|
|
90
|
+
IS NOT THE VERDICT EITHER.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Applies only when the failing run belongs to an **open PR for the current
|
|
94
|
+
branch** — that is what makes the deliverable remote. Then:
|
|
95
|
+
|
|
96
|
+
1. Commit the fix (chunked, the agent picks the split per
|
|
97
|
+
[`commit-policy`](../../../rules/commit-policy.md) — never ask how).
|
|
98
|
+
2. Update the branch against its PR base first:
|
|
99
|
+
`./scripts-run src/scripts/sync_pr_branch`, then regenerate any derived files
|
|
100
|
+
the merge touched (`task sync && task generate-tools`). A PR left behind its
|
|
101
|
+
base accumulates conflicts for the moment someone wants to merge it, and a
|
|
102
|
+
push against a moved base is rejected — both cost a round trip that this one
|
|
103
|
+
call prevents.
|
|
104
|
+
3. Push. The instruction named it; do not raise a separate ask
|
|
105
|
+
([`/create-pr` § 4d item 5](../../../git/pr/create/command.md)).
|
|
106
|
+
4. Re-verify remotely: `./scripts-run src/scripts/check_pr_ci_current`, then
|
|
107
|
+
settle the check set on the new head. Report the *remote* verdict, never the
|
|
108
|
+
local one.
|
|
109
|
+
|
|
110
|
+
Bounded by N=3 per failing target ([`autonomous-execution`](../../../rules/autonomous-execution.md)).
|
|
111
|
+
|
|
83
112
|
### Rules
|
|
84
113
|
|
|
85
|
-
- **
|
|
114
|
+
- **No open PR for this branch → do NOT commit or push.** Apply local fixes only
|
|
115
|
+
and hand back. Without a PR there is no remote state the instruction could be
|
|
116
|
+
about, so the deliverable really is the working tree.
|
|
117
|
+
- **A push is authorized for the named failure only.** Once the checks the user
|
|
118
|
+
pointed at are green, further pushes need their own instruction — a one-off
|
|
119
|
+
authorization is spent on the operation it was given for.
|
|
120
|
+
- **Never force-push over a commit you did not author** — including a
|
|
121
|
+
GitHub *Update branch* merge on your own PR branch. Merge it in; the ask-first
|
|
122
|
+
floor is [`git-history-discipline`](../../../rules/git-history-discipline.md)
|
|
123
|
+
and nothing here reaches it.
|
|
86
124
|
- **Do NOT skip or ignore errors** — fix the root cause.
|
|
87
125
|
- If a fix is unclear, explain the error and ask the user for guidance.
|
|
@@ -149,6 +149,21 @@ than less: the gate can now read the PR's real `baseRefName` from the forge, so
|
|
|
149
149
|
a stacked or release-line PR is measured against the branch it will actually
|
|
150
150
|
merge into instead of against the repo default.
|
|
151
151
|
|
|
152
|
+
**The resolution is executable now, not just described.**
|
|
153
|
+
`./scripts-run src/scripts/sync_pr_branch` resolves the base from the open PR
|
|
154
|
+
(so a stacked or release-line PR is measured against what it actually merges
|
|
155
|
+
into), fetches, and merges it in when the branch is behind. On a conflict it
|
|
156
|
+
STOPS and splits the conflicted paths into generated and authored — the first has
|
|
157
|
+
one correct resolution (regenerate), the second has none a script may choose.
|
|
158
|
+
Deliberately not in the pre-push hook: it mutates the tree, and a hook that
|
|
159
|
+
rewrites the tree mid-push turns one rejected push into an unreviewed commit.
|
|
160
|
+
Detection belongs in the hook and is already there; resolution is a step you run
|
|
161
|
+
with the result in front of you.
|
|
162
|
+
|
|
163
|
+
After it merges, REGENERATE — a clean auto-merge of a generated file is still
|
|
164
|
+
wrong, and this is the step that produced the one stale-dashboard conflict on
|
|
165
|
+
every merge of this branch.
|
|
166
|
+
|
|
152
167
|
Where the project wires this gate into its pre-push chain, a push that goes out
|
|
153
168
|
through the hook is covered without a separate step. Run it by hand when you push
|
|
154
169
|
with the hook bypassed, or when you are about to open the PR some time after the
|
|
@@ -430,12 +445,58 @@ turns on `gh pr checks` every minute is the tool-loop
|
|
|
430
445
|
4. **Bounded at N=3 per failing target** ([`autonomous-execution`](../rules/autonomous-execution.md)).
|
|
431
446
|
Same failure signature twice → the hypothesis is wrong; change approach
|
|
432
447
|
rather than spending the third attempt on a near-identical retry.
|
|
433
|
-
5. **The push stays gated
|
|
448
|
+
5. **The push stays gated — and a fix-the-CI instruction IS the gate being
|
|
449
|
+
cleared.** `git push` is a Hard Floor
|
|
434
450
|
([`non-destructive-by-default`](../rules/non-destructive-by-default.md)) and a
|
|
435
451
|
one-off authorization is spent on the push it was given for
|
|
436
|
-
([`commit-policy`](../rules/commit-policy.md)).
|
|
437
|
-
|
|
438
|
-
|
|
452
|
+
([`commit-policy`](../rules/commit-policy.md)). What that forbids is a loop
|
|
453
|
+
that re-pushes on its **own** authority. It does not forbid delivering the
|
|
454
|
+
instruction the user actually gave.
|
|
455
|
+
|
|
456
|
+
```
|
|
457
|
+
AN INSTRUCTION WHOSE DELIVERABLE IS A REMOTE STATE NAMES THE PUSH.
|
|
458
|
+
"FIX THE CI" · "RESOLVE THE CONFLICT WITH MAIN" · "UPDATE THE PR" ·
|
|
459
|
+
"MAKE THE CHECKS GREEN" → THE PUSH IS THAT INSTRUCTION, NOT A SECOND
|
|
460
|
+
OPERATION ON TOP OF IT. DO NOT RAISE A SEPARATE ASK FOR IT.
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
The test is **where the deliverable lives**, and it is decidable: a red check,
|
|
464
|
+
a `CONFLICTING` merge state and a stale PR head are all facts about the
|
|
465
|
+
remote. An unpushed local fix leaves every one of them exactly as it was, so
|
|
466
|
+
treating the push as optional turns the instruction into a no-op and hands the
|
|
467
|
+
user back the state they asked to have changed. This is the same reading
|
|
468
|
+
[`no-cheap-questions`](../rules/no-cheap-questions.md) IL 5 gives prerequisite
|
|
469
|
+
work and IL 6 gives an already-named destination.
|
|
470
|
+
|
|
471
|
+
**What is still NOT covered**, so the floor keeps its teeth: an instruction
|
|
472
|
+
about the *code* only ("fix the type error", "use file X for the tests") — that
|
|
473
|
+
authorizes the edit, never the push. A push to a branch or base the user did
|
|
474
|
+
not name. A push after the named deliverable is already green. And a
|
|
475
|
+
force-push over a commit you did not author, which
|
|
476
|
+
[`git-history-discipline`](../rules/git-history-discipline.md) gates
|
|
477
|
+
separately and which this clause never reaches.
|
|
478
|
+
|
|
479
|
+
6. **Re-verify remotely after the re-push — the fix is not done until the
|
|
480
|
+
REMOTE says so.**
|
|
481
|
+
|
|
482
|
+
```
|
|
483
|
+
A GREEN LOCAL RUN IS NOT THE VERDICT. A GREEN CI RUN ON AN EARLIER
|
|
484
|
+
COMMIT IS NOT THE VERDICT EITHER. THE VERDICT IS A SETTLED CHECK SET
|
|
485
|
+
WHOSE HEAD SHA IS THE BRANCH HEAD YOU JUST PUSHED.
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Loop back to the top of § 4d — settle again, on the new head. Two traps make
|
|
489
|
+
this more than a restatement:
|
|
490
|
+
|
|
491
|
+
- **Stale green.** `gh pr checks` reports the last run it has, which may have
|
|
492
|
+
run against the pre-fix commit. Compare the SHA the checks ran against with
|
|
493
|
+
the PR head before reading a green as yours.
|
|
494
|
+
- **The re-push may not have landed.** A pre-push hook can refuse, and the
|
|
495
|
+
branch can be behind its OWN remote counterpart because someone pressed
|
|
496
|
+
*Update branch*. `git push` exiting non-zero means the PR still carries the
|
|
497
|
+
failure — never report the fix as delivered off a local verification.
|
|
498
|
+
|
|
499
|
+
`./scripts-run src/scripts/check_pr_ci_current` answers both in one call.
|
|
439
500
|
|
|
440
501
|
**When the verdict cannot be reached** — network down, `gh` failing, the run
|
|
441
502
|
never registering — say so plainly and name what is unverified. A background
|
|
@@ -236,15 +236,38 @@ diagnose and fix in the working tree on red, within the N=3 budget per
|
|
|
236
236
|
[`autonomous-execution`](../../rules/autonomous-execution.md).
|
|
237
237
|
|
|
238
238
|
```
|
|
239
|
-
THE LOCAL FIX IS AUTONOMOUS.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
THE LOCAL FIX IS AUTONOMOUS. A RE-PUSH ON THE AGENT'S OWN AUTHORITY IS NOT.
|
|
240
|
+
BUT AN INSTRUCTION WHOSE DELIVERABLE IS A REMOTE STATE — "FIX THE CI",
|
|
241
|
+
"RESOLVE THE CONFLICT WITH MAIN", "UPDATE THE PR" — NAMES THE PUSH, AND
|
|
242
|
+
DELIVERING IT IS NOT A SECOND OPERATION TO ASK ABOUT.
|
|
243
|
+
NEVER INVENT A PER-PR "STANDING MANDATE" FOR A PUSH NOBODY ASKED FOR.
|
|
244
|
+
AND NEVER CALL A CI FIX DONE OFF A LOCAL RUN — RE-VERIFY ON THE PUSHED HEAD.
|
|
243
245
|
```
|
|
244
246
|
|
|
247
|
+
The full reading, its decidable test, and what it deliberately does **not**
|
|
248
|
+
cover live in [`/create-pr` § 4d items 5–6](../../git/pr/create/command.md);
|
|
249
|
+
this is the pointer, not a second copy.
|
|
250
|
+
|
|
251
|
+
Measured on this command's own run, 2026-08-17: a `/roadmap:next` invocation
|
|
252
|
+
raised a separate push ask **three times** — after a CI fix, after a
|
|
253
|
+
cross-reference fix, and after resolving a merge conflict the user had asked
|
|
254
|
+
for by name. Each ask cost a turn and returned the same answer, and the third
|
|
255
|
+
was for a conflict whose entire existence is a remote fact. That is the friction
|
|
256
|
+
this clause removes; the floor it keeps is the *unnamed* push.
|
|
257
|
+
|
|
258
|
+
**Before every push to the open PR**, bring the branch up to its base with
|
|
259
|
+
`./scripts-run src/scripts/sync_pr_branch` and regenerate afterwards. Measured on
|
|
260
|
+
this run: the base moved three times, the push was rejected twice for it, and the
|
|
261
|
+
PR reached `CONFLICTING` in between. Verify the result afterwards with
|
|
262
|
+
`./scripts-run src/scripts/check_pr_ci_current` — a green local gate says nothing
|
|
263
|
+
about a fix that was never pushed, and a green CI run on an earlier commit says
|
|
264
|
+
nothing about the current one.
|
|
265
|
+
|
|
245
266
|
The cheapest CI-fix loop is the one that never fires: run `task
|
|
246
267
|
preflight` before the first push, which runs the same
|
|
247
|
-
`skill_linter --changed` gate CI does.
|
|
268
|
+
`skill_linter --changed` gate CI does. Two gates it does NOT reach are
|
|
269
|
+
`check_references` and `check_r2_manifest`, both remote-only — measured on this
|
|
270
|
+
run, each forced one extra commit and therefore one extra review re-bind.
|
|
248
271
|
|
|
249
272
|
### 8. Report
|
|
250
273
|
|
|
@@ -149,6 +149,22 @@ engine owns the verdict.
|
|
|
149
149
|
| `medium` | PARTIAL halt | Engine emits the assumptions report; surface verbatim, wait for the user. On confirm, write `state.input.data.confidence_confirmed=true` and re-run. On refine, replace `state.input.data.raw` with the new prompt, clear `reconstructed_ac` + `assumptions`, and re-run |
|
|
150
150
|
| `low` | BLOCKED halt | Engine emits exactly one clarifying question on the weakest dimension (per [`ask-when-uncertain`](../rules/ask-when-uncertain.md) Iron Law). Surface verbatim, wait for the user, append their answer to `state.input.data.raw`, clear `reconstructed_ac` + `assumptions`, and re-run |
|
|
151
151
|
|
|
152
|
+
**Elicitation is the contract's, not this command's.** The bands above decide
|
|
153
|
+
*whether* the run may proceed; they do not each own a question surface. When
|
|
154
|
+
`/work` derives an execution contract, the `medium`-band assumptions report and
|
|
155
|
+
the `low`-band clarifying question are rows of the
|
|
156
|
+
[`contract-decision-sheet`](../contexts/execution/contract-decision-sheet.md)
|
|
157
|
+
rendered inside that contract screen — the same derivation
|
|
158
|
+
[`roadmap-execution-contract`](../contexts/execution/roadmap-execution-contract.md)
|
|
159
|
+
runs for `/roadmap:process-*`, reused rather than reimplemented here. `/work`
|
|
160
|
+
carrying a second elicitation mechanism is exactly the drift the single-surface
|
|
161
|
+
principle exists to stop, and reusing the derivation means a fix to the sheet
|
|
162
|
+
reaches both entry points at once.
|
|
163
|
+
|
|
164
|
+
Unchanged by that reuse: the engine still owns the band verdict (never flip it
|
|
165
|
+
yourself), a `low` band still blocks, and the locked decision classes still
|
|
166
|
+
escalate individually rather than becoming sheet rows.
|
|
167
|
+
|
|
152
168
|
Once the gate releases, the rest of the loop is identical to
|
|
153
169
|
`/implement-ticket`: `create-plan`, `apply-plan`, `run-tests`,
|
|
154
170
|
`review-changes` directives flow through the same dispatch table. The
|
|
@@ -42,12 +42,59 @@ rank() → apply floor, drop blocklisted, anti-noise heuristics,
|
|
|
42
42
|
apply_cooldown() → drop (command, evidence) pairs shown in window
|
|
43
43
|
│
|
|
44
44
|
▼
|
|
45
|
+
tier() → HIGH | MEDIUM | LOW (see § Tier matrix)
|
|
46
|
+
│
|
|
47
|
+
├── HIGH → route directly + one-line basis statement
|
|
48
|
+
│
|
|
49
|
+
└── MEDIUM / LOW
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
45
52
|
render() → numbered-options block + Recommendation line
|
|
46
53
|
│
|
|
47
54
|
▼
|
|
48
55
|
agent emits the block as the first and ONLY thing this turn
|
|
49
56
|
```
|
|
50
57
|
|
|
58
|
+
## Tier matrix — the one case that routes without a block
|
|
59
|
+
|
|
60
|
+
Extends the non-interactive contract's tier matrix onto this layer
|
|
61
|
+
(road-to-user-out-of-the-loop Phase 1). The principle it serves is
|
|
62
|
+
single-elicitation: when the routed command **has its own contract screen**,
|
|
63
|
+
showing an options block first makes the user confirm the same intent twice.
|
|
64
|
+
|
|
65
|
+
**HIGH** requires ALL of the following. They are deterministic facts, not a
|
|
66
|
+
confidence score, because a threshold on a fuzzy score is exactly what would
|
|
67
|
+
turn "unique match" into "usually right":
|
|
68
|
+
|
|
69
|
+
1. The signal names the command **uniquely** — the roadmap file named in the
|
|
70
|
+
prompt exists on disk, or the phrase matches a `trigger_description`
|
|
71
|
+
**exactly** (not a substring hit).
|
|
72
|
+
2. **No second candidate above the floor.** Two candidates, even at very
|
|
73
|
+
different scores, is MEDIUM.
|
|
74
|
+
3. The routed command **shows its own confirmation** (a contract screen, a
|
|
75
|
+
plan-confidence gate, or an explicit accept step). A command that would
|
|
76
|
+
begin acting on arrival is never HIGH, whatever the signal.
|
|
77
|
+
|
|
78
|
+
HIGH routes directly and prints **one line** naming its basis:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Routing to /roadmap:process-full — the named roadmap file exists and no second
|
|
82
|
+
candidate scored above the floor. Its contract screen is your confirmation.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
MEDIUM and LOW keep the numbered-options block, unchanged.
|
|
86
|
+
|
|
87
|
+
**What HIGH does not do.** It does not skip a confirmation; it removes a
|
|
88
|
+
*duplicate* one. Condition 3 is what makes that true rather than rhetorical —
|
|
89
|
+
strip it and this becomes auto-execution. It also never applies to a Hard-Floor
|
|
90
|
+
action, which is gated by [`non-destructive-by-default`](../../rules/non-destructive-by-default.md)
|
|
91
|
+
regardless of how it was reached.
|
|
92
|
+
|
|
93
|
+
**Kill criterion** (from the originating roadmap's Risk 3): more than 5 %
|
|
94
|
+
mis-routes across 50 auto-routes reverts this to block-always. The instrument
|
|
95
|
+
for that count does not exist yet — until it does, a mis-route is a reportable
|
|
96
|
+
defect, and the honest position is that the rate is unmeasured rather than low.
|
|
97
|
+
|
|
51
98
|
## Scoring breakdown
|
|
52
99
|
|
|
53
100
|
Per match, `match.ts` computes:
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Contract Decision Sheet
|
|
2
|
+
|
|
3
|
+
Loaded by [`roadmap-execution-contract`](roadmap-execution-contract.md)'s
|
|
4
|
+
derivation, so every consumer of the contract inherits it without binding to a
|
|
5
|
+
command. One place asks the user: the contract screen. The plan-confidence
|
|
6
|
+
interview, artifact understand-questions, and in-run clarifications feed *this*
|
|
7
|
+
surface instead of opening rounds of their own.
|
|
8
|
+
|
|
9
|
+
## The Iron Law
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
ONE SHEET PER CONTRACT DISPLAY. EVERY QUESTION THE PRE-SCAN FOUND IS ON IT,
|
|
13
|
+
EACH WITH A DEFAULT, PLUS AN ACCEPT-ALL-DEFAULTS PATH.
|
|
14
|
+
A QUESTION THAT COULD HAVE BEEN ON THE SHEET AND IS ASKED MID-RUN INSTEAD
|
|
15
|
+
IS A DEFECT, NOT A CLARIFICATION.
|
|
16
|
+
THE LOCKED CLASSES NEVER ENTER THE SHEET — THEY ESCALATE WHEN THEY FIRE.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What goes on the sheet
|
|
20
|
+
|
|
21
|
+
Pre-scan class 4 (open questions / ambiguity) produces the rows. A row is
|
|
22
|
+
sheet-eligible when **all** hold:
|
|
23
|
+
|
|
24
|
+
- it is answerable **before** the run starts — its answer does not depend on
|
|
25
|
+
something the run itself produces;
|
|
26
|
+
- its decision class is `trivial`, `low_impact`, or `medium_impact`
|
|
27
|
+
([`ai-council-config`](../../../docs/contracts/ai-council-config.md)
|
|
28
|
+
§ decision_resolution);
|
|
29
|
+
- a **conservative default** exists and can be stated in one line.
|
|
30
|
+
|
|
31
|
+
Anything else is not a sheet row. In particular:
|
|
32
|
+
|
|
33
|
+
| Not on the sheet | Why | Where it goes instead |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `high_impact` / `user_required` | Locked to the user by an Iron Law no config lifts | Escalates during the run, at the moment it fires |
|
|
36
|
+
| A question whose answer depends on run output | Cannot be answered at contract time; a guessed default would be a fabrication | The in-run escalation path |
|
|
37
|
+
| A question with no conservative default | An option set with no safe side is a real decision, not a preference | Its own escalation |
|
|
38
|
+
|
|
39
|
+
## Shape
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Decision sheet — <N> question(s), all answerable now
|
|
43
|
+
|
|
44
|
+
1. <question>
|
|
45
|
+
default: <option> — <one clause on why this is the conservative side>
|
|
46
|
+
alt: <option> · <option>
|
|
47
|
+
2. <question>
|
|
48
|
+
default: <option> — <why>
|
|
49
|
+
alt: <option>
|
|
50
|
+
|
|
51
|
+
A. Accept all defaults
|
|
52
|
+
B. Change some (name them: "1=x, 2=y")
|
|
53
|
+
C. Ask me these one at a time instead
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The sheet is rendered **inside** the contract screen, above its Accept line —
|
|
57
|
+
never as a second block and never as a second turn. Accepting the contract with
|
|
58
|
+
`A` is one decision point answered by one keystroke, which is what makes it one
|
|
59
|
+
question under [`ask-when-uncertain`](../../rules/ask-when-uncertain.md)'s
|
|
60
|
+
Iron Law rather than N questions wearing a table.
|
|
61
|
+
|
|
62
|
+
`C` exists because the batch is a convenience the user may decline. It is not a
|
|
63
|
+
fallback the agent may choose: only the user picks `C`.
|
|
64
|
+
|
|
65
|
+
## Recording — every answer is auditable after the fact
|
|
66
|
+
|
|
67
|
+
Each answered row is written to the run's decision-memo directory with the
|
|
68
|
+
question, the chosen option, and whether it came from `A` (default accepted) or
|
|
69
|
+
an explicit override. Risk 1 of the originating roadmap is that a batched sheet
|
|
70
|
+
invites accepting a decision that deserved thought; the mitigation is not to
|
|
71
|
+
make the sheet harder to accept, it is to make every accepted default
|
|
72
|
+
reviewable afterwards. A default accepted without being read is recoverable
|
|
73
|
+
when it is on the record and invisible when it is not.
|
|
74
|
+
|
|
75
|
+
## Why one sheet is not "fewer safeguards"
|
|
76
|
+
|
|
77
|
+
The count of *decisions the user makes* is unchanged. What changes is the number
|
|
78
|
+
of times the run stops to collect them: N stops become one. The locked classes
|
|
79
|
+
still stop the run individually, when they fire, because their whole point is
|
|
80
|
+
that they are seen at the moment they matter rather than pre-answered in a batch.
|
|
81
|
+
|
|
82
|
+
Measured motivation: [`roadmap-process-loop § 3a`](roadmap-process-loop.md)
|
|
83
|
+
records that 27 of 37 active roadmaps carried no `execution.mode` and therefore
|
|
84
|
+
derived no contract at all — so before this surface existed, the questions this
|
|
85
|
+
sheet batches were not asked once, they were asked one at a time, mid-run,
|
|
86
|
+
by whichever mechanism happened to hit them first.
|
|
87
|
+
|
|
88
|
+
## See also
|
|
89
|
+
|
|
90
|
+
- [`roadmap-execution-contract`](roadmap-execution-contract.md) — the screen this renders inside; its single Accept is the authorization.
|
|
91
|
+
- [`roadmap-process-loop § 3`](roadmap-process-loop.md) — the pre-scan that produces the rows, and the § 3a ladder that decides whether a contract is derived at all.
|
|
92
|
+
- [`ai-council-config`](../../../docs/contracts/ai-council-config.md) § decision_resolution — the class table and the locked-class Iron Law.
|
|
93
|
+
- [`ask-when-uncertain`](../../rules/ask-when-uncertain.md) — one question per turn; one sheet answered by one keystroke is one question.
|
|
94
|
+
- [`user-interaction`](../../rules/user-interaction.md) — the numbered-options shape and the single recommendation line.
|
|
@@ -91,6 +91,36 @@ inline with the same stop conditions:
|
|
|
91
91
|
summary (goal + in/out + constraints + AC) is stable for two turns.
|
|
92
92
|
4. **Then author** via the surface's normal flow.
|
|
93
93
|
|
|
94
|
+
#### 3c-batch — the batch branch, when a contract is being derived
|
|
95
|
+
|
|
96
|
+
Serial is correct when the gate runs on its own. It is the wrong shape when the
|
|
97
|
+
gate runs **inside** a contract derivation
|
|
98
|
+
([`roadmap-execution-contract`](roadmap-execution-contract.md)), because the
|
|
99
|
+
contract's whole premise is that the user is asked once. N serial turns inside a
|
|
100
|
+
one-confirmation flow is the flow contradicting itself.
|
|
101
|
+
|
|
102
|
+
So when the gate runs under a contract derivation, replace steps 2–3 with:
|
|
103
|
+
|
|
104
|
+
1. **One sheet at seed time.** Every load-bearing branch known after step 1
|
|
105
|
+
becomes a row of the
|
|
106
|
+
[`contract-decision-sheet`](contract-decision-sheet.md), each with a
|
|
107
|
+
conservative default. Not two blocks, not two turns.
|
|
108
|
+
2. **At most two rounds, and round two is narrow.** Round two exists only for
|
|
109
|
+
branches *created by round-one answers* — never for branches that were
|
|
110
|
+
knowable at seed time and were missed. A branch that could have been on
|
|
111
|
+
round one and appears on round two is a defect in the step-1 resolve, and
|
|
112
|
+
is recorded as one rather than silently re-asked.
|
|
113
|
+
3. **Remaining ambiguity resolves to its conservative default plus a decision
|
|
114
|
+
memo** — never to a third round and never to a silent guess. The memo makes
|
|
115
|
+
the default reviewable after the fact, which is what allows the round cap to
|
|
116
|
+
be a cap rather than a loss.
|
|
117
|
+
|
|
118
|
+
Unchanged, deliberately: the locked classes never enter a sheet
|
|
119
|
+
(`high_impact` / `user_required` escalate when they fire), and **the C→R1 state
|
|
120
|
+
file below is written exactly as before**. Batching changes how the questions
|
|
121
|
+
are *collected*, never what is recorded — so R1 still never re-asks a resolved
|
|
122
|
+
branch and no plan is interviewed twice.
|
|
123
|
+
|
|
94
124
|
### 4. C→R1 handoff — write the state file
|
|
95
125
|
|
|
96
126
|
On completing the gate (either path that ran an interview), write
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Roadmap Execution Contract
|
|
2
2
|
|
|
3
|
-
Loaded by [`roadmap-process-loop § 3`](roadmap-process-loop.md) when the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Loaded by [`roadmap-process-loop § 3`](roadmap-process-loop.md) when the run's
|
|
4
|
+
**derived** mode is `autonomous` or `phase-checkpoints`. The mode comes from the
|
|
5
|
+
§ 3a ladder — explicit invocation suffix, then frontmatter `execution.mode`,
|
|
6
|
+
then the invocation form — so an ABSENT frontmatter field no longer keeps this
|
|
7
|
+
context unloaded: under `process-full` / `/roadmap:next` it derives
|
|
8
|
+
`autonomous`, under `process-phase` it derives `phase-checkpoints`. Only a
|
|
9
|
+
*derived* `interactive` (asked for explicitly, declared in frontmatter, or
|
|
10
|
+
`process-step`) leaves this context unloaded and falls back to the legacy
|
|
11
|
+
commit-step scan. Defines the run-start pre-scan,
|
|
7
12
|
the contract summary the user confirms ONCE, the grants that
|
|
8
13
|
confirmation activates, and the per-mode gate table.
|
|
9
14
|
|
|
@@ -37,7 +42,13 @@ Scan every open step (text + inline notes) for:
|
|
|
37
42
|
4. **Open questions / ambiguity** — explicit `?` markers, "decide
|
|
38
43
|
whether", options left unresolved, or steps matching the
|
|
39
44
|
[`ask-when-uncertain`](../../rules/ask-when-uncertain.md)
|
|
40
|
-
vague-trigger patterns.
|
|
45
|
+
vague-trigger patterns. These become the rows of the
|
|
46
|
+
[`contract-decision-sheet`](contract-decision-sheet.md), rendered inside the
|
|
47
|
+
summary below — one numbered block, a default per row, and an
|
|
48
|
+
accept-all-defaults path. Loading is part of this derivation, not of any
|
|
49
|
+
command, so every consumer of the contract inherits the sheet. The locked
|
|
50
|
+
classes (`high_impact`, `user_required`) never become rows: they escalate
|
|
51
|
+
during the run, at the moment they fire.
|
|
41
52
|
|
|
42
53
|
## 2. Contract summary — shown once, confirmed once
|
|
43
54
|
|
|
@@ -49,10 +60,12 @@ Git: branch <feat/<roadmap-slug>> · commits: chunked (N commit steps
|
|
|
49
60
|
· PR: open against <default branch> (description only — no merge)
|
|
50
61
|
Artifacts: <N> planned (skills/rules/commands/guidelines) —
|
|
51
62
|
batched overlap check: <result — run NOW, against current state>
|
|
52
|
-
Open questions: <N> →
|
|
53
|
-
configured — will halt on ambiguity">)
|
|
63
|
+
Open questions: <N> → decision sheet below (<M> rows); the rest via AI
|
|
64
|
+
council (<members | "none configured — will halt on ambiguity">)
|
|
54
65
|
Quality: <cadence> · Dashboard: <cadence>
|
|
55
66
|
|
|
67
|
+
<decision sheet, per contract-decision-sheet — omitted entirely when M = 0>
|
|
68
|
+
|
|
56
69
|
Always active regardless of this contract (never lifted):
|
|
57
70
|
• Hard Floor per-commit diff gate (bulk deletions / infra)
|
|
58
71
|
• Push anywhere except feat/<roadmap-slug>; any merge
|
|
@@ -90,7 +103,7 @@ These grants satisfy [`scope-control`](../../rules/scope-control.md)'s
|
|
|
90
103
|
|---|---|---|
|
|
91
104
|
| `autonomous` | All steps `[x]` · quality green per cadence · work committed in chunks on `feat/<roadmap-slug>` · pushed · PR open · archival sweep run. **Merge out of scope, always.** | Safety floors only (+ quality-red, + step reveals out-of-roadmap work) |
|
|
92
105
|
| `phase-checkpoints` | Same end state | Safety floors + a compact status + "continue?" prompt at each phase boundary |
|
|
93
|
-
| `interactive` (absent field) | Legacy: work lands, no git delivery without per-op permission | All gates as authored by their owning rules |
|
|
106
|
+
| `interactive` (derived, never from an absent field) | Legacy: work lands, no git delivery without per-op permission | All gates as authored by their owning rules |
|
|
94
107
|
|
|
95
108
|
If the roadmap contains **no** delivery need and no commit steps, the
|
|
96
109
|
git grants are omitted from the contract (nothing to authorize —
|
|
@@ -76,7 +76,7 @@ options + wait):
|
|
|
76
76
|
> Phase 2: `<name>` — 0/4
|
|
77
77
|
> Next open step: `<description>`
|
|
78
78
|
> Scope: **step | phase | full**
|
|
79
|
-
> Execution mode: **autonomous | phase-checkpoints | interactive** (
|
|
79
|
+
> Execution mode: **autonomous | phase-checkpoints | interactive** (derived per § 3a — name the rung: `invocation suffix` | `frontmatter` | `invocation form`)
|
|
80
80
|
> AI council: **on | off** (`<member list or "no members configured">`)
|
|
81
81
|
> Quality cadence: **end_of_roadmap | per_phase | per_step**
|
|
82
82
|
> Commit steps in roadmap: **N** (see § 3)
|
|
@@ -91,11 +91,55 @@ does not fire.
|
|
|
91
91
|
|
|
92
92
|
## 3. Pre-scan — execution contract or commit-step ask
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
### 3a. Mode derivation ladder — first source wins
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
AN ABSENT `execution.mode` IS NOT A DECLARATION OF `interactive`.
|
|
98
|
+
IT IS THE ABSENCE OF A DECLARATION, AND IS DERIVED — NEVER DEFAULTED SILENTLY.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Resolve the mode from the first source that answers, and **state which rung
|
|
102
|
+
answered** in the pre-run summary so the derivation is auditable rather than
|
|
103
|
+
implicit:
|
|
104
|
+
|
|
105
|
+
| # | Source | Wins when |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| 1 | **Explicit invocation suffix** — `… autonomous` / `… phase-checkpoints` / `… interactive` in the invocation | the user typed it this turn |
|
|
108
|
+
| 2 | **Frontmatter `execution.mode`** | the roadmap declares one |
|
|
109
|
+
| 3 | **Invocation form** (table below) | neither of the above answered |
|
|
110
|
+
|
|
111
|
+
Rung 3, by wrapper:
|
|
112
|
+
|
|
113
|
+
| Wrapper | Derived mode | Contract |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `/roadmap:process-full`, `/roadmap:next` | `autonomous`, **preselected** | offered |
|
|
116
|
+
| `/roadmap:process-phase` | `phase-checkpoints` | offered |
|
|
117
|
+
| `/roadmap:process-step` | — | none (one step needs no run contract) |
|
|
118
|
+
|
|
119
|
+
Still **exactly one confirmation**, never two: rung 3 changes which option the
|
|
120
|
+
contract screen arrives preselected on, never whether the screen is shown. The
|
|
121
|
+
screen's `3. Run interactive instead` option
|
|
122
|
+
([`roadmap-execution-contract § 2`](roadmap-execution-contract.md)) stays on it
|
|
123
|
+
in every case, so a derived mode is always one keystroke from being refused.
|
|
124
|
+
|
|
125
|
+
**Why the old fallback was a defect and not a conservative default.** Absent
|
|
126
|
+
`execution.mode` used to mean the legacy commit-step scan, which derives no
|
|
127
|
+
contract at all — no batched artifact drafting, no council auto-enable, no
|
|
128
|
+
push/PR grant. Measured 2026-08-17: **27 of 37 active roadmaps carry no
|
|
129
|
+
`execution.mode`**, so roughly three quarters of the corpus ran the degraded
|
|
130
|
+
path *under the wrapper built for the opposite*, and silently — the user saw a
|
|
131
|
+
`process-full` invocation behave like an interactive one with no line saying so.
|
|
132
|
+
A default that contradicts the wrapper the user just typed is a wrong answer,
|
|
133
|
+
not a safe one.
|
|
134
|
+
|
|
135
|
+
**What this does NOT change.** A derived mode grants nothing on its own:
|
|
136
|
+
authorization is still the single Accept on the contract screen, per
|
|
137
|
+
[`roadmap-execution-contract § Principle`](roadmap-execution-contract.md). The
|
|
138
|
+
Hard Floor, the locked decision classes, and the kernel-edit soak are untouched.
|
|
139
|
+
|
|
140
|
+
### 3b. Contract or commit-step ask
|
|
141
|
+
|
|
142
|
+
**Derived `autonomous` or `phase-checkpoints`** → load
|
|
99
143
|
[`roadmap-execution-contract`](roadmap-execution-contract.md) and run
|
|
100
144
|
its four-class pre-scan over every open step:
|
|
101
145
|
|
|
@@ -114,8 +158,11 @@ cached for the run, never re-asked. The contract never lifts a Hard
|
|
|
114
158
|
Floor or any safety floor; boundaries + per-mode gate table live in the
|
|
115
159
|
contract context.
|
|
116
160
|
|
|
117
|
-
|
|
118
|
-
|
|
161
|
+
**Derived `interactive`** — i.e. the user asked for it explicitly (rung 1), the
|
|
162
|
+
frontmatter declares it (rung 2), or the invocation was `process-step` (rung 3)
|
|
163
|
+
→ legacy commit-step scan only: lines matching `commit:` / `git commit` /
|
|
164
|
+
`Commit phase`. An ABSENT field no longer reaches this branch; that is the whole
|
|
165
|
+
change in § 3a.
|
|
119
166
|
|
|
120
167
|
- **No commit steps** → nothing to ask. Never commit, never re-ask
|
|
121
168
|
per [`commit-policy`](../../rules/commit-policy.md).
|
|
@@ -31,6 +31,48 @@ orchestrator synthesises and re-verifies.
|
|
|
31
31
|
chars (~3k tokens against a measured ~251k spawn floor). Constants + checks:
|
|
32
32
|
`src/scripts/_lib/subagent_response.ts`.
|
|
33
33
|
|
|
34
|
+
## Durable copy — the envelope on disk before the message
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
THE FINAL MESSAGE IS A SINGLE TEXT-ONLY ENVELOPE. NEVER END ON A TOOL CALL.
|
|
38
|
+
THE SAME ENVELOPE IS WRITTEN TO THE RUNTIME ARTIFACT DIR BEFORE IT IS EMITTED.
|
|
39
|
+
DISK IS THE DURABLE CHANNEL. THE MESSAGE IS THE FAST CHANNEL.
|
|
40
|
+
A RETURN THAT WAS PAID FOR AND NEVER DELIVERED IS THE FAILURE THIS PREVENTS.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The envelope reaches the orchestrator twice, and the two copies are not two
|
|
44
|
+
result shapes:
|
|
45
|
+
|
|
46
|
+
- **The message** — the worker's final assistant message, text only, carrying
|
|
47
|
+
the envelope verbatim. Fast, and the channel that can vanish.
|
|
48
|
+
- **The file** — the same envelope written into the runtime artifact dir
|
|
49
|
+
(gitignored) as `response-envelope.json` *before* the final message is
|
|
50
|
+
emitted, so it exists even when the message never arrives.
|
|
51
|
+
|
|
52
|
+
This does not weaken *the envelope is the ONLY return channel* above. That
|
|
53
|
+
clause governs what the orchestrator may **ingest** — one envelope shape, never
|
|
54
|
+
a wholesale transcript. The disk copy carries that same shape, so the
|
|
55
|
+
orchestrator still reads exactly one; what changes is that it can still read it
|
|
56
|
+
after a delivery failure.
|
|
57
|
+
|
|
58
|
+
**Why the ordering is load-bearing.** A subagent whose last block is a
|
|
59
|
+
`tool_use` delivers nothing to its parent on host 2.1.229 — measured with a
|
|
60
|
+
matched control dispatched in the same turn: `(no output)` after 3 tool uses and
|
|
61
|
+
18,242 tokens, against a control ending on assistant text that returned the
|
|
62
|
+
complete report
|
|
63
|
+
([`subagent-lifecycle-phase0-return-channel.md`](../../../../agents/evidence/investigations/subagent-lifecycle-phase0-return-channel.md)
|
|
64
|
+
§ F1). The tokens were spent either way. Writing the envelope first is what
|
|
65
|
+
turns a dropped message into a recoverable read instead of a paid-for discard.
|
|
66
|
+
|
|
67
|
+
**Honest status — a convention, not a checked invariant.** Nothing in the tree
|
|
68
|
+
writes, reads, or validates `response-envelope.json`: the filename is fixed here
|
|
69
|
+
so that a durable channel is *findable* rather than nominal, and the clause
|
|
70
|
+
travels in the dispatch prompt (spawn contract rule (f)), which is where a
|
|
71
|
+
worker actually reads its duties. A `subagent_stop` concern that finds the file
|
|
72
|
+
and injects its path when the message is empty is planned and **not shipped** —
|
|
73
|
+
said plainly, because "the durable channel" must not be read as a recovery
|
|
74
|
+
mechanism that already runs.
|
|
75
|
+
|
|
34
76
|
## Budget-hit partial result
|
|
35
77
|
|
|
36
78
|
When the worker's `max_tokens_per_worker` stop-loss fires
|