@event4u/agent-config 14.4.0 → 14.6.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 (48) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +132 -291
  3. package/dist/agent-src/commands/analyze/decision.md +7 -0
  4. package/dist/agent-src/commands/optimize/project.md +10 -0
  5. package/dist/agent-src/commands/roadmap/process-full.md +45 -3
  6. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +130 -1
  7. package/dist/agent-src/rules/decision-revisit-gate.md +108 -7
  8. package/dist/agent-src/skills/adr-create/SKILL.md +25 -3
  9. package/dist/agent-src/skills/decision-review/SKILL.md +18 -0
  10. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  11. package/dist/cli-delegate/{chunk-ZPSXJTLI.js → chunk-P6LQDIWK.js} +15 -1
  12. package/dist/cli-delegate/cmd_conformance.js +1 -1
  13. package/dist/cli-delegate/cmd_handoff.js +1 -1
  14. package/dist/cli-delegate/cmd_session_recycle.js +1 -1
  15. package/dist/discovery/deprecation-report.md +1 -1
  16. package/dist/discovery/discovery-manifest.json +8 -8
  17. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  18. package/dist/discovery/discovery-manifest.summary.md +1 -1
  19. package/dist/discovery/dormancy-report.md +1 -1
  20. package/dist/discovery/orphan-report.md +1 -1
  21. package/dist/discovery/packs.json +2 -2
  22. package/dist/discovery/trust-report.md +1 -1
  23. package/dist/discovery/workspaces.json +2 -2
  24. package/dist/hooks/dispatch.js +419 -94
  25. package/dist/mcp/registry-manifest.json +2 -2
  26. package/dist/mcp/server.json +2 -2
  27. package/dist/router.json +1 -1
  28. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +49 -0
  29. package/package.json +1 -1
  30. package/src/config/estate-count-budget.json +36 -1
  31. package/src/config/pack-size-budget.json +3 -2
  32. package/src/scripts/_lib/layer_overlap_notice.ts +85 -0
  33. package/src/scripts/_lib/scope_guard.sh +62 -3
  34. package/src/scripts/_lib/subagent_capsule.ts +81 -1
  35. package/src/scripts/adr/regenerate_index.ts +13 -2
  36. package/src/scripts/adr_cite_check.ts +424 -0
  37. package/src/scripts/bench_hook_injection.ts +18 -1
  38. package/src/scripts/check_adr_frontmatter.ts +187 -1
  39. package/src/scripts/check_single_delivery.ts +473 -0
  40. package/src/scripts/hooks/host_semantics.ts +28 -0
  41. package/src/scripts/hooks/injection_budget.ts +152 -16
  42. package/src/scripts/hooks/run_continuation_hook.ts +918 -46
  43. package/src/scripts/install.sh +12 -2
  44. package/src/scripts/memory_consolidation.ts +189 -0
  45. package/src/scripts/memory_eviction.ts +384 -0
  46. package/src/scripts/report_layer_overlap.ts +72 -0
  47. package/src/scripts/report_memory_pointers.ts +622 -0
  48. package/src/scripts/session_register_hook.ts +144 -21
@@ -93,6 +93,13 @@ suggest deferring or strengthening evidence before proposing.
93
93
  ### Rules
94
94
 
95
95
  - Do NOT commit, push, or open a PR.
96
+ - Do NOT report an ADR as still binding without evaluating it first —
97
+ `./scripts-run src/scripts/adr_cite_check <ADR-NNN>` resolves status,
98
+ `review_trigger` state, amendments, successors, and back-references in one
99
+ call. A `superseded` / `deprecated` ADR is not a live decision
100
+ to audit, and an amended one is not the text its body's top half claims.
101
+ (`rejected` is NOT in that set — on an ADR it records a rejected *proposal*,
102
+ so the rejection is the live decision.)
96
103
  - Do NOT auto-promote — `/memory propose` is the intake.
97
104
  - Do NOT re-litigate a decision confirmed still valid — acknowledge it,
98
105
  note the validation date, stop.
@@ -166,6 +166,16 @@ Hard rules for this step:
166
166
  and its recorded revisit-conditions first; if it truly blocks, the
167
167
  only flip path offered is option 3 (council re-eval) — "Flip" is not
168
168
  offered for locks.
169
+ - **An ADR lock is evaluated before it is reported.** When the lock is a
170
+ numbered ADR, the FIRST action is
171
+ `./scripts-run src/scripts/adr_cite_check <ADR-NNN>` — not "report the
172
+ lock". A `superseded` / `deprecated` status means there is no
173
+ live lock to route at all, and an amended ADR means the cited text may not
174
+ be the operative one. `rejected` stays live — it records a rejected
175
+ *proposal*, so reopening it means showing the premise it rejected on has
176
+ changed. Reporting an unevaluated ADR as a blocker is the
177
+ ordering defect `decision-revisit-gate` exists over: it costs the owner a
178
+ turn to discover what one command answers.
169
179
  - **Session budget:** at most 5 interview questions by default
170
180
  (`--max-questions=N` to override). Budget exhausted → remaining
171
181
  candidates go to Step 4 as "further candidates".
@@ -46,10 +46,15 @@ with the **scope delta below**.
46
46
  - **Working set:** every open step across every phase, in document
47
47
  order. Phase-internal annotations like `(deferred)` / `(optional)` /
48
48
  "gated on Phase N" do not narrow the working set.
49
- - **Stop after:** the entire roadmap reaches `count_open == 0`, or a
50
- halt condition fires (Hard-Floor, council-off + ambiguity — the
51
- latter only outside an accepted contract with council available,
49
+ - **Stop after:** the entire roadmap reaches `count_open == 0`
50
+ (`complete`), or the runnable set is empty with steps still open
51
+ (`blocked` — see the terminal-outcomes section below), or a halt
52
+ condition fires (Hard-Floor, council-off + ambiguity — the latter only
53
+ outside an accepted contract with council available,
52
54
  security-sensitive, scope-out-of-roadmap, test/quality red).
55
+ - **Do not start** when NO open step is runnable: that is
56
+ `blocked-preflight`, and it creates no branch and takes no grant. The
57
+ runnable test is § 3c of the loop.
53
58
  - **Phase boundary handling:** at every phase boundary, run the
54
59
  per-phase quality pipeline when `quality_cadence: per_phase` (or
55
60
  `per_step`) AND `quality.local_auto_run: true` — under the default
@@ -91,6 +96,8 @@ FORBIDDEN NON-HALT REASONS — NEVER STOP THE RUN FOR ANY OF THESE:
91
96
  · "avoid a PR pile-up" / "let the open PRs merge first"
92
97
  · "this phase is large / touches a deep subsystem"
93
98
  · "phase-checkpoints mode, so I'll checkpoint and wait"
99
+ · "this step looks human-gated" — `blocked` is reached by the § 3c
100
+ runnable test over PRE-EXISTING blockers, never by how a step feels
94
101
  · any agent-invented caution not in the five halt conditions above.
95
102
  INVENTING A HALT REASON IS A VIOLATION OF THE COMMAND AND THE USER'S WILL.
96
103
  IF CONTEXT RUNS OUT MID-RUN, KEEP LANDING COMPLETE STEPS UNTIL IT DOES —
@@ -110,6 +117,41 @@ roadmap carries such phrasing — whether by legacy or by an opt-in
110
117
  setting — treat it as ordinary prose during execution, never as a
111
118
  gate. Phase ordering and explicit dependency gates govern the loop.
112
119
 
120
+ ## Terminal outcomes — and why `blocked` is not a sixth halt
121
+
122
+ The five halt conditions answer *"what interrupts runnable work"*. They never
123
+ answered *"what does the run report when no runnable work is left and the roadmap
124
+ is not finished"*, and the omission was not academic: measured 2026-08-19 across
125
+ the twelve most nearly complete roadmaps in the estate, **zero** could reach
126
+ `count_open == 0` in one PR — every remaining open step needed a human action, a
127
+ repo-admin setting, a paid authorisation, an absent binary, or an elapsed soak
128
+ window. Under the contract as written, such a roadmap had no legal stopping point,
129
+ so the command could be neither obeyed nor honestly declined.
130
+
131
+ | Outcome | When | Success? |
132
+ |---|---|---|
133
+ | `complete` | `count_open == 0` | yes — archival check runs |
134
+ | `blocked` | `count_open > 0` and no open step is runnable per § 3c | **no** — partial progress, labelled as such |
135
+ | `blocked-preflight` | no open step was runnable before the run started | **no** — nothing was attempted; no branch |
136
+ | a halt | one of the five conditions fired | **no** — the halt is reported |
137
+
138
+ ```
139
+ `blocked` IS NEVER REPORTED AS COMPLETION. count_open STAYS > 0.
140
+ NEVER FLIP A BOX TO [~] TO REACH IT — THAT LAUNDERS OPEN WORK THROUGH A GLYPH.
141
+ A PR OPENED ON A BLOCKED RUN SAYS PARTIAL PROGRESS IN ITS FIRST LINE.
142
+ REVALIDATE THE RUNNABLE SET BEFORE REPORTING IT. ONE RUNNABLE STEP REJECTS THE CLAIM.
143
+ ```
144
+
145
+ **It is a terminal outcome, not a halt, and the distinction is the safety
146
+ property.** The Iron Law above and its forbidden list hold their full authority
147
+ over mid-run stopping: an agent that may not stop for "this phase is large" may
148
+ equally not stop for "this step looks human-gated". Runnability is decided by the
149
+ § 3c test over blockers that **pre-date the run** — a citation the run wrote
150
+ itself buys nothing. AI council 2026-08-19, 2/2 convergent on exactly this
151
+ separation.
152
+
153
+ Recorded in [`ADR-235`](../../../../docs/decisions/ADR-235-process-full-blocked-terminal-outcome.md).
154
+
113
155
  ## Iron Law — Real-time dashboard
114
156
 
115
157
  ```
@@ -180,6 +180,83 @@ change in § 3a.
180
180
  `commit-policy` § NEVER ask about committing holds regardless of
181
181
  autonomy).
182
182
 
183
+ ### 3c. Runnable-work precondition — refuse a run with nothing to do
184
+
185
+ ```
186
+ A RUN WITH NO RUNNABLE OPEN STEP DOES NOT START.
187
+ NAME THE BLOCKERS. CREATE NO BRANCH. WRITE NOTHING.
188
+ THIS IS A PRECONDITION, NEVER A HALT — IT CANNOT FIRE MID-RUN.
189
+ ```
190
+
191
+ Run once, at the end of the pre-scan, before any grant is exercised.
192
+
193
+ **Runnable** is decided from the roadmap's own `## Blockers` section and nothing
194
+ else. An open step is **not** runnable when a blocker satisfies all four:
195
+
196
+ 1. it exists in `## Blockers` **before this run started** — a blocker the run
197
+ itself authored does not count (see the gaming note below);
198
+ 2. its `Class:` is `2` (consent-once) or `3` (human-only) — classes `0` and `1`
199
+ are agent-runnable by construction and carry a `Run:` the agent executes,
200
+ per [`templates/roadmaps.md`](../../templates/roadmaps.md);
201
+ 3. its `Blocks:` field names this step, by phase-and-step identifier or by a
202
+ phase whose scope contains it;
203
+ 4. it names what would clear it.
204
+
205
+ Every other open step is runnable. **No blocker citation → runnable**, and the
206
+ default direction is deliberate: the failure this precondition must not have is
207
+ refusing work an agent could have done.
208
+
209
+ - **At least one runnable open step** → the run proceeds. It does *not* matter
210
+ how many steps are blocked; the blocked ones are skipped in place (never
211
+ flipped — see the terminal-outcomes section), and the run works the rest.
212
+ - **Zero runnable open steps** → `blocked-preflight`. Report the roadmap, the
213
+ open-step count, and each blocker with its class and its clearing action.
214
+ Create no branch, write no state, take no grant.
215
+
216
+ **A step this precondition judges non-runnable carries a `blocked-by:` marker on
217
+ its own line.** The obligation is here because two mechanisms read blockedness
218
+ from two different places and only one of them reads this section: `run-continuation`,
219
+ the stop-slot concern that re-engages an autonomous run, decides open-vs-blocked
220
+ from the inline `<!-- blocked-by: <id> -->` marker and never parses `## Blockers`
221
+ at all. Without the marker a step that IS blocked per the four conditions above
222
+ still counts as open work to the concern, which re-engages the agent into it every
223
+ stop fire until the stall rung fires — the mechanism whose job is to detect a
224
+ stall manufacturing one, which is the failure shape this file already records once
225
+ for the roadmap-root split.
226
+
227
+ Round 8 finding 7 caught the two predicates as disjoint. The fix is this coupling
228
+ sentence rather than teaching the concern to parse `## Blockers`: a second
229
+ implementation of the four conditions is a second thing to keep in step, and the
230
+ one-line marker is checkable by eye at the step it belongs to. **The residual is
231
+ real and is not papered over:** nothing enforces the pairing, so a `## Blockers`
232
+ entry authored without its marker is caught by review or not at all.
233
+
234
+ **Why a precondition and not a sixth halt.** The five halt conditions interrupt
235
+ work that is still runnable; this decides whether any runnable work exists at
236
+ all. Keeping them structurally separate is what preserves the forbidden-list's
237
+ authority over mid-run stopping — an agent that may not stop for "this phase is
238
+ large" also may not stop for "this feels human-gated". AI council 2026-08-19,
239
+ 2/2 convergent, explicitly on this point: *"keep this structurally separate from
240
+ 'five, and only five': the five are exceptional halts; `blocked` is an
241
+ exhaustion-of-runnable-work terminal outcome."*
242
+
243
+ **The gaming vector, named because it is the one thing that would make this
244
+ worse than the gap it closes.** An agent meets a hard step, writes a `## Blockers`
245
+ entry claiming Class 3, cites it, and stops — a comfort-stop wearing a citation.
246
+ Condition 1 is the whole defence: a blocker must pre-date the run, which is
247
+ checkable from git rather than from the agent's word. A blocker discovered
248
+ mid-run is recorded (that is honest and useful) and does **not** make the step
249
+ non-runnable in this run.
250
+
251
+ **One imprecision, recorded rather than smoothed over.** The class taxonomy has
252
+ four rows and none of them says *"waiting on time"* or *"waiting on another
253
+ roadmap"*. A soak window and a cross-roadmap dependency are authored as `3`
254
+ today, because absence of `Class:` already means `3` — so they are decidable but
255
+ mislabelled as human-only. A fifth class is a taxonomy change with a linter
256
+ behind it (`lint_roadmap_blockers`) and is not made here.
257
+ *Revisit-if:* a run is refused on a blocker whose real content is "wait", and
258
+ the report reads wrong to the person holding it.
259
+
183
260
  ## 4. Resolve cadences — read once, cache for the run
184
261
 
185
262
  Read both keys from `.agent-settings.yml` once and cache for the whole
@@ -430,6 +507,52 @@ artifact drafting, council enablement), not safety.
430
507
 
431
508
  On halt: stop, surface state, do **not** auto-fix outside the failing step.
432
509
 
510
+ ### Terminal outcomes — `complete`, `blocked`, or a halt
511
+
512
+ The halt list above answers *"what interrupts runnable work"*. It does not answer
513
+ *"what does the run report when there is no runnable work left and the roadmap is
514
+ not finished"*, and until this section there was no answer: the wrapper's stop
515
+ condition was `count_open == 0` or a halt, so a roadmap whose remaining steps all
516
+ need a human had **no legal stopping point**.
517
+
518
+ That is not a hypothetical. Measured 2026-08-19 across the twelve most nearly
519
+ complete roadmaps in the estate: **zero** could reach `count_open == 0` in one
520
+ PR. Every remaining open step needed a human action — flip branch protection,
521
+ delete committed evidence, authorise paid spend, install an absent binary, wait
522
+ out a soak window, use the maintainer's own machine, or edit a file an armed host
523
+ hook denies.
524
+
525
+ Three outcomes, and only one of them is success:
526
+
527
+ | Outcome | When | What it reports |
528
+ |---|---|---|
529
+ | `complete` | `count_open == 0` | the roadmap is finished; archival check runs (§ 6) |
530
+ | `blocked` | `count_open > 0` **and** no open step is runnable | the work that DID close, plus every blocker with its clearing action |
531
+ | a halt | one of the five conditions above fired | the halt, its evidence, and what remains |
532
+
533
+ ```
534
+ `blocked` IS NEVER PRESENTED AS COMPLETION.
535
+ count_open STAYS > 0. NO CHECKBOX IS FLIPPED TO [~] TO REACH IT.
536
+ A PR OPENED ON A BLOCKED RUN IS LABELLED PARTIAL PROGRESS.
537
+ REVALIDATE IMMEDIATELY BEFORE REPORTING IT — ONE RUNNABLE STEP LEFT REJECTS THE CLAIM.
538
+ ```
539
+
540
+ The `[~]` prohibition is load-bearing and was the one point the council split on.
541
+ Deferring a blocked step to `[~]` would let the run reach `count_open == 0` and
542
+ report completion — laundering unfinished work through a glyph, which is exactly
543
+ what Iron Law 3 of [`roadmap-progress-sync`](../../rules/roadmap-progress-sync.md)
544
+ exists to catch on the archival side. So the boxes stay open and the outcome
545
+ carries the truth instead.
546
+
547
+ Revalidation is the second half of the same discipline: the runnable set is
548
+ recomputed at the moment of reporting, because steps unblock during a run (a
549
+ prerequisite closes, a `Run:` succeeds, a peer merges). If any open step is
550
+ runnable, `blocked` is refused and the loop continues.
551
+
552
+ **Runnability is decided by the § 3c test**, unchanged — the same four conditions,
553
+ including that a qualifying blocker must pre-date the run. A blocker the run
554
+ authored is recorded and does not make a step non-runnable in that run.
555
+
433
556
  ### Forbidden non-halt reasons — agent-invented cautions
434
557
 
435
558
  The halt list above is **exhaustive**. An agent running `process-full` (or any
@@ -446,9 +569,15 @@ a violation of the command and the user's will:
446
569
  a phase boundary emits a non-blocking status line and the run **continues**;
447
570
  the stop-and-wait reading of `phase-checkpoints` applies only to
448
571
  `process-phase`.
572
+ - **"this step looks human-gated"** — the `blocked` outcome above is reached by
573
+ the § 3c test over blockers that pre-date the run, never by a judgement about
574
+ how a step feels. A step with no qualifying blocker citation is runnable, and
575
+ writing the citation yourself does not make it one. This entry exists because
576
+ the terminal outcome is the single most abusable thing on this page.
449
577
 
450
578
  If the work genuinely cannot continue, it will be because one of the five real
451
- halt conditions fired — surface THAT, not a manufactured caution.
579
+ halt conditions fired, or because the runnable set is empty by the § 3c test —
580
+ surface THAT, with the blockers named, not a manufactured caution.
452
581
 
453
582
  ### Non-halt — gating notes, "optional" tags
454
583
 
@@ -10,8 +10,14 @@ triggers:
10
10
  - keyword: "already decided"
11
11
  - keyword: "locked decision"
12
12
  - keyword: "budget blocks"
13
+ - keyword: "adr-"
14
+ - keyword: "adrs"
15
+ - keyword: "superseded"
16
+ - keyword: "review_trigger"
17
+ - phrase: "the adr"
13
18
  routes_to:
14
- - "skill:decision-review"
19
+ - "skill:ai-council"
20
+ - "skill:decision-record"
15
21
  workspaces: [agent-config-maintainer, engineering]
16
22
  packs: [meta]
17
23
  collision_ok:
@@ -28,24 +34,99 @@ obligation_frequency: "per-task"
28
34
  A LOCK IS A DECISION UNDER PAST CONDITIONS, NOT A PERMANENT LAW.
29
35
  BENEFIT BLOCKED BY A LOCK → SURFACE + OFFER RE-EVALUATION.
30
36
  NEVER SILENT COMPLIANCE. NEVER SILENT DROP OF A GOOD CHANGE.
37
+ RE-EVALUATION GOES TO THE COUNCIL FIRST, NOT TO THE USER FIRST.
38
+ THE USER IS REACHED FOR THE RESERVED SET — AND ALWAYS FOR IT.
39
+ NEVER CITE A LOCK YOU HAVE NOT EVALUATED THIS TURN.
31
40
  ```
32
41
 
33
42
  An agent that finds a genuinely beneficial change blocked by a recorded
34
43
  past decision — an honest-null eval verdict, a "don't relitigate"
35
44
  memory or context note, a token-frugality/budget canon line, or an ADR —
36
- does not quietly comply and drop the change. It surfaces the conflict
37
- and offers the user a path to re-evaluate the lock. Progress means
38
- adaptation: locks encode what was true when they were written, not a
39
- ceiling on what the package may ever become.
45
+ does not quietly comply and drop the change. It surfaces the conflict and
46
+ re-evaluates the lock — **in the council by default**, reaching the user only
47
+ for the reserved set below. Progress means adaptation: locks encode what was
48
+ true when they were written, not a ceiling on what the package may ever become.
49
+
50
+ **The default venue is the council, and this is a correction, not a new
51
+ policy.** [`ai-council`](../skills/ai-council/SKILL.md) has said since its own
52
+ Iron Law that *"a design decision the agent cannot settle from the tree goes to
53
+ the council first, not to the user first"*, and its class table already lists
54
+ "reopening a recorded decision". This rule used to say "offers the user a path",
55
+ which contradicted that and made every lock an owner interrupt. The measured
56
+ cost of the contradiction: across 26 days of transcripts, the agent reported a
57
+ lock and waited, and the owner had to void the decision retroactively before the
58
+ work resumed — in the two clearest cases the lock report is timestamped **before**
59
+ the override demand. The ordering was the defect; the permission was never
60
+ missing.
40
61
 
41
62
  **Mechanism-match check comes FIRST**: a verdict settles the *mechanism it
42
63
  tested*, not every future proposal that resembles it — if the blocked change
43
64
  is a different mechanism, the lock does not apply; proceed, noting the
44
65
  distinction.
45
66
 
46
- Body migrated to [`skill:decision-review` § Decision-revisit gate — mechanics](../skills/decision-review/SKILL.md) (per P4 of `road-to-kernel-and-router.md`) — what-counts-as-a-lock catalog (honest nulls, don't-relitigate notes, budget-canon lines, ADRs, hard structural caps), the five fire steps, when-NOT-to-fire, failure modes.
67
+ ## The five steps, carried here — the depth is elsewhere, the obligation is not
68
+
69
+ 1. **Mechanism-match** (above) — different mechanism, no lock, proceed.
70
+ 2. **Evaluate the lock before citing it.** An ADR may not be presented as a
71
+ reason not to act until its status, `review_trigger` state, amendments and
72
+ successors have been read. In this repository that is one command —
73
+ `./scripts-run src/scripts/adr_cite_check <ADR-NNN>`; elsewhere it is the
74
+ same four reads done by hand. A `superseded` / `deprecated` status means it is
75
+ not a live lock at all; a fired or indeterminate trigger means it is not an
76
+ **unqualified** one. `rejected` is NOT in the dead set — on an ADR it records
77
+ a rejected *proposal*, so the rejection binds until its premise is shown to
78
+ have changed.
79
+ 3. **Surface** the change, the lock, the condition it recorded, and what has
80
+ changed since.
81
+ 4. **Route it** — council by default (below), user only for the reserved set.
82
+ 5. **Record** the outcome with scope and `revisit-if`.
83
+
84
+ These five are the obligation and they are stated here rather than only behind
85
+ a route, because the route was measurably unreachable: `decision-revisit-gate`
86
+ lives in the always-on `meta` pack while `decision-review` ships
87
+ `install.default: false` in the non-default `analysis-workbench` pack, so a
88
+ pack-legal install received the obligation and not the procedure. `routes_to`
89
+ now names two always-on skills; the backward-audit depth in
90
+ [`decision-review`](../skills/decision-review/SKILL.md) stays optional, which is
91
+ the correct status for depth.
92
+
93
+ Full catalog (honest nulls, don't-relitigate notes, budget-canon lines, ADRs,
94
+ hard structural caps), the per-step detail, when-NOT-to-fire and the failure
95
+ modes remain in [`skill:decision-review` § Decision-revisit gate — mechanics](../skills/decision-review/SKILL.md).
47
96
  Trigger-set above activates this routing on demand, independent of the discipline profile (ADR-110).
48
97
 
98
+ ## Who decides — the owner-reserved set
99
+
100
+ The discriminator, in one question: **does the proposed transition weaken an
101
+ owner-reserved invariant, or create an undelegated external, irreversible, or
102
+ destructive commitment?** No, and reversible inside the authorised envelope →
103
+ the council decides. Yes, or not establishable from tree evidence → the owner.
104
+
105
+ The routing unit is the **transition**, never the document: the same ADR may be
106
+ strengthened by the council and weakened only by the owner.
107
+
108
+ | Reserved to the owner | Council-decidable |
109
+ |---|---|
110
+ | Changes the project's purpose or a declared non-negotiable outcome | Any mechanism serving that purpose |
111
+ | **Lowers or removes** a recorded security / privacy / safety / data-handling floor | Strengthening a floor, or an equivalent swap above it |
112
+ | Irreversible or materially destructive | Reversible within the envelope |
113
+ | Spend or liability **above** a delegated threshold | Budgeted, threshold-bounded spend |
114
+ | Creates / removes / weakens a legal, regulatory, contractual, licensing, compatibility, or public commitment | Internal-only commitments |
115
+ | Governance self-amendment — reopening authority, quorum, escalation, this set | What the rules already permit |
116
+ | Cannot be bounded from available evidence | Bounded, with the evidence cited |
117
+
118
+ Council split, abstention, or no quorum is an **escalation condition**, not a
119
+ class: that transition escalates, the ADR does not become owner-reserved
120
+ forever. Availability is `agent-config council:status`, never a project file
121
+ ([`council-availability`](council-availability.md)).
122
+
123
+ Field on the ADR: `reopen_policy: directional | owner | unclassified`, absent →
124
+ **`unclassified`**, which permits council investigation and reversible
125
+ experiments and gates only execution of a reserved transition. Absent is
126
+ deliberately not `owner`: with 146 accepted ADRs that default would encode
127
+ today's blockage into the new schema. Full contract, the reopen record, and the
128
+ precedent-creates-no-authority clause: [`adr-layout § Reopen authority`](../docs/contracts/adr-layout.md).
129
+
49
130
  ## See also
50
131
 
51
132
  - [`decision-review`](../skills/decision-review/SKILL.md) — the backward-audit
@@ -53,10 +134,30 @@ Trigger-set above activates this routing on demand, independent of the disciplin
53
134
  - [`ai-council`](../skills/ai-council/SKILL.md) — the re-evaluation mechanism;
54
135
  owns the convergence-summary scope + `revisit-if` contract.
55
136
  - [`decision-record`](../skills/decision-record/SKILL.md) — forward-flow decision
56
- locking; the escalation litmus there names the reopening condition up front.
137
+ locking; its **§ 4 Lock the choice + consequences** requires the `Revisit-if:`
138
+ line that names the reopening condition up front. (This pointer used to cite an
139
+ "escalation litmus" heading; `grep` over `src/` + `docs/` returns two hits and
140
+ neither is in that file — the heading never existed, so the pointer led
141
+ nowhere. Corrected to the section that carries the obligation.)
57
142
  - [`token-budget-discipline`](token-budget-discipline.md) — the frugality-canon
58
143
  value-over-budget escalation this rule's budget-lock case defers to.
59
144
  - [`no-cheap-questions`](no-cheap-questions.md) — the question-quality floor a
60
145
  revisit-offer must still clear.
61
146
  - [`ask-when-uncertain`](ask-when-uncertain.md) — the numbered-options shape
62
147
  used to present the revisit offer.
148
+
149
+ ## Honest enforcement — `enforced_by: none`
150
+
151
+ `adr_cite_check` is deterministic where it runs, and nothing makes it run. No
152
+ gate can observe an agent citing a decision it never opened, so step 2 above is
153
+ model-carried — the same honesty boundary
154
+ [`security-sensitive-stop`](security-sensitive-stop.md) and
155
+ [`active-remediation`](active-remediation.md) state for their own obligations.
156
+
157
+ Two reach limits, named rather than implied. The tool lives in this repository's
158
+ `src/scripts/` and is **not** exposed as an `agent-config` verb, so a consumer
159
+ install performs step 2 by hand; wiring the verb touches six further surfaces
160
+ plus the curated `dist/agent-src/scripts/` list and is deliberately out of this
161
+ change. And `docs/decisions/` is projected into no agent-visible tree at all —
162
+ the agent sees ADR *numbers* cited across rules and skills, almost never ADR
163
+ *text*. Until that changes, "evaluate before citing" means opening the file.
@@ -11,6 +11,8 @@ execution:
11
11
  command:
12
12
  - ./scripts-run
13
13
  - src/scripts/adr/regenerate_index
14
+ - --dir
15
+ - docs/decisions
14
16
  runtime_requires:
15
17
  bins:
16
18
  - bash
@@ -59,7 +61,10 @@ Do NOT use when:
59
61
  governance ADRs, 3-digit numbering (`ADR-NNN-<slug>.md`).
60
62
  - **Per-area** — `docs/adrs/<area>/`: sub-area ADRs, 4-digit
61
63
  numbering (`NNNN-<slug>.md`); `<area>` must match the canonical
62
- inventory in [`scripts/audit_adr_coverage.ts`](../../../scripts/audit_adr_coverage.ts).
64
+ inventory in `src/scripts/audit_adr_coverage.ts` (`AREAS`). Deliberately not
65
+ a link: this skill is projected into `dist/agent-src/skills/`, whose sibling
66
+ `scripts/` directory carries six curated files and not this one, so any
67
+ relative href that resolves in `src/` is broken in the projection.
63
68
  - The decision is **already made** — ADRs record outcomes, they do
64
69
  not run the decision process. For unresolved trade-offs, run the
65
70
  council or consult `adversarial-review` first.
@@ -80,7 +85,7 @@ Ask one question only if both are plausible:
80
85
  `NNNN-<slug>.md` (4-digit, no `ADR-` prefix).
81
86
  3. **Unknown area** — `<area>` not in the inventory: refuse with a
82
87
  hint to add the area to `AREAS` in
83
- `scripts/audit_adr_coverage.ts` in the same PR. Do not invent.
88
+ `src/scripts/audit_adr_coverage.ts` in the same PR. Do not invent.
84
89
  4. **In doubt** → per-area (cheaper to surface, easier to relocate).
85
90
 
86
91
  ### 2. Pick the next ADR number
@@ -134,8 +139,12 @@ date: YYYY-MM-DD
134
139
  decision: <slug>
135
140
  supersedes: — | ADR-MMM
136
141
  superseded_by: — | ADR-MMM
142
+ amends: — | ADR-MMM # optional — this ADR amends that one (reciprocal required)
143
+ amended_by: — | ADR-MMM # optional — reciprocal of `amends`
137
144
  phase: <roadmap> · <phase-id>
138
145
  review_trigger: <the CONDITION that would reopen this decision>
146
+ protected_dimensions: [...] # optional — purpose | security_floor | privacy_floor | external_commitment | governance | none
147
+ reopen_policy: directional | owner | unclassified # optional; absent → unclassified
139
148
  ---
140
149
 
141
150
  # ADR-NNN — <Decision Title>
@@ -204,7 +213,7 @@ completeness check — not on every ADR by default.
204
213
  - **Per-area numbering is 4-digit** (`NNNN-<slug>.md`); the flat
205
214
  surface stays 3-digit (`ADR-NNN-<slug>.md`). Do not mix.
206
215
  - **Area inventory is closed** — `<area>` must already exist in
207
- `AREAS` in `scripts/audit_adr_coverage.ts`. Adding a new area is
216
+ `AREAS` in `src/scripts/audit_adr_coverage.ts`. Adding a new area is
208
217
  a separate PR with explicit reviewer sign-off.
209
218
  - Frontmatter `adr:` (flat) is the canonical number; the filename
210
219
  prefix must match. The flat regenerator fails on mismatch.
@@ -214,6 +223,19 @@ completeness check — not on every ADR by default.
214
223
  to `superseded`.
215
224
  - Never delete an ADR file — supersede it. Deletion breaks
216
225
  historical links and round-trips through git history checks.
226
+ - **Amending is the common case; wire it in both directions.** Most reopens
227
+ correct one decision inside an otherwise sound ADR rather than replacing the
228
+ whole record. Use `## Amendment N (YYYY-MM-DD) — <topic>` plus the reciprocal
229
+ `amends:` / `amended_by:` pair — the validator rejects a one-sided link,
230
+ because a one-sided link is invisible from the stale side, and the stale side
231
+ is the one a reader lands on first. Where the amendment reverses text that is
232
+ still asserted above it, add a one-line banner there too; the frontmatter
233
+ alone does not stop someone quoting the reversed sentence.
234
+ - **Who may reopen it is recorded, not assumed** — `reopen_policy` /
235
+ `protected_dimensions`, both optional, absent meaning `unclassified`
236
+ ([`adr-layout § Reopen authority`](../../../docs/contracts/adr-layout.md)).
237
+ Reach for `owner` only when EVERY future transition is genuinely reserved;
238
+ `directional` is the normal answer, and no answer is a fine answer.
217
239
 
218
240
  ## Frugality Standards
219
241
 
@@ -280,6 +280,24 @@ in the rule; the lock catalog, fire steps, and failure modes live here.
280
280
  contract — every re-evaluated lock gets a fresh, correctly-scoped
281
281
  disposition, not a re-statement of the old one.
282
282
 
283
+ When the lock is an **ADR**, the disposition carries the five-field reopen
284
+ record from [`adr-layout § Reopen record`](../../../docs/contracts/adr-layout.md):
285
+ the original rationale **addressed** (not cited), what changed with tree
286
+ evidence, dependants and external commitments touched, the rollback path,
287
+ and a blast radius — `narrow | wide | irreversible` — with the evidence for
288
+ that call. Two clauses bind the same record: **precedent creates no
289
+ authority** (that a similar ADR was reopened is never grounds for this one),
290
+ and **one seat must argue the strongest case for keeping the decision**.
291
+ Both answer precedent laundering through correlated self-review, which is
292
+ the failure two independent council seats named for this mechanism on
293
+ 2026-08-19: the proposer frames the evidence, correlated seats ratify, and
294
+ the amendment becomes authoritative input for the next review.
295
+
296
+ Proportionally: a narrow, reversible, bounded transition takes the light
297
+ path (record + council); `wide` or `irreversible` adds owner notification.
298
+ Identical ceremony for a typo-level amendment would cost more than asking
299
+ the owner and the mechanism would die of its own weight.
300
+
283
301
  ### When NOT to fire
284
302
 
285
303
  - The blocked change has no real benefit — the gate is not a lever to
@@ -39,7 +39,7 @@ schema_version: 1
39
39
  # CI guard: a release bump of `package.json` must update this value
40
40
  # in lockstep — see scripts/check_template_pin_drift.ts (road-to-
41
41
  # portable-runtime-and-update-check P3.3).
42
- agent_config_version: "14.4.0"
42
+ agent_config_version: "14.6.0"
43
43
 
44
44
  # --- Project identity ---
45
45
  project:
@@ -213,6 +213,20 @@ var CAPSULE_SCHEMA_VERSION = 3;
213
213
  function isShortLine(value, max) {
214
214
  return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
215
215
  }
216
+ function isPathRef(value) {
217
+ return typeof value === "string" && value.length > 0 && !/\s/.test(value);
218
+ }
219
+ function checkPathRefList(errors, field, value, max, required) {
220
+ checkList(errors, field, value, max, required);
221
+ if (!Array.isArray(value)) return;
222
+ if (value.some((x) => !isShortLine(x, max))) return;
223
+ const bad = value.filter((x) => !isPathRef(x));
224
+ if (bad.length === 0) return;
225
+ const shown = bad.slice(0, 3).map((x) => JSON.stringify(String(x))).join(", ");
226
+ errors.push(
227
+ `${field} carries ${bad.length} entr${bad.length === 1 ? "y" : "ies"} that are prose, not path refs: ${shown}${bad.length > 3 ? ", \u2026" : ""} \u2014 write the path (src/generated/api.ts, ../other-worktree/) or drop the entry; a sentence naming a file cannot be compared against a write target, and being comparable is the whole reason this is a field rather than a line of prose`
228
+ );
229
+ }
216
230
  function checkList(errors, field, value, max, required) {
217
231
  if (value === void 0) {
218
232
  if (required) errors.push(`${field} is required`);
@@ -402,7 +416,7 @@ function validateRecycleEnvelope(input) {
402
416
  checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
403
417
  errors.push(...decisionTagErrors(e["decisions"]));
404
418
  checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
405
- checkList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
419
+ checkPathRefList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
406
420
  checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
407
421
  checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
408
422
  checkList(errors, "suggested_skills", e["suggested_skills"], MAX_REF_CHARS, false);
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-F7DQWYR5.js";
5
5
  import {
6
6
  validateAssumption
7
- } from "./chunk-ZPSXJTLI.js";
7
+ } from "./chunk-P6LQDIWK.js";
8
8
  import {
9
9
  ArgparseExit,
10
10
  STATUS_SYMBOLS,
@@ -21,7 +21,7 @@ import {
21
21
  scanEnvelopeDirectives,
22
22
  validateRecycleEnvelope,
23
23
  wrapAsPriorSessionData
24
- } from "./chunk-ZPSXJTLI.js";
24
+ } from "./chunk-P6LQDIWK.js";
25
25
  import {
26
26
  _RAW_KEY_PREFIXES,
27
27
  hardenedSpawnEnv,
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  CAPSULE_SCHEMA_VERSION,
9
9
  validateRecycleEnvelope
10
- } from "./chunk-ZPSXJTLI.js";
10
+ } from "./chunk-P6LQDIWK.js";
11
11
  import {
12
12
  atomic_write_json
13
13
  } from "./chunk-EJITJBJX.js";
@@ -1,6 +1,6 @@
1
1
  # Discovery — Deprecation Report
2
2
 
3
- - Generated: `2026-08-19T14:19:48Z`
3
+ - Generated: `2026-08-20T10:01:02Z`
4
4
  - Deprecated artefacts: **0**
5
5
 
6
6
  _None. Tree is clean._