git:20261021.f6e50b5 to git:20261021.f069886

118 added, 100 removed. Audit A to A.

# Design step
## Needs-input guard
A blank or vague scope or acceptance-criteria input is a gap, not a licence to
infer. The order is fixed: search the repository's own docs first and append an
`open-question` row to the unit folder's `decisions.md` recording where; research
an external gap into 2–3 concrete options. A gap surviving both runs
`node scripts/needs-input.mjs <unit-dir>`, pastes the `open-questions@1` block
and stops — route `design` for scope/architecture questions. "Decide for me" is
a legitimate answer: the lane chooses and records the choice with its reason.
Cheap-to-change defaults are recorded as assumptions, never silent.
## Purpose
- Run the gap interview, induce acceptance criteria from user scenarios, and
- close entity, role, and expectation boundaries — distilled from the full design
- skill's closure.
+ Run **investigate → orient → ask → decide**: every claim the SPEC makes is
+ entered in a ledger that cites its source, and entity, role, and expectation
+ boundaries close. The unit of progress is a **claim with a source** — a claim no
+ source or owner answer supports is a defect, not a judgment call.
## Inputs
- The unit's objective, why, and user outcome from the SPEC
- The user's original request, the repository's current state, and the
- installed tooling — whatever they already answers is never asked again
+ installed tooling — whatever they already answer is never asked again
- Research findings from the research step
- ---
-
- The design step is split into three distinct stages. Each stage writes its
- output to the unit folder's `decisions.md` and the next stage reads only that
- output — no stage validates itself against the raw context. This prevents
- the self-verification loop that burned fix-258 through 12 review→fold
- cycles (each cycle re-verified the row it just wrote but never re-read it
- as an instruction chain).
-
- ## Investigate
-
- Discover every fact the design decision depends on. Do not filter, do not
- resolve — just record what exists.
+ ## Stage 1 — investigate
- Procedure:
+ Open with a provenance search, then journal every claim. **The first action of
+ this stage is a search, not a sentence**: no design claim is written before the
+ repository has been asked.
- 1. Read the unit's objective, why, and user outcome from the SPEC.
- 2. Read the user's original request and the repository's current state
- (the installed tooling, the architecture docs, the roadmap).
- 3. Read the research findings from the research step (if present).
- 4. For each fact the design depends on, append a row to `decisions.md`:
+ 1. **Provenance search.** Run the greps and reads whose result would settle the
+ claim (`grep -rn "<term>" docs/ src/`, the documentation map, the architecture
+ doc, the roadmap, prior units' `decisions.md`), and record **where you
+ looked**: `path:line` hits and the greps run. A "not found" without that
+ receipt is the defect this stage exists to catch.
+ 2. **Journal** — append one row per claim to the unit folder's `sources.md`:
- ```
- | id | fact | source | certainty |
+ | id | claim | source | certainty |
|---|---|---|---|
- | INV-001 | <the fact> | <path:line or "user request"> | confirmed | inferred |
- ```
+ | INV-001 | <the claim, one line> | `<path:line>`, `<doc#anchor>`, `owner answer <Q-id>`, or `user request` | confirmed / inferred / unknown |
- Certainty values: `confirmed` (verifiable by command or documented),
- `inferred` (deduced from available evidence, not yet verified), `unknown`
- (no evidence available).
+ `confirmed` = verifiable by a command or documented; `inferred` = deduced,
+ not yet verified; `unknown` = no evidence found (→ the orient stage must ask).
+ 3. **Induce acceptance criteria** from user scenarios — each AC is a claim too,
+ and cites the scenario or owner answer it came from.
+ 4. **Close boundaries**: entities and their roles, actors, accepted and rejected
+ inputs (the expectation sweep), deferrals (→ `## Future`).
- Fixed output contract — the output is a table of rows:
- `- <fact>: <source> · <certainty>`
+ Pass only if: ✓ the provenance search ran and its receipt is recorded ✓ every
+ claim is a `sources.md` row ✓ every AC is induced from a user scenario.
- The investigate stage produces nothing but this list. It does NOT filter
- the facts, does NOT decide what to ask, does NOT induce acceptance criteria.
+ ## Stage 2 — orient
- ## Orient
+ Filter each `INV-*` claim with three fixed tiers, in order — the lowest tier that
+ settles the claim wins, and the repository always speaks first:
- Filter each investigated fact against the gap-filter table. Decide what
- blocks now, what blocks later, what is cheap to change, and what is already
- answered.
+ | Tier | When it settles the claim | What this stage does |
+ |---|---|---|
+ | **0 · provenance** | A recorded `path:line`, doc, or prior decision answers it | Nothing to ask — point the row at the source |
+ | **1 · research** | External and unresearched, in tier 0 or outside it | Research it into 2–3 options with trade-offs |
+ | **2 · ask** | No evidence exists anywhere | Backlog it for the ask stage — never decided here |
- Filter table (runs on each INV-* row):
+ The tier-2 backlog is then filtered by cost of being wrong — expensive to undo
+ = **scope** (personal / team / global), **stack**, **architecture pattern**,
+ **data model**, **deployment target**, **security configuration**:
- | The fact… | The lane does |
+ | The claim… | The lane does |
|---|---|
- | The request, the repo, or the installed tooling already answers it | Never asks |
| Blocks now and is expensive to undo once code sits on top | Asks |
| Blocks a later task that is already foreseeable | Asks now as a possibility; re-asks only if conditions change |
- | Cheap to change later | Takes a reasonable default and records it as an assumption — never silent |
-
- Expensive to undo = the choices that cost a lot to change once code exists
- on top: **scope** (personal / team / global), **stack**, **architecture
- pattern**, **data model**, **deployment target**, and **security configuration**.
-
- For each gap that passes the filter (blocks now/expensive → ask, blocks
- later/foreseeable → ask, cheap → assume, already-answered → skip),
- append a row to `decisions.md`:
-
- ```
- | id | gap | filter-result | action |
- |---|---|---|---|
- | OR-001 | <the gap> | blocks now / cheap / already-answered / foreseeable | ask / assume / skip |
- ```
-
- Fixed output contract — the output is a table of rows:
- `- <gap>: <filter-result> · <action>`
+ | Cheap to change later | Takes a reasonable default, records it as a dated assumption — never silent |
- The orient stage produces nothing but this filtered list. It does NOT
- formulate questions, does NOT ask the user, does NOT induce acceptance
- criteria.
+ Pass only if: ✓ every `INV-*` row carries a tier and a cost verdict ✓ every
+ tier-0 row names the source that settled it ✓ no claim was researched or asked
+ before the provenance tier ran.
- ## Ask
+ ## Stage 3 — ask
- Batch user decisions from the Orient output. The Ask stage reads only the
- Orient table (the list of gaps needing a decision) — it does NOT re-read
- the raw investigated facts.
+ Batch the tier-2 claims from the orient stage. This stage reads the **orient
+ output and the ask backlog** — never re-derives a claim the provenance tier
+ settled, never re-asks an answer the user already gave.
Mechanics — one batched form-turn, never one-question-per-turn:
- Group all independent questions into a single turn; ≤6 slots, one-word
defaults accepted, ≤2 ambiguity follow-ups per slot.
- Ask a single question first only when its answer changes the others. When
more than five gaps remain, the root decision (objective or scope) goes
first — its answer usually removes most of the rest.
- Every slot carries: the **recommended option with its why**, one
alternative, **"Decide for me"**, and **"Explain the options"** — the user
may always answer freely.
- - **"Decide for me"**: the lane chooses, then records the choice and its
- reason as a dated row in the unit folder's `decisions.md` — explicit,
- never guessed silently.
- - **"Explain the options"**: explain each alternative didactically, then
- re-ask only that slot.
- A tool the project lacks may be offered as one more option (with its
recommendation and why); installing it always needs the user's explicit
consent.
- - **Ready when:** no expensive-to-undo blocking gap remains unanswered — not
- when no gaps remain. An answer the user already gave is never re-asked.
+ - **Ready when:** no expensive-to-undo blocking claim remains unanswered — not
+ when no questions remain.
- For each user decision, append a row to `decisions.md`:
+ The questions are the `open-questions@1` block of the unit folder's
+ `decisions.md` — the grammar `scripts/needs-input.mjs` reads, published in the
+ template agent guide's question protocol. Append the block (never a table of
+ your own invention) and carry a search receipt on every question:
- ```
- | id | question | recommended | user-decision |
- |---|---|---|---|
- | ASK-001 | <the question> | <recommended option with why> | <user choice> |
+ ```text
+ open-questions@1
+ id | date | type | question | blocks | search-receipt | options | route
+ Q1 | <YYYY-MM-DD> | open-question | <the decision being asked> | <why nothing proceeds without it> | <where the repository was searched: path:line, greps, prior units> | <option A — trade-off> \| <option B — trade-off> \| Decide for me \| Explain the options | design
```
- ## Deferred ideas
+ ## Stage 4 — decide
- Deferred ideas ("down the road I'd like…") are never implemented, never turned
- into spec or tasks by this unit: they go verbatim to the unit doc's
- `## Future` section, dated, so the architecture may accommodate them without
- building them.
+ Record every answer — the user's, and every "Decide for me" choice with its
+ reason — as a `decision` row of the same block, newest last. Only the owner
+ closes a question; the row carries where the answer is recorded (a chat paste, an
+ issue comment) and what was discarded:
+ ```text
+ D1 | <YYYY-MM-DD> | decision | Q1 | human-owner | <where the answer is recorded> | <what was chosen> | <what was discarded and why>
+ ```
+
+ A cheap default taken in stage 2 goes to the file's `## Assumptions` as a dated
+ row, correctable by the user. Then fill the unit doc's **Acceptance criteria**
+ (induced from a concrete scenario, command-verified where possible, numbered).
+
## Fixed output contract
- Fill the unit doc's **Acceptance criteria** section. Each AC must be:
- - Induced from a concrete user scenario ("I do X and observe Y")
- - Command-verified where possible (not "feel correct")
- - Numbered (AC1, AC2, …)
+ The step owns four panes of the unit folder and nothing else:
+ <!-- sources:start -->
+ `sources.md` — one row per claim, each with a source or an owner answer. A
+ claim row with an empty, `—`, or `n/a` source is a **defect**: either find the
+ source in the provenance tier or convert the claim into a question.
+ <!-- sources:end -->
+
+ <!-- questions:start -->
+ The unit folder's `decisions.md` — the `open-questions@1` block the ask stage
+ appended, plus the `decision` rows the decide stage appended (one per question
+ closed). The step also refreshes `BRIEF.md`, the reviewer brief that restates
+ them, so a reviewer never has to re-derive the step's questions.
+
+ | Asked | Resolution |
+ |---|---|
+ | <question id + the decision being asked> | <what was chosen, by whom (owner answer / Decide for me), and why> |
+
+ When the orient stage left an empty ask backlog, write exactly
+ ``none — no questions: every claim was settled by provenance or research``.
+ An empty table is never that line — the form is a decision, the blank is a
+ missing one.
+ <!-- questions:end -->
+
+ <!-- deferred:start -->
+ `## Future` in the unit doc — deferred ideas ("down the road I'd like…"),
+ verbatim and dated. They are never implemented, never turned into spec or tasks
+ by this unit, and are reviewed at close, on resume, and when work returns to the
+ area.
+ <!-- deferred:end -->
+
+ <!-- acceptance:start -->
+ The unit doc's **Acceptance criteria** section, numbered and command-verified.
+ <!-- acceptance:end -->
+
## Checklist (pass only if)
- - [ ] The investigate stage ran: each fact recorded as INV-* row in `decisions.md`
- - [ ] The orient stage ran: each INV-* row filtered through the gap table, gaps recorded as OR-* rows
- - [ ] The ask stage ran: all blocking/expensive gaps batched into a single form-turn, decisions recorded as ASK-* rows
- - [ ] No expensive-to-undo blocking gap remains unanswered
+ - [ ] The provenance search ran first and its receipt is recorded (`path:line`, the greps, prior units)
+ - [ ] Every claim (objective, why, every AC, non-goals) cites its source or an owner answer in `sources.md`, and none lacks one
+ - [ ] Every claim carries a certainty (`confirmed` / `inferred` / `unknown`); an `unknown` claim became a question
+ - [ ] Every acceptance criterion (AC1, AC2, …) is induced from a user scenario and cites what induced it
+ - [ ] The orient tiers ran in order: provenance before research before ask
+ - [ ] Every question asked was recorded with its resolution — or the questions pane says `none` explicitly
+ - [ ] No expensive-to-undo blocking claim remains unanswered
- [ ] Every "Decide for me" choice is recorded with its reason in `decisions.md`
- - [ ] Cheap defaults are recorded as assumptions, correctable by the user
- - [ ] Deferred user ideas landed in `## Future`, not in scope
- - [ ] Every AC is induced from a user scenario, not inferred from vague intent
- - [ ] Acceptance criteria are command-verified where possible
+ - [ ] Cheap defaults are recorded as dated assumptions, correctable by the user
- [ ] Entity closure: every entity mentioned has its role in the unit stated
- [ ] Role closure: every actor/role that interacts with the unit is listed
- [ ] Expectation sweep: user's accepted and rejected inputs are bounded
- - [ ] Vague items → ask the user with concrete options, never invent
- - [ ] The ask stage read only the Orient output, not the raw investigate facts
+ - [ ] Deferrals landed in `## Future`, not in scope
## Forbidden
+ - Never infer a claim: one that is not in the repository and not derivable from
+ it is a question for the owner, never a default. A claim with no source and no
+ owner answer is the defect, not a judgment call
+ - Do not write a design claim before the provenance search ran
- Do not ask what the request, the repo, or the installed tooling already answers
- Do not ask one question per turn when slots are independent
+ - Do not invent a question table of your own: the ask stage writes the
+ `open-questions@1` block the dispatcher reads
+ - Do not decide at the ask stage — asking and answering are different stages
- Do not implement, spec, or task anything from `## Future`
- Do not install a missing tool without explicit user consent
- Do not build a separate DESIGN.md — one SPEC, all in the unit doc
- - Do not invent product scope the user did not confirm
- Do not pre-fill engineering content (phases, tests, architecture)
- Do not stamp "designed" with an incomplete closure row
- - Do not validate your own output against the raw context
- - An incomplete row silently un-does the skill's purpose