@event4u/agent-config 13.0.0 → 14.0.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 (118) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +160 -333
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/evals/roadmap.json +8 -0
  5. package/dist/agent-src/commands/fix/ci.md +39 -1
  6. package/dist/agent-src/commands/pr/create.md +65 -4
  7. package/dist/agent-src/commands/roadmap/next.md +28 -5
  8. package/dist/agent-src/commands/work.md +16 -0
  9. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +47 -0
  10. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +94 -0
  11. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +30 -0
  12. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +21 -8
  13. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +55 -8
  14. package/dist/agent-src/contexts/execution/subagent-response-contract.md +42 -0
  15. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +29 -0
  16. package/dist/agent-src/rules/command-suggestion-policy.md +33 -0
  17. package/dist/agent-src/rules/design-review-after-ui-write.md +25 -8
  18. package/dist/agent-src/rules/ui-audit-gate.md +25 -8
  19. package/dist/agent-src/scripts/gate_execute.ts +395 -0
  20. package/dist/agent-src/scripts/resume_probe.ts +422 -0
  21. package/dist/agent-src/scripts/roadmap_gates.ts +138 -4
  22. package/dist/agent-src/scripts/update_roadmap_progress.ts +53 -2
  23. package/dist/agent-src/skills/ai-council/SKILL.md +61 -0
  24. package/dist/agent-src/skills/experiment-loop/SKILL.md +116 -0
  25. package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +27 -0
  26. package/dist/agent-src/skills/experiment-loop/evals/triggers.json +17 -0
  27. package/dist/agent-src/skills/experiment-loop/references/pivot-ladder.md +54 -0
  28. package/dist/agent-src/skills/experiment-loop/references/protocol.md +61 -0
  29. package/dist/agent-src/skills/experiment-loop/references/register-format.md +66 -0
  30. package/dist/agent-src/skills/roadmap-management/SKILL.md +2 -2
  31. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  32. package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +8 -3
  33. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  34. package/dist/agent-src/templates/roadmaps.md +43 -3
  35. package/dist/cli/registry.js +1 -0
  36. package/dist/cli/registry.js.map +1 -1
  37. package/dist/cli-delegate/{chunk-N7FEST6D.js → chunk-7PZ4FSZB.js} +351 -174
  38. package/dist/cli-delegate/{chunk-3B72LSZL.js → chunk-F3YUF7SA.js} +1 -1
  39. package/dist/cli-delegate/cmd_conformance.js +224 -104
  40. package/dist/cli-delegate/cmd_doctor.js +2 -2
  41. package/dist/cli-delegate/cmd_handoff.js +1 -1
  42. package/dist/discovery/deprecation-report.md +1 -1
  43. package/dist/discovery/discovery-manifest.json +40 -18
  44. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  45. package/dist/discovery/discovery-manifest.summary.md +3 -3
  46. package/dist/discovery/dormancy-report.md +1 -1
  47. package/dist/discovery/orphan-report.md +1 -1
  48. package/dist/discovery/packs.json +6 -5
  49. package/dist/discovery/trust-report.md +2 -2
  50. package/dist/discovery/workspaces.json +5 -4
  51. package/dist/hooks/dispatch.js +2018 -1320
  52. package/dist/mcp/registry-manifest.json +3 -3
  53. package/dist/mcp/server.json +2 -2
  54. package/dist/mcp/server.mjs +1652 -892
  55. package/dist/router.json +1 -1
  56. package/dist/scripts/condense.js +1 -1
  57. package/dist/scripts/condense.js.map +1 -1
  58. package/dist/ui/assets/{index-B0aMJnuz.js → index-C1pBRm1f.js} +2 -2
  59. package/dist/ui/assets/index-C1pBRm1f.js.map +1 -0
  60. package/dist/ui/index.html +1 -1
  61. package/package.json +1 -1
  62. package/src/agent-src/scripts/gate_execute.ts +395 -0
  63. package/src/agent-src/scripts/resume_probe.ts +422 -0
  64. package/src/agent-src/scripts/roadmap_gates.ts +138 -4
  65. package/src/agent-src/scripts/update_roadmap_progress.ts +53 -2
  66. package/src/config/ci-local-parity.yml +13 -0
  67. package/src/config/evaluator-budgets.json +4 -4
  68. package/src/config/gate-coverage.yml +111 -5
  69. package/src/config/gate-violation-baselines.json +2 -2
  70. package/src/config/rule-activation-census.json +41 -0
  71. package/src/config/rule-stub-ceilings.json +52 -0
  72. package/src/scripts/_dispatch.bash +4 -0
  73. package/src/scripts/_lib/evaluator_contract.ts +159 -0
  74. package/src/scripts/_lib/gh_transient.ts +80 -0
  75. package/src/scripts/_lib/release_material.ts +16 -5
  76. package/src/scripts/_lib/review_independence.ts +111 -0
  77. package/src/scripts/_lib/session_register.ts +14 -0
  78. package/src/scripts/_lib/skill_catalogue.ts +20 -0
  79. package/src/scripts/_lib/skill_catalogue_series.ts +411 -0
  80. package/src/scripts/_lib/turn_end_refusals.ts +482 -0
  81. package/src/scripts/ai_council/_py_json.ts +96 -0
  82. package/src/scripts/ai_council/cli_call_budget.ts +357 -0
  83. package/src/scripts/ai_council/clients.ts +80 -143
  84. package/src/scripts/ai_council/config.ts +25 -11
  85. package/src/scripts/ai_council/probe_store.ts +196 -0
  86. package/src/scripts/ai_council/qualification.ts +425 -0
  87. package/src/scripts/ai_council/qualification_wiring.ts +243 -0
  88. package/src/scripts/ai_council/quorum_wiring.ts +211 -0
  89. package/src/scripts/ai_team/team_dispatch.ts +40 -6
  90. package/src/scripts/capture_skill_catalogue.ts +264 -4
  91. package/src/scripts/check_evaluator_schema.ts +249 -0
  92. package/src/scripts/check_pr_ci_current.ts +409 -0
  93. package/src/scripts/check_review_schema.ts +195 -0
  94. package/src/scripts/check_rule_activation_census.ts +451 -0
  95. package/src/scripts/check_rule_stub_ceiling.ts +1128 -0
  96. package/src/scripts/condense.ts +1 -1
  97. package/src/scripts/council_cli.ts +141 -191
  98. package/src/scripts/dispatch_r2_reviewer.ts +8 -1
  99. package/src/scripts/hook_manifest.yaml +72 -5
  100. package/src/scripts/hooks/concern_registry.ts +4 -0
  101. package/src/scripts/hooks/dispatch_hook.ts +43 -1
  102. package/src/scripts/hooks/interruption_ledger_hook.ts +256 -0
  103. package/src/scripts/hooks/ship_diff_volume_hook.ts +180 -0
  104. package/src/scripts/hooks/turn_end_gate_hook.ts +119 -26
  105. package/src/scripts/hooks_doctor.ts +112 -0
  106. package/src/scripts/interruption_report.ts +443 -0
  107. package/src/scripts/lint_evidence_artifacts.ts +359 -0
  108. package/src/scripts/lint_roadmap_blockers.ts +65 -0
  109. package/src/scripts/lint_roadmap_complexity.ts +7 -1
  110. package/src/scripts/release.ts +38 -53
  111. package/src/scripts/rule_activation_census.ts +292 -0
  112. package/src/scripts/schemas/evaluator-output.schema.json +60 -0
  113. package/src/scripts/schemas/review-findings.schema.json +31 -0
  114. package/src/scripts/self_review_gate.ts +6 -0
  115. package/src/scripts/session_register_hook.ts +30 -1
  116. package/src/scripts/sync_pr_branch.ts +271 -0
  117. package/src/scripts/test_council_qualification.ts +213 -0
  118. package/dist/ui/assets/index-B0aMJnuz.js.map +0 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Smoke](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml/badge.svg)](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml) [![Public install smoke (3 OS × 2 Node)](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml/badge.svg)](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml) [![npm](https://img.shields.io/npm/v/@event4u/agent-config?style=flat-square&label=npm&color=orange)](https://www.npmjs.com/package/@event4u/agent-config) [![agent-config MCP server](https://glama.ai/mcp/servers/event4u-app/agent-config/badges/score.svg)](https://glama.ai/mcp/servers/event4u-app/agent-config) [![MCP Toplist](https://mcptoplist.com/badge/glama%2Fevent4u-app%2Fagent-config.svg)](https://mcptoplist.com/server/glama%2Fevent4u-app%2Fagent-config)
6
6
 
7
- [![Skills](https://img.shields.io/badge/Skills-289-orange?style=flat-square)](dist/agent-src/skills/) [![Rules](https://img.shields.io/badge/Rules-117-orange?style=flat-square)](dist/agent-src/rules/) [![Commands](https://img.shields.io/badge/Commands-200-orange?style=flat-square)](dist/agent-src/commands/) [![Guidelines](https://img.shields.io/badge/Guidelines-106-orange?style=flat-square)](docs/guidelines/) [![Personas](https://img.shields.io/badge/Personas-29-orange?style=flat-square)](dist/agent-src/personas/) [![Advisors](https://img.shields.io/badge/Advisors-5-orange?style=flat-square)](dist/agent-src/personas/advisors/)
7
+ [![Skills](https://img.shields.io/badge/Skills-290-orange?style=flat-square)](dist/agent-src/skills/) [![Rules](https://img.shields.io/badge/Rules-117-orange?style=flat-square)](dist/agent-src/rules/) [![Commands](https://img.shields.io/badge/Commands-200-orange?style=flat-square)](dist/agent-src/commands/) [![Guidelines](https://img.shields.io/badge/Guidelines-106-orange?style=flat-square)](docs/guidelines/) [![Personas](https://img.shields.io/badge/Personas-29-orange?style=flat-square)](dist/agent-src/personas/) [![Advisors](https://img.shields.io/badge/Advisors-5-orange?style=flat-square)](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
- - **Do NOT commit or push.** Only apply local fixes.
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.** `git push` is a Hard Floor
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)). Fix in the working tree and
437
- push only under a fresh or still-standing instruction. A CI-fix loop that
438
- re-pushes on its own authority is not on the table.
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. THE RE-PUSH IS NOT.
240
- git push IS A HARD-FLOOR TRIGGER AND THE FLOOR REFUSES A STANDING
241
- DIRECTIVE BY CONSTRUCTION. FIX, VERIFY, THEN SAY WHAT IS READY.
242
- NEVER INVENT A PER-PR "STANDING MANDATE" WORKAROUND.
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
- resolved roadmap declares `execution.mode` in frontmatter
5
- (`autonomous` | `phase-checkpoints`; absent / `interactive` = legacy
6
- behavior, this context stays unloaded). Defines the run-start pre-scan,
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> → resolved via AI council (<members | "none
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** (frontmatter `execution.mode`; absent = 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
- Read `execution.mode` from the roadmap's frontmatter
95
- (`autonomous` | `phase-checkpoints` | `interactive`; absent =
96
- `interactive`).
97
-
98
- **`mode: autonomous` or `phase-checkpoints`** → load
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
- **`mode: interactive` (or field absent)** → legacy commit-step scan
118
- only: lines matching `commit:` / `git commit` / `Commit phase`.
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