@pilotspace/add 1.2.0 → 1.4.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 (43) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/GETTING-STARTED.md +26 -0
  3. package/README.md +16 -3
  4. package/bin/cli.js +85 -8
  5. package/docs/02-the-flow.md +4 -1
  6. package/docs/03-step-1-specify.md +2 -0
  7. package/docs/06-step-4-tests.md +8 -0
  8. package/docs/07-step-5-build.md +2 -0
  9. package/docs/08-step-6-verify.md +11 -0
  10. package/docs/09-the-loop.md +3 -1
  11. package/docs/10-setup-and-stages.md +1 -1
  12. package/docs/11-governance.md +4 -0
  13. package/docs/appendix-c-glossary.md +16 -1
  14. package/docs/appendix-e-checklists.md +14 -2
  15. package/package.json +1 -1
  16. package/skill/add/SKILL.md +18 -5
  17. package/skill/add/advisor.md +75 -0
  18. package/skill/add/compact-foundation.md +53 -0
  19. package/skill/add/confidence.md +48 -0
  20. package/skill/add/fold.md +4 -4
  21. package/skill/add/phases/0-ground.md +68 -0
  22. package/skill/add/phases/0-setup.md +52 -3
  23. package/skill/add/phases/1-specify.md +7 -0
  24. package/skill/add/phases/2-scenarios.md +2 -0
  25. package/skill/add/phases/3-contract.md +5 -1
  26. package/skill/add/phases/4-tests.md +2 -0
  27. package/skill/add/phases/5-build.md +24 -0
  28. package/skill/add/phases/6-verify.md +18 -0
  29. package/skill/add/phases/7-observe.md +7 -0
  30. package/skill/add/run.md +48 -5
  31. package/skill/add/soul.md +77 -0
  32. package/skill/add/streams.md +65 -9
  33. package/tooling/add.py +1715 -64
  34. package/tooling/templates/DESIGN.md.tmpl +66 -0
  35. package/tooling/templates/GLOSSARY.md.tmpl +11 -1
  36. package/tooling/templates/PROJECT.md.tmpl +3 -1
  37. package/tooling/templates/SOUL.md.tmpl +40 -0
  38. package/tooling/templates/TASK.md.tmpl +23 -4
  39. package/tooling/templates/catalog.sample.json +38 -0
  40. package/tooling/templates/prototype.sample.json +48 -0
  41. package/tooling/templates/tokens.sample.json +55 -0
  42. package/tooling/templates/udd-catalog.md +122 -0
  43. package/tooling/templates/udd-tokens.md +79 -0
package/skill/add/run.md CHANGED
@@ -28,7 +28,7 @@ What the human is actually approving in that one gate: that the drafted Spec cap
28
28
  that the Scenarios cover the cases that matter, and that the Contract shape is the one to freeze. Reject
29
29
  any part and the bundle goes back to draft — that is backward-correction (principle 4), not failure.
30
30
  Approve, and the run begins. The decision-point guide (`phases/3-contract.md`) carries the
31
- **freeze review checklist** — six lines that walk the human through exactly this, ⚠-first.
31
+ **freeze review checklist** — seven lines that walk the human through exactly this, ⚠-first.
32
32
 
33
33
  **The lowest-confidence flag — aiming the one approval.** A single approval over a whole bundle is easy to
34
34
  grant without reading. So the AI presents the bundle **lowest-confidence first**: of everything it is asking the human
@@ -117,6 +117,34 @@ The auto-gate NEVER writes a human signature it did not get. An auto-PASS is log
117
117
  honestly — the line between a pass and a skip is the recorded outcome, not a forged name.
118
118
  </constraints>
119
119
 
120
+ ## The bounded self-heal loop — a confirmed cheat returns to build
121
+
122
+ The auto-gate trusts evidence; but evidence can be **gamed**. A build can make the unchanged red suite
123
+ pass without EARNING it — a test or the frozen contract edited after the red run, src **overfit** to the
124
+ fixtures, **vacuous** asserts, or real logic **stubbed away**. That is a **confirmed cheat**, and a cheat
125
+ is **HARD-STOP-class**: never auto-passed, never RISK-ACCEPTED-waived (like a security finding). But a
126
+ first cheat is not yet a stop — it is a chance to redo honestly.
127
+
128
+ So a confirmed cheat enters a **bounded self-heal loop**: the engine returns the task to **build** for an
129
+ honest redo, **counts** the attempt, and **caps** it. After **3** honest re-build attempts a fourth
130
+ confirmed cheat forces a **HARD-STOP that escalates to the human** — never an auto-PASS, never an unbounded
131
+ loop. The engine COUNTS, CAPS, and ESCALATES; the **agent** does the honest re-build (the engine never
132
+ auto-fixes). The counter is **monotonic** — it never auto-resets, so the cap cannot be cleared by
133
+ re-crossing a phase; only an honest build (no cheat) escapes the loop, and an honest build PASSes even at
134
+ the third attempt (the cap bites a *continued* cheat, never a recovery).
135
+
136
+ Two findings enter the loop:
137
+ - **mechanical** (enforced) — the tamper tripwire (`tamper-tripwire`): at the gate the engine re-hashes the
138
+ red test files + the frozen §3 against the `tests→build` snapshot; any divergence is a cheat, routed to
139
+ the loop before any completing outcome is recorded.
140
+ - **semantic** (honor-system, necessary-not-sufficient) — the **adversarial refute-read** (`6-verify.md`):
141
+ an independent reviewer argues "the green was NOT earned" and, on a confirmed overfit/vacuous/stub, the
142
+ agent reports it with `add.py heal <slug> --reason "<finding>"`. The engine cannot SEE a judgment cheat,
143
+ so this entry is the agent's honest report — the human verify gate stays the real backstop.
144
+
145
+ The mechanical entry returns-to-build automatically at the gate; the `heal` verb is how a *reported* cheat
146
+ enters the same bounded loop. Either way: ≤3 honest redos, then escalate. A gamed green never ships.
147
+
120
148
  ## Emitting deltas — feeding the foundation back
121
149
 
122
150
  The completeness-critic does not discard what it finds. Every gap, surprise, or convention that helped
@@ -137,14 +165,19 @@ How much a run may auto-gate is a **per-scope setting**, not a global switch (pr
137
165
  earned per scope). A task declares its level in its `TASK.md` header:
138
166
 
139
167
  ```
140
- autonomy: auto | conservative
168
+ autonomy: manual | conservative | auto
141
169
  ```
142
170
 
143
- - **auto (the default)** the run may auto-PASS when the evidence + residue checks above are
171
+ An ordered ladder`manual < conservative < auto` declared once in the header and reviewed at the freeze:
172
+
173
+ - **auto (the seeded default)** — the run may auto-PASS when the evidence + residue checks above are
144
174
  satisfied. Security still always escalates. This is the default starting point: a frozen contract
145
175
  flips the task into a self-driving run that converges and auto-gates on evidence.
146
176
  - **conservative** — the deliberate *lowering*: the run does all the work and converges, but STOPS at
147
177
  the verify gate for a human. Auto-PASS is disabled. Choose it wherever evidence is thin or risk is high.
178
+ - **manual** — the strict floor: the human owns the verify gate and the engine never auto-resolves
179
+ (behaviourally the conservative floor with the explicit "I drive this decision; the AI proposes only"
180
+ name). Choose it for the highest-stakes scope; like `conservative`, it satisfies the high-risk guard.
148
181
 
149
182
  > **v7 reversal (recorded, not hidden).** Earlier the default was `conservative` and `auto` was the
150
183
  > earned exception; v7 flips this — `auto` is the default, `conservative` is the deliberate lowering.
@@ -154,7 +187,8 @@ autonomy: auto | conservative
154
187
  **The high-risk guard — `auto` is refused where it matters most.** The autonomy level is not a blank cheque. On a
155
188
  **high-risk or method-defining scope** — anything where a wrong-but-plausible result is expensive or
156
189
  hard to reverse (auth, money, data-loss paths, the method/trust-layer itself) — `auto` must be lowered
157
- to `conservative`; leaving it at `auto` there is the reject code **`unguarded_high_risk_auto`**. This
190
+ to a stricter rung — `conservative` or `manual`; leaving it at `auto` there is the reject code
191
+ **`unguarded_high_risk_auto`**. This
158
192
  closes the v6 dogfood gap, where the whole milestone ran at `auto` on the riskiest possible
159
193
  scope (defining the method) with no friction. The default is `auto` *for ordinary, well-tested scope*;
160
194
  high risk still earns a human gate.
@@ -163,9 +197,18 @@ Judging *what* is high-risk stays human — the scope declares **`risk: high`**
163
197
  header where the autonomy level lives, reviewed at the freeze like every header line (the engine never
164
198
  classifies scope). **Since v14 the guard is mechanical for the declared case:**
165
199
  the engine refuses the declared combination — `add.py gate` will not complete (`PASS`/`RISK-ACCEPTED`) a task whose header
166
- carries `risk: high` without `autonomy: conservative` (error `unguarded_high_risk_auto`; `HARD-STOP`
200
+ carries `risk: high` without a lowered level — `conservative` or `manual` (error `unguarded_high_risk_auto`; `HARD-STOP`
167
201
  always records — stopping is never blocked), and `add.py audit` flags the same code on a finished
168
202
  record whose header was tampered or whose GATE RECORD reviewer is the auto-gate — which CI enforces
169
203
  (audit-ci). The honest limit mirrors the audit's: an **undeclared** high-risk scope passes; declaring
170
204
  is the human decision point, the engine enforces what was declared.
205
+
206
+ **Autonomy is earned by goal-clarity — the auto-ready goal.** The level decides *who* resolves Verify;
207
+ an **auto-ready goal** decides whether a self-verifying run is even *meaningful*. A milestone goal is
208
+ auto-ready when **every exit criterion cites a verifier** — `(verify: <test | command | metric>)` — so the
209
+ run can check its own result against the goal without human judgment. `add.py check` raises a
210
+ `goal_not_auto_ready` WARN (never red, the active milestone only) while criteria are uncited, and `status`
211
+ prints a `goal-ready:` line every session. It **measures, never blocks** — it changes neither the freeze
212
+ gate nor the autonomy level. The lint forces a citation slot per criterion (raising the floor) but cannot
213
+ prove the citation is honest (`(verify: it works)` passes) — that judgment stays the human's.
171
214
  </constraints>
@@ -0,0 +1,77 @@
1
+ # Self-improving the voice — how SOUL.md converges to the human
2
+
3
+ `SOUL.md` is the AI's voice (tone · communication style · trust). It ships as a **proposed starter**
4
+ and is **human-owned**; this doc is how it stops being write-once and starts converging to *this*
5
+ human. It mirrors `deltas.md` (emit) + `fold.md` (confirm → rewrite), but a confirmed voice delta is
6
+ consolidated into **SOUL.md**, not the foundation — because voice is not one of the five competencies.
7
+
8
+ You (the AI) **emit** voice deltas as `open`. Only the **human** confirms one, and only a confirmed
9
+ delta rewrites SOUL.md. **The human's confirm is the only writer** — you never self-approve a voice
10
+ rewrite (rewriting someone's voice is theirs to approve, like a foundation consolidation).
11
+
12
+ ## What a voice delta is drawn from
13
+
14
+ A voice delta is grounded in how the human actually shows up **in session**:
15
+ - their **wordings** — the words they reach for, and the words they correct you on (they cross out a
16
+ bit of jargon and write the plain word over it);
17
+ - their **flow** — what they skip, what they double-check, where they want the summary before the detail.
18
+
19
+ NOT from their private **memory** files or anything outside the working session — SOUL learns from what
20
+ you observed together, never from reading a personal store.
21
+
22
+ ## The grammar (mirrors deltas.md)
23
+
24
+ Each voice delta begins on its own tag line; the observation may wrap, and a required `(evidence: …)`
25
+ clause closes it:
26
+
27
+ ```
28
+ - [VOICE · <status>] <observation about the voice> (evidence: <in-session pointer>)
29
+ ```
30
+
31
+ - `<status>` — `open` | `confirmed` | `declined`. A newly emitted delta is **`open`**.
32
+ - `<observation>` — what the voice should become ("lead with the decision, not the preamble").
33
+ - `(evidence: …)` — **required**, non-empty: a moment in the session (a correction, a re-ask, a
34
+ visible preference). No evidence → it is a guess about the human, not a delta. Drop it.
35
+
36
+ ```
37
+ - [VOICE · open] the human strips hedging from my drafts — cut "I think / it seems" and state it plainly
38
+ (evidence: they rewrote two replies this session to remove the qualifier)
39
+ ```
40
+
41
+ ## The loop — observe → confirm → rewrite
42
+
43
+ 1. **Emit** (OBSERVE) — at a task's observe phase (or on demand), propose 0–N voice deltas as `open`
44
+ from the session's wordings + flow. Surface them in the report; show-before-ask.
45
+ 2. **Confirm** — the human accepts or declines each. **No SOUL.md write happens without this.**
46
+ 3. **Rewrite** — on a confirmed delta, edit the routed SOUL.md section, then record the delta line
47
+ (status `confirmed`) at the **top** of the "Voice deltas" ledger (**newest-first**, append-only — a
48
+ declined delta flips to `declined` and stays in place, so "considered, chose not to" is auditable).
49
+
50
+ ## Routing — every voice delta has a SOUL.md home
51
+
52
+ | the delta is about… | rewrite this SOUL.md section |
53
+ |---------------------|------------------------------|
54
+ | how I *sound* (warmth, directness, hedging) | **## Tone** |
55
+ | how I *structure* what I say (summary-first, show-before-ask, length) | **## Communication style** |
56
+ | what keeps the human's *trust* (gates, honesty, what I never do) | **## Trust** |
57
+
58
+ The rewrite is surgical: refine or append the bullet the delta names; never silently rewrite the rest
59
+ of the voice. Every confirmed delta also gets its line in **## Voice deltas** (newest-first).
60
+
61
+ ## Reject codes (the AI is first check, the human the backstop)
62
+
63
+ <reject_codes>
64
+ - `unconfirmed_voice_rewrite` — a SOUL.md write was attempted without a recorded human confirm. The AI
65
+ proposes; it never self-approves. Stop and get the confirm. (The identity-owned floor.)
66
+ - `no_open_voice_deltas` — nothing is `open`. The loop is a no-op; do not touch SOUL.md.
67
+ - `unroutable_voice_delta` — the observation maps to no SOUL.md section (not tone/style/trust). Fix the
68
+ delta or widen the routing before writing.
69
+ </reject_codes>
70
+
71
+ ## Where it plugs in
72
+
73
+ - **Emit**: `phases/7-observe.md` proposes voice deltas beside its competency/spec deltas.
74
+ - **Target**: `SOUL.md` (scaffolded by setup) — its "## Voice deltas" ledger holds the confirmed history.
75
+ - **Kin**: `deltas.md` (competency learnings → foundation) and `fold.md` (the same propose→confirm→write
76
+ discipline). This is the voice's version of that discipline; the engine stays judgment-free (no
77
+ `add.py` command writes the voice).
@@ -1,8 +1,11 @@
1
1
  # Parallel streams — pipelining independent tasks
2
2
 
3
- Load this **only** when a milestone has more than one task and you want to run them
4
- concurrently. The default ADD path is one task at a time; this rubric is the opt-in
5
- escape hatch for when independent tasks are queued and a human is ready to review.
3
+ Load this when a milestone has more than one task and you want to run them concurrently.
4
+ **Default:** when a project confirms `parallel + auto` as its run mode at setup
5
+ (`phases/0-setup.md` "Run mode"), parallel streaming is the project default an **opt-out**, not
6
+ the opt-in it once was; downgrade in one step (`add.py autonomy set conservative --project`, or just
7
+ run tasks one at a time). A project that kept the conservative run mode still treats this rubric as
8
+ the opt-in escape hatch. Either way it changes nothing below.
6
9
 
7
10
  It changes **no `add.py` code and no phase semantics**. It is a way *you, the
8
11
  orchestrator*, drive several tasks at once by reading the dependency DAG that
@@ -35,6 +38,44 @@ Compute both from one `python3 .add/tooling/add.py status` — no new state:
35
38
  └──────────────── a task gating PASS unblocks its dependents ──────────────┘
36
39
  ```
37
40
 
41
+ ## The DAG strategy — let the engine schedule the waves (`add.py waves`)
42
+
43
+ Do **not** eyeball the READY-QUEUE by hand once a milestone has more than a couple of
44
+ tasks — the engine computes the whole schedule from the dependency DAG `status` already
45
+ holds. `add.py waves` (read-only, writes nothing) groups the active milestone's not-done
46
+ tasks into **topological waves**, names the **critical path**, and emits an advisory
47
+ **tier hint** — exactly the inputs you need to fan out effectively:
48
+
49
+ ```
50
+ $ add.py waves
51
+ milestone: v13-onboarding-polish
52
+ wave 1: dag-scheduler, setup-suggest-milestone, setup-domain-deepdive, soul-artifact
53
+ wave 2: setup-run-mode (deps: dag-scheduler), soul-self-improve (deps: soul-artifact)
54
+ critical path: dag-scheduler → setup-run-mode (2 tasks)
55
+ tier hint: top → dag-scheduler, setup-run-mode; mid → the rest
56
+ ```
57
+
58
+ Read the schedule as a strategy, not a command:
59
+
60
+ - **Wave = a fan-out batch.** Every task in a wave has all its in-milestone deps already
61
+ PASS, so the whole wave is spawnable at once (one worker per task, `isolation="worktree"`).
62
+ Finish a wave, gate its tasks PASS, then `add.py waves` again — the next wave is unblocked.
63
+ - **Run the widest wave first.** It hides the most build latency under the human's review
64
+ latency (the honest frame above): more concurrent builds while the reviewer reads one bundle.
65
+ - **Spend your strongest model on the critical path.** The critical-path tasks gate the most
66
+ downstream work, so a wrong-but-plausible result there is the costliest — give them the
67
+ **top** tier (`run.md` tiers); off-path tasks take **mid**. The tier hint is exactly this rule,
68
+ applied to the graph. It is **advisory** — graph position is a proxy for scope difficulty, not a
69
+ gate; override it when you know a task is harder than its position suggests.
70
+ - **`--json`** (`{ milestone, waves, critical_path, critical_path_len, tiers, blocked }`) feeds a
71
+ runner that spawns the wave programmatically. `blocked` lists any task whose dep can never be
72
+ satisfied within this milestone (a cross-milestone dep) — surfaced, never silently dropped; a
73
+ `dependency_cycle` is refused with the offending members named (no schedule exists).
74
+
75
+ What `waves` does **not** change: the irreducible floor below still holds — one human approval
76
+ per contract, builds overlap but the review queue stays serial. `waves` decides *order and model*,
77
+ never *whether the human gate fires*.
78
+
38
79
  ## The autonomy level is the throttle (not a new flag)
39
80
 
40
81
  How much concurrency you actually get is set by each task's `autonomy:` header
@@ -42,9 +83,9 @@ How much concurrency you actually get is set by each task's `autonomy:` header
42
83
 
43
84
  | `autonomy` (TASK.md) | What serializes on the human | Concurrency |
44
85
  |----------------------|------------------------------|-------------|
45
- | `conservative` | bundle approval **+** every Verify | pure pipelining — builds overlap, both gates queue |
86
+ | `conservative` / `manual` | bundle approval **+** every Verify | pure pipelining — builds overlap, both gates queue (`manual` is the strict floor; same streams behaviour) |
46
87
  | `auto` (default) | bundle approval **only**; Verify auto-PASSes on evidence | real concurrency — only the decision point + residue escalations queue |
47
- | `auto` but **high-risk** | refused → forced `conservative` (`unguarded_high_risk_auto`) | back to pipelining, by design |
88
+ | `auto` but **high-risk** | refused → must lower to `conservative` / `manual` (`unguarded_high_risk_auto`) | back to pipelining, by design |
48
89
 
49
90
  The irreducible floor is **one human approval per task at the contract decision point** — the decision point
50
91
  never drops to zero (`run.md:22`). That floor is correct; do not engineer around it.
@@ -72,6 +113,16 @@ never drops to zero (`run.md:22`). That floor is correct; do not engineer around
72
113
  worktree forked from a stale base forces the worker to recreate the frozen artifacts by hand
73
114
  (the v10 dogfood hit exactly this). Before the worker starts, confirm `git -C <worktree>
74
115
  rev-parse HEAD` equals the orchestrator's `HEAD`; if it drifted, `git merge` the base in first.
116
+ On a runner that creates each worktree **at spawn** from a pool (e.g. Claude Code), that pool can hand
117
+ out a STALE base, so the pre-spawn `rev-parse` evidence cell is unsatisfiable. The `unverified_fork_base`
118
+ check then **shifts** — it never skips: the worker's **step-0** syncs to base (`git merge` the orchestrator's
119
+ `HEAD`) and re-echoes `rev-parse HEAD`, which the orchestrator verifies at **merge-time**, before merge-back.
120
+ The pre-spawn check stays the DEFAULT for fresh-`HEAD`-worktree runners; the merge-time path is the additive
121
+ ALTERNATIVE for spawn-time runners — never a replacement of the pre-spawn rule.
122
+ **The engine executes this gate** (engine-merge-base-enforcement): run
123
+ `python3 .add/tooling/add.py wave-verify` before the first merge-back — it refuses a mismatched or
124
+ pending echo (`unverified_fork_base`) and an off-template ledger (`wave_ledger_malformed`, fail-closed);
125
+ `add.py check` is the standing monitor (red at `status: merging`, `fork_base_pending` WARN at `live`).
75
126
  - **Lease + timeout** — record which worker holds which task (in the wave ledger, below);
76
127
  if a worker dies, release the claim back to READY (re-spawn, do not assume partial work is sound).
77
128
  - **Failure isolates** — a worker that hits a STOP-and-escalate (below) blocks only its
@@ -114,7 +165,10 @@ base: <orchestrator HEAD at spawn — the sha every fork must equal>
114
165
  `git -C <worktree> rev-parse HEAD`, and it must equal `base:`. A tick is not evidence; a row
115
166
  you can only fill by running the command is the fresh-worktree-base check EXECUTING — the
116
167
  v12-1 lesson (words-exist ≠ method-works) closed structurally. Spawning a worker whose roster
117
- row lacks that evidence is refused (`unverified_fork_base`).
168
+ row lacks that evidence is refused (`unverified_fork_base`). On a spawn-time pool runner this
169
+ PRE-spawn paste is unsatisfiable (the pooled base is stale until the worker syncs), so the cell
170
+ instead holds the worker's **step-0** post-sync echo (still `== base:`) and the `unverified_fork_base`
171
+ refusal **shifts to merge-time**, before merge-back — it shifts, it never lifts.
118
172
 
119
173
  **Lifecycle — open → consume → digest → delete.** Open the ledger when the first worker
120
174
  spawns. The serial integration Verify consumes it (the merge order is read from it, one
@@ -181,7 +235,7 @@ STOP-and-escalate (return your findings; do not decide):
181
235
  • a discovered scope/contract gap → backward-correction, reopen Specify (principle 4)
182
236
  • any SECURITY finding → HARD-STOP, always
183
237
  • a concurrency/timing OR architecture/layering risk the tests cannot exercise
184
- • [include this bullet ONLY when autonomy=conservative] the verify gate itself — STOP for the human
238
+ • [include this bullet when autonomy is conservative OR manual — any lowered rung] the verify gate itself — STOP for the human
185
239
  Auto-PASS only if autonomy=auto AND: all tests green · coverage not decreased · no test weakened ·
186
240
  no contract edited · loops dry · completeness-critic clean · no residue above. Log it as
187
241
  auto-resolved, naming this run as owner — never forge a human signature.
@@ -204,7 +258,9 @@ ripgrep otherwise. Design every IO path for failure — timeouts, retries, rollb
204
258
  </tools>
205
259
 
206
260
  <return> <!-- the worker PROPOSES; the orchestrator RECORDS. A worker never runs add.py. -->
207
- End with a structured verdict AND write the same into SUMMARY.md in the task dir:
261
+ End with a structured verdict AND write the same into SUMMARY.md in the task dir, then
262
+ **commit SUMMARY.md + deltas.md** in the worktree (uncommitted worktree files survive only by
263
+ harness courtesy — commit them so the serial-integration merge-back carries your report):
208
264
  { task, outcome: PASS|RISK-ACCEPTED|HARD-STOP|ESCALATE, evidence: <tests+coverage>,
209
265
  residue: [security|concurrency|architecture findings], deltas: [open lessons learned] }.
210
266
  Do NOT touch add.py or any shared file — the orchestrator gates on your verdict.
@@ -222,7 +278,7 @@ The contract is identical whichever model runs it (the model is disposable, like
222
278
  | **top** | complex / ambiguous / cross-cutting / broad scope of impact | `opus` | the runner's strongest reasoning model |
223
279
 
224
280
  Two rules sit **above** model choice and never bend:
225
- - **High-risk ⇒ `conservative` autonomy, regardless of model** (`run.md` high-risk guard). A
281
+ - **High-risk ⇒ a lowered rung (`conservative` or `manual`), regardless of model** (`run.md` high-risk guard). A
226
282
  stronger model does not buy back the human gate.
227
283
  - **Security residue always escalates** — no tier and no model auto-passes it.
228
284