From d2a10de08bb0ec2b8da3bf151a22c6166d2a2ae4 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Sun, 19 Jul 2026 22:59:34 +0200 Subject: [PATCH] =?UTF-8?q?feat(agents):=20W4=20handover=20two-mode=20?= =?UTF-8?q?=E2=80=94=20synthesize=20opus=20/=20render=20sonnet,=20run-scop?= =?UTF-8?q?ed=20draft=20handoff=20(BDR-077)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handover-doc-writer: MODE synthesize (model="opus" call-site — STEP 9/10/12 → .audit/handover-draft-.md + DRAFT COMPLETE sentinel) / MODE render (sonnet pin — STEP 13-16 from the draft, fail-closed on absent/mismatched RUNID). Mode-based, not a file split: the §9 name+dispatch census locks survive untouched. client-handover-writer 9.6 dispatches twice with the FULL PACKAGE both times (LRN-126) + RUNID mint + post-run draft cleanup. In-wave smokes PASSED disk-verified: draft written+sentinel+gitignored; render BLOCKED on wrong RUNID (no phantom synthesis); render consumed draft + honored skip-write, report grammar intact. Census §17 (111 pass), make test exit 0. --- agents/client-handover-writer.md | 32 ++++++++++++++++++++++++++++---- agents/handover-doc-writer.md | 31 ++++++++++++++++++++++++++++++- lib/tests/model-routing.test.sh | 9 +++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/agents/client-handover-writer.md b/agents/client-handover-writer.md index 77f91f9..6d0697a 100644 --- a/agents/client-handover-writer.md +++ b/agents/client-handover-writer.md @@ -1072,11 +1072,30 @@ If `OUTPUT` resolved to `skip-write`, still dispatch — the doc-writer reports `MD: skipped` and stops before rendering, per its own contract. -Dispatch: +Dispatch the two-mode pipeline (BDR-077 — synthesis on opus, render on the +sonnet pin, full PACKAGE both times per LRN-126). Mint a RUNID first +(`RUNID=$(date +%s)`); the draft crosses via the run-scoped, gitignored +`.audit/handover-draft-.md`; clean it after 9.7. + +FIRST — synthesize: + +``` +Agent(subagent_type="handover-doc-writer", model="opus") +prompt: "MODE: synthesize +RUNID: +PACKAGE: +" +``` + +Parse its `SYNTH REPORT`: `STATUS: BLOCKED` → surface verbatim, stop (do +not patch the PACKAGE silently); malformed/mute → retry ONCE fresh, then +escalate. `STATUS: DONE` → THEN render: ``` Agent(subagent_type="handover-doc-writer") -prompt: "PACKAGE: +prompt: "MODE: render +RUNID: +PACKAGE: LANG: PROJECT: name= root= type= sub-type= is_local_business= deployed_url= period= @@ -1092,10 +1111,15 @@ PRECHECK_DONE: CLIENT_NAME: OUTPUT: | versioned | skip-write> -Synthesize + write + render the deliverable per your steps. Report the -HANDOVER-DOC REPORT." +Render the deliverable from the draft per your render-mode steps. Report +the HANDOVER-DOC REPORT." ``` +(The PACKAGE block is IDENTICAL in both dispatches — write it once, +paste it twice. A render `STATUS: BLOCKED` on draft absence/RUNID +mismatch means the synthesize leg failed silently: re-run 9.6 from the +synthesize dispatch, never hand-write the draft.) + ### 9.7 — Parse the report, tell the user Parse the returned `HANDOVER-DOC REPORT`: diff --git a/agents/handover-doc-writer.md b/agents/handover-doc-writer.md index a2a1da3..298881c 100644 --- a/agents/handover-doc-writer.md +++ b/agents/handover-doc-writer.md @@ -1,6 +1,6 @@ --- name: handover-doc-writer -description: Deliverable writer — dispatched by client-handover with a resolved PACKAGE. Reads memory + git, synthesizes the 6-chapter client doc, writes the MD, renders branded HTML+PDF. No audits, no questions, no dispatch. +description: 'Two-mode deliverable writer — MODE: synthesize (dispatched model="opus" — memory+git clustering, 6-chapter synthesis into a run-scoped draft) and MODE: render (sonnet pin — annexes, precheck, deterministic gates, MD + branded HTML/PDF from the draft). Dispatched twice by client-handover with the resolved PACKAGE. No audits, no questions, no dispatch.' tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch model: sonnet --- @@ -43,6 +43,29 @@ name the missing field. --- +## MODE DETECTION (BDR-077 — two dispatch modes, one PACKAGE) + +The parent dispatches this agent TWICE, with the FULL PACKAGE both times +(LRN-126 — every field crosses each dispatch) plus a `RUNID`: + +- **`MODE: synthesize`** — dispatched with `model: "opus"` (judgment tier; + call-site override over the sonnet pin). Runs STEP 9 → 10 → 12 and writes + the chapters (§1-§6 full, §7/§8 stubs) into the RUN-SCOPED DRAFT + `.audit/handover-draft-.md`, ending the file with the line + `DRAFT COMPLETE — RUNID: `. Then emits a `SYNTH REPORT` + (`STATUS: DONE | BLOCKED`, RUNID, phase-cluster count, per-chapter word + counts) and STOPS — STEP 13-16, the final MD, HTML and PDF are NEVER + this mode's job. +- **`MODE: render`** — runs on the sonnet frontmatter pin. FIRST loads the + draft: absent file, RUNID mismatch, or missing `DRAFT COMPLETE` sentinel + → `STATUS: BLOCKED` naming the cause (fail closed — never synthesize a + missing draft, never render a partial one). Then runs STEP 13 → 14 → + 14.5 → 15 → 16 on the draft + PACKAGE and emits the `HANDOVER-DOC + REPORT`. `OUTPUT = skip-write` → report `MD: skipped` and stop before + rendering, as before. + +--- + ## STEP 9 — LOAD MEMORY REGISTRIES ```bash @@ -452,6 +475,12 @@ des audits de santé. Pour toute question, contactez [contact].* --- +> **MODE BOUNDARY.** STEP 12 is the last synthesize-mode step: write the +> drafted chapters to `.audit/handover-draft-.md` (+ the +> `DRAFT COMPLETE — RUNID: ` terminal line), emit the SYNTH +> REPORT, stop. Everything below (STEP 13-16) is `MODE: render` and +> operates ON that draft. + ## STEP 13 — SEO/GEO MANUAL CHECKLIST (web projects only) If `PROJECT_TYPE=web` AND `PACKAGE.SKIP_SEO` is not `yes`, append this chapter diff --git a/lib/tests/model-routing.test.sh b/lib/tests/model-routing.test.sh index 069db1a..c502fd7 100755 --- a/lib/tests/model-routing.test.sh +++ b/lib/tests/model-routing.test.sh @@ -131,6 +131,15 @@ lacks "skills/onboard/SKILL.md" 'Load `$HOME/.claude/agents/onboard has "skills/commit-change/SKILL.md" 'model="opus"' has "agents/commit-changer.md" 'MODE: propose' has "agents/commit-changer.md" 'model: sonnet' +# 17) BDR-077 W4 — handover two-mode: synthesize = opus at the call site +# (STEP 9/10/12 → run-scoped .audit/ draft + DRAFT COMPLETE sentinel), +# render = sonnet pin (STEP 13-16, fail-closed on absent/mismatched +# draft). Name + dispatch-string locks of §9 survive untouched. +has "agents/handover-doc-writer.md" 'MODE: synthesize' +has "agents/handover-doc-writer.md" 'MODE: render' +has "agents/handover-doc-writer.md" 'DRAFT COMPLETE' +has "agents/client-handover-writer.md" 'MODE: synthesize' +has "agents/client-handover-writer.md" 'handover-doc-writer", model="opus"' printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail" [ "$fail" -eq 0 ]