# Contract interview — mandatory upstream passage (all orchestrators) Produces the CONTRACT: the single reference passed verbatim to the plan, the dev subagents, and the verifier. The contract is what lets the orchestrator delegate execution without subagents ever needing a human gate (LRN-083: subagents = execution + report only; gates and loop decisions live in the main loop). Run this in the ORCHESTRATOR MAIN LOOP, never in a subagent — STEP 2 may talk to the human, at contract time (pass A) and again at the flow's PLAN step (pass B). Questions follow the open choices, never a quota — a complete request goes through silently. ## STEP 1 — CAPTURE (verbatim) Copy the user's request EXACTLY as typed (`$ARGUMENTS` + the triggering message). No paraphrase, no cleanup, no translation, no summarizing. This section is IMMUTABLE for the life of the run — every later consumer (planner, dev, verifier) reads THESE words, never a restatement. ## STEP 2 — CLARIFY (ask, never guess) Two passes, both in the main loop, both may talk to the human. **Pass A — gaps.** Run here, against the request. Ask if one of these is missing AND not derivable from the repo: - a testable expected outcome - an unambiguous scope (what is allowed to change) - non-contradictory constraints **Pass B — open choices.** Defined here, run ONCE at the flow's PLAN step (see "Where pass B fires" below), against the plan just written — that is where choices become concrete. Enumerate every choice the run will settle that the request leaves open; keep those in these classes: 1. VISIBLE — the user would see it in the result: placement, label, wording, color, order, what a click does. 2. PUBLIC NAME — a name that outlives the run: command, flag, endpoint, env var, a file the human will read. 3. SCOPE — "should X change too?", where the request does not name X. NEVER ask class 4 — internal technical choices with no observable effect (function decomposition, data shape, local naming, layout inside an already-scoped zone). Those are delegated; asking them is the noise that makes classes 1-3 ignorable. Never ask what the repo or the request already answers — verify paths/APIs/behavior yourself first. No question cap. Each pass asks what it finds, in ONE batch. A request that leaves nothing open goes through silently. More than 5 open choices in pass B = the request is under-specified: list them, say so, stop — do not fire a questionnaire. "You decide" / "peu importe" is an answer: record it as `A: delegated — ` and never re-ask it. Pass B answers land in the contract's CLARIFICATIONS marked `[gated ]` — the contract is already on disk by then. ### Where pass B fires | Flow | Pass B runs at | Against | |------|----------------|---------| | feat | STEP 1 PLAN, before 1b CHALLENGE | the PLAN checklist | | bugfix | STEP 3 FIX PLAN, before 3b | the FIX PLAN | | hotfix | STEP 1 LOCATE | the 1-2 target files' visible effect | | ship-feature | STEP 2 PLAN, after the brainstorm | the plan, minus what the brainstorm settled | | init-project | STEP 3 DESIGN, before VALIDATION GATE #1 | the DESIGN, minus what the interview and brainstorm settled | | onboard | its STEP 3 interview, unchanged | scope, in one block | ## STEP 3 — DERIVE - ACCEPTANCE CRITERIA: numbered; each one testable — a fresh reader must be able to mark it MET / NOT-MET against the real code, without having seen this conversation. - FILE SCOPE: paths/zones expected to change, or `repo-wide — `. ### ORACLES — a criterion a command can decide carries one Give such a criterion an indented `CHECK:` (the command), `EXPECT:` (a success-only marker), and `EVIDENCE: pending`. `bash ~/.claude/lib/gates.sh run ` executes it fail-closed — MET requires exit 0 **AND** the marker — and writes the result back over the `EVIDENCE:` line. That persisted evidence is what the fresh verifier reads as fact instead of trusting the executor's report (GATE 0 in `lib/verify-secure-loop.md`). Both attributes or neither. `CHECK:` without `EXPECT:` is a parse error, not a manual criterion — the runner refuses the whole ledger. Leave a criterion oracle-free when no command can decide it; the verifier judges those. Four authoring rules — a gate that cannot fail proves nothing: 1. **Observe the named artifact.** The check reads the file, service, or measurement the criterion's own words name — never a proxy for it. `1. invoices reconcile` + `CHECK: echo ok` is valid and worthless. 2. **Success-only marker.** The script runs every assertion, exits nonzero on any failure, and prints the `EXPECT:` string only after all pass. 3. **Positive control before any absence check.** Run the same logic against a fixture known to trip it and confirm it fails. A missing file, a wrong path, and a broken pattern all look exactly like valid absence. 4. **Recompute supplied numbers.** Never copy a figure from the request into `EXPECT:` — the script derives it from source and prints its own marker. A number that is its own proof proves nothing. `CHECK:` is shell code run with our privileges. It is safe only because we author it in our own repo — never build one out of externally-supplied text (a scraped URL, a client string); route those through `lib/url-guard.sh`. ## STEP 4 — WRITE TO DISK (immediately, before any next step) Path: `.claude/tasks/contracts/--.md` (`mkdir -p` the directory; unique per run: date + short kebab slug + HHMM — two runs on the same day never collide). A contract that lives only in context dies at compaction, and the verbatim request with it. Template: ```markdown # CONTRACT — - date: | flow: | branch: - status: active ## REQUEST (verbatim — IMMUTABLE) ## CLARIFICATIONS Q: / A: (pass B and mid-run entries: [gated ]) (or: none — request complete) ## ACCEPTANCE CRITERIA 1. CHECK: EXPECT: EVIDENCE: pending 2. (ABANDON: — only for a criterion proven impossible) ## FILE SCOPE (or: repo-wide — ) ``` Print one line to the user, then continue the flow: `CONTRACT: — criteria, scope , questions asked` ## MID-RUN CLARIFICATION (the channel executors halt into) An executor cannot talk to the human. It halts with `NEED-DECISION`, the exact question, the options it sees, and a `CLASS:` tag (visible | public-name | scope | internal). `/hotfix`: the hotfixer keeps `DONE | BLOCKED`; a BLOCKED carrying the tag follows the same routing instead of escalating to `/bugfix`. The orchestrator re-reads the class — the tag is a hint, not a verdict — then routes: - visible / public-name / scope → ASK THE HUMAN, verbatim question and options. Never decide these yourself, never spend a round-trip guessing. - internal → decide here, note the decision, re-dispatch. The only case the orchestrator settles alone; max 2 such round-trips → escalate. Every answer, human or orchestrator, appends to the contract's CLARIFICATIONS marked `[gated ]` — the same micro-gate as scope enrichment — and to the plan handed to the FRESH re-dispatched executor, which reads the decision from disk, never from a transcript. ## HOW TO ASK (LRN-102) The harness reliably renders only the turn's FINAL text; text printed before a tool call may be swallowed. So: - up to 4 questions → one `AskUserQuestion` call; option descriptions carry the context; print nothing the user needs before the call. - more than 4, or a list handed back for re-specification → plain text, end the turn. ## Lifecycle - **REQUEST**: immutable, for the life of the run. Never rewritten, never "cleaned up". - **CRITERIA / FILE SCOPE enrichment**: ONLY at a human gate, each added entry marked `[gated ]`. A dev subagent NEVER enriches the contract. An out-of-scope edit the dev justifies is accepted ONLY through this micro-gate: human approves → FILE SCOPE gains the entry `[gated]`; human declines → the dev removes the edit. Without this gate the dev justifies everything and scope constrains nothing. - **ABANDONMENT**: a criterion proven impossible within the authorized task is NEVER deleted and never quietly downgraded. Keep it, append `ABANDON: ` under the criteria, and name it in the final report. An abandonment is a visible handoff, not a pass: the verifier cannot return `CONFORME` while one stands, and the run cannot be described as fully complete. This is the structural half of the house rule "blocked on an independent sub-part → do the rest, state what's missing". - **Deep re-scope** (the request itself changes): NEW contract file with `supersedes: ` in its header — never a rewrite of the old one. - **Aborted run**: delete the contract file, or commit it with `status: aborted` in the header. NEVER left dirty in the working tree. - **Commit**: the contract rides the existing memory commit — `lib/capitalize-commit.md` already covers the `.claude/tasks` pathspec. No new plumbing. ## Weight per flow | Flow | Weight | |------|--------| | hotfix | Pass A silent autofill — criteria: "symptom gone; build/tests green"; scope = the 1-2 target files. Pass B runs at LOCATE against the 1-2 target files' visible effect; a typo fix asks nothing. | | feat / bugfix | Proportional. bugfix: the DIAGNOSIS feeds the criteria (symptom reproduced-then-gone + regression test present). | | ship-feature | Full. Design decisions approved at the validation gate append criteria `[gated ]` — the human validates the enriched contract, the verifier receives that version. | | init-project | Full. The interviewer's PROJECT BRIEF pours into the contract (V1 features → criteria). | | onboard | Audit-scope contract (interview answers → what to audit, which axes). | Oracles follow the same proportion. hotfix: none — that flow runs no floor (and no verifier); the hotfixer runs build/tests itself. feat / bugfix: the suite criterion at minimum, and for bugfix the regression test the DIAGNOSIS names — its `CHECK:` runs that test alone, so a green result means the reproduction actually flipped. ship-feature / init-project: build, suite, and every criterion a command can settle. onboard: audit criteria are mostly judgement — leave them oracle-free rather than invent a check that cannot fail. ## Hand-off rule Downstream consumers (plan step, dev subagents, verifier) receive the contract PATH, not a restatement of its content — the file on disk is the only authoritative copy, and reading it from disk is what makes the dev's reformulation structurally unable to interpose.