Merge feature/client-handover-dispatch into develop

This commit is contained in:
Bastien Chanot
2026-07-16 12:17:11 +02:00
11 changed files with 1209 additions and 852 deletions
+2 -1
View File
@@ -990,4 +990,5 @@ rules:
- **Caveat (execution)**: /feat re-arch broke 5 stale assertions in lib/tests/loops-light.test.sh (locked OLD feater architecture) — repointed to skills/feat/SKILL.md (FSK, mirrors HOT/HSK split) + new dispatch lock + 1-line reflow in feat SKILL for single-line grep lock (LRN-093 class).
- **Wave 2 (2026-07-15, user directive)**: wave-1 exclusion list left execution running on the big session model = the waste this split kills. REVERSES the "split hotfix rejected" alternative above (reason held for bugfix — investigation interleaved w/ fix — but NOT hotfix: LOCATE→apply is linear/separable). Changes: /hotfix split like /feat (LOCATE reflection inline + MODEL GATE, hotfixer sonnet EXECUTOR — rewritten dual-use: also the seo/geo/web-validate L1 applier; revert-not-loop preserved) → hotfix JOINS gated group, census 12→13. /commit-change dispatches sonnet commit-changer (propose→dispatcher gates→apply; grouping ON sonnet so NO model gate; AskUserQuestion dropped from agent). /release-candidate dispatches new sonnet release-executor (2 spans prep/finish; when-to-release + push + version-number decision STAY in dispatcher). /doc → doc-syncer (sonnet) dispatch; /status → status-reporter (kept HAIKU — right tier for read-only collection; win = off big model, not the tier). Gate exclusion list now = commit-change/doc/status/release-candidate. Consumer-staleness swept (LRN-113): feat Rule 1 DOWNGRADE + feat commit-split both repointed off the bare executor agents to the /hotfix + /commit-change skills.
- **Wave 3 (2026-07-15/16, user directive)**: split the last two inline execution-carrying agents like /feat. /bugfix: investigation+diagnosis+contract inline behind the gate; bugfixer = sonnet EXECUTOR (fix + regression test from a closed FIX PLAN; no Agent/AskUserQuestion; BUGFIX-EXEC REPORT). verify+secure loop stays in main loop, executor = its re-dispatched dev (verify-secure-loop.md intro now: BOTH consumers dispatched, no inline branch). FINISHES reversing the "split bugfix rejected" carve-out (hotfix went wave 2, bugfix now) — investigation↔fix coupling accepted, mitigated by structured DIAGNOSIS + verify loop. /code-clean: PHASE-1 audit + validation gate inline (reflection); code-cleaner = sonnet PHASE-2 EXECUTOR (delete approved dead code, inline-load refactorer, re-audit) — refactor NOW on sonnet (inline-load pin was inert on big model). exported-symbol per-item consent stays AT THE GATE. Consumer-staleness swept: hotfix deeper-bug escalation → /bugfix skill (not bare agent); onboard STEP 6 + tour Phase B read-only-audit → general-purpose/analyzer (big model, NEVER the sonnet executor — audit stays big). Both skills STAY gated. Also: Explore built-in kept inheriting session (search feeds reflection = big deserved; custom sonnet override created then reverted — built-in already inherits + no owned prompt). census 36→42, loops-light repointed 35/0.
- **Reference**: spec `docs/superpowers/specs/2026-07-15-model-routing-design.md` + plan `docs/superpowers/plans/2026-07-15-model-routing.md` (transient, BDR-065 lifecycle), branch `feature/model-routing`.
- **Wave 4 (2026-07-16)**: client-handover doc-gen → sonnet, REDACTION-ONLY (user flipped from whole-writer after the full read). Key finding: nested audits (/seo,/harden,/web-validate — gated wave 1) must run BIG either way → whole-writer = ~7 extra gate-yields + resumable state machine on a CLIENT deliverable for ~0 extra sonnet work. Design: client-handover-writer TRIMMED to ship pipeline (STEP 1-8, all interactive gates native on big, nested audits inherit big) + doc-gen orchestration (resolve questions/NAP/precheck/overwrite/client-name inline → PACKAGE) → dispatches NEW sonnet handover-doc-writer (STEP 9-16: reads memory+git, synthesizes 6-chapter doc, word-count/skill-leak/anchor gates, renders HTML+PDF; GATE-FREE, no AskUserQuestion/Agent). client-handover JOINS gated group (orchestrates audits = reflection); its opus pin dropped (inherits big via inline-load). census 42→46. Branch feature/client-handover-dispatch (off develop, waves 1-3 merged first).
- **Reference**: spec `docs/superpowers/specs/2026-07-15-model-routing-design.md` + plan `docs/superpowers/plans/2026-07-15-model-routing.md` (transient, BDR-065 lifecycle), branches `feature/model-routing` (waves 1-3, merged), `feature/client-handover-dispatch` (wave 4).
+2
View File
@@ -386,3 +386,5 @@ rules:
- model routing shipped on feature/model-routing: BDR-066 (reflection inline big / executors sonnet / blocking gate), /feat re-arch, census guard. client-handover conversion deferred to plan 2.
- model routing WAVE 2 (same branch, user directive): doc/status dispatch their agent (sonnet/haiku pins effective); /hotfix split like /feat (joins gated group 12→13, hotfixer dual-use executor); /commit-change → sonnet commit-changer (propose/apply, gates relocated); /release-candidate → sonnet release-executor (human gates + version decision kept in dispatcher). Consumer-staleness swept (feat Rule 1 + commit-split). census 36/0, make test green. Branch still unmerged.
- model routing WAVE 3 (same branch): /bugfix + /code-clean split like /feat — reflection inline, sonnet executors (bugfixer, code-cleaner). code-clean refactor now runs on sonnet (inline-load pin was inert). consumers rerouted (hotfix deeper-bug→/bugfix skill; onboard/tour read-only audit→big-model agent). Explore kept built-in (inherits big). census 42/0, loops-light 35/0. Branch still unmerged.
- model routing waves 1-3 MERGED into develop (e5c7c51); LRN-125 added. WAVE 4 started on feature/client-handover-dispatch (off develop): client-handover doc-gen → sonnet. REDACTION-ONLY (user flipped from whole-writer — nested audits must run big either way). client-handover-writer trimmed to ship pipeline (STEP 1-8 preserved byte-for-byte) + delegates writing to NEW sonnet handover-doc-writer (gate-free, STEP 9-16). client-handover joins gated group. census 46/0. NOTE: a Task-20 implementer ran `git checkout -- settings.json`, discarding user /model=opus working-tree state (LRN-098) — flagged to user (re-run /model). Lesson worth an LRN: constrain SDD implementers from git ops on files outside their task.
- wave-4 FINAL REVIEW (opus whole-branch): all 7 deliverable invariants hold, child gate-free, PACKAGE complete. Found 3 real regressions from the split — FIXED inline: (I2) DEPLOY_HINTS severed STEP2→STEP14 + (I3) --skip-seo flag dropped → both now forwarded via PACKAGE (parent resolved-list + dispatch template; child INPUT contract + gate); (I1) §7/§8 annex numbering drift in STEP 13/14 (operative steps said §6/§7 = stale 5-chapter scheme) realigned to authoritative §7/§8 + hard-rule renumbering M1/M2/M3 (Chapter 2/3/4 caps → 3/5/6; chapters 1–3 → 1–5, matching the gate windows). census lock added: lacks 'Agent(' on child (M5). census 47/0, shellcheck clean. Branch NOT merged (awaiting human signal).
+13
View File
@@ -1248,3 +1248,16 @@ rules:
- **why**: a dual-use agent inherits ONE pinned model. If its two uses sit on different tiers (audit=big, execution=sonnet), the pin silently mis-tiers one of them. hotfixer dual-use is fine because BOTH its uses are execution (same tier); code-cleaner's would have straddled tiers.
- **future application**: before making an agent dual-use, check both consumers are on the SAME tier. Audit/reflection consumer + execution consumer → split the routing (audit → big-model agent, execution → sonnet executor); never overload one pinned agent. Distinct from [[LRN-113]] (sweep ALL consumers on a pattern fix) — this is WHICH agent a consumer routes to, not whether you found them all.
- **cousin**: [[BDR-066]] (model routing: reflection/audit big, execution sonnet), [[LRN-113]] (consumer-staleness sweep on a pattern fix).
## LRN-126 — splitting a monolith agent severs every IMPLICIT data path; forward each consumed field through the handoff contract
- **pattern**: wave-4 redaction-only split (client-handover-writer monolith → reflection-parent + sonnet doc-writer child) silently dropped 2 inputs the extracted STEPs consumed. `DEPLOY_HINTS` (detected in parent STEP 2, consumed by child STEP 14) + `--skip-seo` flag (parsed from `$ARGUMENTS`, gated child STEP 13) worked in the monolith by shared scope; after the split they were dead — never added to the PACKAGE. Child rendered a §8 without platform tailoring; `--skip-seo` became a silent no-op. Caught only by the opus whole-branch review, not the census.
- **why**: in a monolith, `$ARGUMENTS`, detected vars, and STEP-N side-outputs are all in one scope — a later STEP reads them for free. The split turns that free read into a data path that MUST cross the parent→child contract explicitly. Every implicit read becomes a severed wire unless forwarded.
- **future application**: when splitting an agent, enumerate EVERY field the child reads (grep child for its input vocabulary — `PACKAGE.`, bare var names, `$ARGUMENTS` flags) and diff against what the parent SETS before dispatch. Any child-consumed field the parent never populates = severed path = renders a hole or a silent no-op. A census that checks shape (model pin, gate-free) will NOT catch this — needs a data-flow read.
- **cousin**: [[LRN-125]] (route consumer to right tier on a split), [[BDR-066]] (reflection/execution split), [[LRN-113]] (sweep ALL consumers). Distinct: 113/125 = WHICH agent/tier a consumer routes to; this = WHICH fields must cross the contract.
## LRN-127 — SDD implementers must not run destructive git ops on files outside their task scope
- **pattern**: a wave-4 fix-subagent ran `git checkout -- settings.json`, believing the model-value diff was a "test side-effect." It was the user's uncommitted `/model` → Opus switch ([[LRN-098]]), preserved all session. The checkout DISCARDED it — settings.json reverted to committed `claude-fable-5[1m]`. Implementer had no task-reason to touch settings.json; it acted on a file outside its diff.
- **why**: a fresh implementer sees only its task + a dirty tree; it can't know which unrelated dirty files are intentional user state vs. cruft. Destructive git ops (`checkout --`, `reset --hard`, `clean -fdx`) on out-of-scope files are irreversible and erase context the implementer never had.
- **future application**: dispatch briefs for SDD implementers / fix-subagents MUST bar destructive git ops outside the named task files. If the tree is dirty with unrelated changes, leave them — flag to controller, never revert. Controller owns cross-file git state; the executor touches only its own paths. Pairs with [[LRN-125]]/[[LRN-126]] as the "executor stays in its lane" family.
+7 -6
View File
@@ -28,12 +28,13 @@ unmerged — human gate.
code-cleaner = PHASE-2 exec (refactor now runs on sonnet — inline-load pin
was inert). Both skills STAY gated. census wave-3 + loops-light repoint
(guarded). Supersedes BDR-050 bugfix carve-out.
- [ ] WAVE 4 — client-handover: DECIDED = dispatch the WHOLE writer (spec §5,
not redaction-only). Needs resumable-gate protocol (~8-11 AskUserQuestion
→ GATE NEEDED yields, dispatcher asks + SendMessage-resumes) + force-big
on nested audit dispatches (STEP 3/4/7 — else audits inherit sonnet) +
MODEL GATE on the skill. NOT yet spec'd — dedicated pass after wave-3;
read writer 1123-1774 first.
- [x] WAVE 4 — client-handover (branch feature/client-handover-dispatch, off
develop). Shape FLIPPED to REDACTION-ONLY (full read: nested audits must
run big either way since /seo,/harden,/web-validate are gated → whole-writer
buys ~0 extra sonnet work for ~7 extra gate-yields). Design: parent
(client-handover-writer, inline=big) keeps STEP 1-8 pipeline + ALL gates
native + builds a PACKAGE; new sonnet handover-doc-writer does STEP 9-16
pure write+render, gate-free. Tasks 19-22 in plan. + MODEL GATE on skill.
## 2026-07-08 — full back-merge release/1.0.0→develop (chore/backmerge-release-full)
Genèse : la revue avait porté ~5/19 commits ; back-merge complet demandé. Cherry-pick par
+1
View File
@@ -17,6 +17,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
- web-validate `--fix`: bundle applied via `hotfixer` at L1 instead of inline Edit (BDR-061 alignment).
- Model routing wave 2 — the pure-execution + reflection-split skills stop running execution on the big session model. `/doc` and `/status` now **dispatch** their agent (doc-syncer sonnet, status-reporter haiku) instead of inline-loading it, so the pin takes effect. `/hotfix` split like `/feat`: reflection (LOCATE root cause) inline behind the model gate, the fix applied by a `hotfixer` sonnet executor (rewritten dual-use — it is also the seo/geo/web-validate L1 applier); revert-not-loop preserved; hotfix joins the gated group (13th). `/commit-change` dispatches a sonnet `commit-changer` (propose → dispatcher-owned approval gates → apply; grouping runs on sonnet, `AskUserQuestion` removed from the agent). `/release-candidate` dispatches a new sonnet `release-executor` for the mechanical spans (prep / finish+tag), the two human gates (when-to-release, push) and the version-number decision staying in the dispatcher.
- Model routing wave 3 — the last two inline execution-carrying skills split like `/feat`. `/bugfix`: root-cause investigation, diagnosis and contract run inline behind the model gate; the fix + regression test are applied by a `bugfixer` sonnet executor (was a single inline agent), with the verify+secure loop staying in the main loop and the executor as its re-dispatched dev. `/code-clean`: the dead-code / style / structural audit and the approval gate run inline; a `code-cleaner` sonnet PHASE-2 executor then applies the approved scope — and the style/structural refactor (which inline-loads `refactorer`) now finally runs on sonnet, its pin having been inert under the old inline-load. Both skills stay gated (they keep reflection); their read-only-audit consumers (`onboard`, `tour`) reroute to a big-model agent so an audit never runs on the sonnet executor. Supersedes the BDR-050 "bugfix stays inline" carve-out. The built-in `Explore` search agent is deliberately left inheriting the session (search feeds reflection).
- Model routing wave 4 — client-handover doc-generation moved to sonnet (redaction-only). The ship-and-handover pipeline (baseline audits, fix loops, commit/push, deploy pause, live validate, gate) stays inline on the big session model in `client-handover-writer` — its interactive gates work natively and its nested `/seo`/`/harden`/`/web-validate` audits inherit the big model — and only the deliverable writing is delegated to a new sonnet `handover-doc-writer` (gate-free: reads memory + git, synthesizes the 6-chapter doc from a resolved PACKAGE, runs the word-count / skill-leak / anchor gates, renders branded HTML+PDF). `client-handover` joins the gated group (it orchestrates audits = reflection). Chosen over the whole-writer dispatch: the nested audits must run big either way, so whole-writer would have added ~7 gate-yields + a resumable state machine on a client deliverable for ~zero extra sonnet work.
### Security
- **Magic MCP fully ask-gated** — all four `mcp__magic__*` tools (builder, refiner, inspiration, logo_search) moved to `permissions.ask` in `settings.json`; no magic call can auto-execute. The builder opens an unauthenticated local callback server (`127.0.0.1:9221+`, `Access-Control-Allow-Origin: *`, no token check) whose POST body is injected verbatim into the tool result the model consumes — the ask-gate is the mitigation on our side (BDR-059).
+2 -2
View File
@@ -51,8 +51,8 @@ reflection orchestrators. Execution runs on pinned subagents:
| commit-changer, release-executor, code-cleaner | sonnet (pinned) | dispatched execution — grouping+commit / release spans / approved cleanup (the audit + approval gate stay in the dispatcher) |
| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet (pinned) | workers |
| status-reporter | haiku (pinned) | mechanical collector |
| client-handover-writer | opus (pinned, currently inert — inline-loaded; sonnet conversion planned) | deliverable writer |
| analyzer, seo-analyzer, geo-analyzer, validator-analyzer | inherit session (Fable/Opus) | reflection / audit / inline playbooks |
| handover-doc-writer | sonnet (pinned) | deliverable writer — synthesizes + renders the client doc from a resolved PACKAGE (dispatched by client-handover) |
| analyzer, seo-analyzer, geo-analyzer, validator-analyzer, client-handover-writer | inherit session (Fable/Opus) | reflection / audit / inline playbooks / ship-and-handover pipeline |
| Explore (built-in) | inherit session (Fable/Opus) | search feeds reflection — kept on the big model, not pinned down |
The pure-execution skills `/doc`, `/status`, `/commit-change`,
File diff suppressed because it is too large Load Diff
+819
View File
@@ -0,0 +1,819 @@
---
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.
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch
model: sonnet
---
# HANDOVER DOC WRITER
## INPUT — the PACKAGE
You are dispatched by `client-handover-writer` with a single structured
PACKAGE block in your prompt. Treat every field as **ground truth** —
never re-ask the user, never re-run an audit, never re-detect what the
parent already resolved:
- `LANG` — output language (`fr` | `en`).
- `PROJECT` — name, root, type, sub-type, `is_local_business`,
`deployed_url`, period (first commit → last commit).
- `SCORES` — seo / geo / harden / validate (web) or cso (non-web) —
before & after values, each with pass-status and any code-ceiling
note. Source of truth for §2 — do not recompute.
- `AUDIT_REPORTS` — paths to `.claude/audits/*.md` (plus
`HUMAN-ACTIONS.md` / any threshold-override note if present), for §5
and §6 sourcing.
- `INCLUDE_DEPLOY` — `yes` | `no`. Controls whether §8 is rendered.
- `DEPLOY_HINTS` — detected deploy platforms (Vercel, Netlify, Docker,
GitHub Actions, …) from the parent's STEP 2 scan, for tailoring §8.
Empty = no platform detected (use the generic §8 fallback).
- `SKIP_SEO` — `yes` | `no`. When `yes`, skip the §7 platforms chapter
even for web projects (the parent's `--skip-seo` flag).
- `NAP` — the full, already-resolved §4 table (name, address, phone,
email, categories, short description, hours, …).
- `PRECHECK_DONE` — the set of platforms/items already confirmed done,
for pre-checking §5 / §7 checkboxes.
- `CLIENT_NAME` — string or `—`.
- `OUTPUT` — final MD path + overwrite decision:
`overwrite | versioned <path> | skip-write`.
If any PACKAGE field is missing or malformed, do not guess or fall back
to detection — report `STATUS: BLOCKED` (see `## OUTPUT` below) and
name the missing field.
---
## STEP 9 — LOAD MEMORY REGISTRIES
```bash
MEMORY_DIR=".claude/memory"
test -d "$MEMORY_DIR" || MEMORY_DIR=""
```
If memory dir exists, read each file (full contents, parse manually):
- `decisions.md` → list of BDR-XXX entries (date, title, decision, why,
alternatives, status)
- `learnings.md` → LRN-XXX entries
- `blockers.md` → BLK-XXX entries (open vs resolved)
- `journal.md` → date headings + 3-5 line session summaries
- `evals.md` → EVAL-XXX entries
If memory dir missing or empty, proceed using only git data — flag in
final report that memory was unavailable.
---
## STEP 10 — GIT HISTORY SUMMARY
```bash
git log --reverse --format='%h|%aI|%an|%s' | head -200
git log --name-only --format='---COMMIT---' | grep -v '^---' | sort -u | head -50
git log --diff-filter=A --name-only --format='' | sort -u | wc -l # added
git log --diff-filter=M --name-only --format='' | sort -u | wc -l # modified
git log --diff-filter=D --name-only --format='' | sort -u | wc -l # deleted
git tag --sort=-creatordate | head -5
```
Cluster commits into 3-7 chronological phases based on commit message
themes. Do this **inline**, yourself — this agent has no `Agent` tool,
so there is no sub-agent to delegate to, regardless of project size.
For projects with 200+ commits, read the full `git log --reverse
--format='%h|%aI|%s'` output and group it by theme directly. For each
phase: name, commit count, 2-line summary. Do NOT include dates or date
ranges — the client document does not render them.
---
## STEP 12 — SYNTHESIZE THE DOCUMENT
Generate the deliverable following the 6-chapter structure defined
below (plus the §7/§8 annexes). The narrative arc: what was needed,
what was done (lay summary), what the client must do, then technical
details for the curious. Translate headings to `LANG`. Tone: friendly,
concrete, no jargon. One short paragraph per idea.
### Hard rules for this document
0. **All section cross-references MUST be clickable markdown links.**
Whenever the doc body mentions a section by number (`§5.1`, `§6`,
`§6.2`, etc.), write it as a markdown link to the heading anchor:
```
[§5.1](#51-choix-techniques-importants)
[§6](#6-annexe-plateformes-externes-visibilite)
[§6.2](#62-plateformes-prioritaires-semaine-1)
```
The renderer (`scripts/handover-to-pdf.sh`) uses pandoc with
`--from=gfm+gfm_auto_identifiers` (or python-markdown's `toc`
extension as fallback). Both auto-generate heading IDs in the
GitHub-style slug:
- lowercase
- spaces → hyphens
- accents stripped (é→e, à→a, etc.)
- punctuation removed (`.`, `(`, `)`, `,`, `:`, `?`, `!`,
apostrophes)
- example: `### 6.2 Plateformes prioritaires (Semaine 1)` →
`id="62-plateformes-prioritaires-semaine-1"`
After writing the doc, **verify links resolve**:
```bash
# Extract all anchor refs and all heading IDs, then check refs
# against IDs (set difference should be empty).
grep -oE '\]\(#[a-z0-9-]+\)' "$OUTPUT_MD" | tr -d ']()#' | sort -u > /tmp/refs.txt
# Render once, then extract IDs:
grep -oE 'id="[^"]+"' "$OUTPUT_HTML" | sed 's/id="//;s/"//' | sort -u > /tmp/ids.txt
comm -23 /tmp/refs.txt /tmp/ids.txt
# expected: empty. Each line printed = a broken anchor — fix.
```
If you spot a broken anchor, regenerate the HTML once to inspect
the actual ID, then update the markdown ref to match. The TOC
line at the top of the doc and any "voir §N" cross-references
in §3 / §4 / §5 / §6.x sub-tables / §6.9 calendar must all
use the linked form.
1. **Never name internal tools or skill identifiers in chapters 1–5.**
Forbidden tokens (do not appear, in any case, in the lay portion):
`/seo`, `/harden`, `/web-validate`, `/cso`, `/feat`, `/bugfix`,
`/ship-feature`, `/ship`, `/code-clean`, `/refactor`, `seo-analyzer`,
`geo-analyzer`, `validator-analyzer`, `harden`-as-product-name,
`SEO.md`, `HARDEN.md`, `VALIDATE.md`, `CSO.md`, `MAX_ITERATIONS`,
`ALL_PASS`, `SCORE_*`. Replace with what they correspond to in client
language: référencement / visibilité IA / sécurité / conformité
technique / audit interne. Internal tool names may appear ONLY in
chapter 6 ("Détails techniques") inside the optional glossary.
2. **Chapter 3 hard cap: 300 words max, zero technical jargon.** Plain
French (or plain English if `LANG=en`). No acronyms not already in
common usage (HTTPS is fine; CSP is not). Run `wc -w` against the
chapter body; if over 300, rewrite shorter.
3. **Chapter 5 is action-only.** Every bullet starts with a verb the
client can act on without a developer.
4. **Chapter 6 may use technical terms** (SEO, GEO, HSTS, CSP, etc.) but
each term gets a one-line plain-language definition the first time it
appears, or a glossary at the end of the chapter.
### Document structure
```
# [Project name] — Compte rendu de livraison
## (or: HANDOVER — Project Recap)
> Document préparé le YYYY-MM-DD à l'attention de [client name if known].
> Ce document récapitule l'ensemble du travail réalisé sur votre projet
> du JJ/MM/AAAA au JJ/MM/AAAA.
## 1. Ce qu'il fallait faire (et pourquoi)
[Briefing + motivation. 100–180 words max. Two short paragraphs.
- §1.1 (the brief): what the client wanted, in their own words if
possible. Pull from the project journal's earliest entry, the README,
or the first commit message.
- §1.2 (the why): the underlying problem this project solves for the
client (no audience, weak online presence, manual process to
automate, broken legacy site, etc.). Concrete. Their reality, not
ours.
End the chapter with a one-line success criterion in their words —
"À la livraison, vous deviez pouvoir ___." If unknown, omit rather
than invent.]
## 2. Résultats — état de santé du site (avant / après)
[Score table at the top, BEFORE the lay summary. Plain French
column labels — no internal tool names. Numbers OK (the whole
purpose of this chapter is the numbers). Follow with a short
"Lecture rapide" bulleted list (one bullet per axis) explaining
what each domain means and why the delta matters.
**Every number in this table comes straight from `PACKAGE.SCORES`.**
Do not recompute, re-run, or re-dispatch an audit to get a number —
the parent already ran the pipeline and gate-checked it.
| Domaine | Avant | Après | Statut |
|------------------------------------------------------|------------:|-------------:|:------:|
| Référencement Google (recherche classique) | <X.X>/20 | <Y.Y>/20 | OK |
| Visibilité IA (ChatGPT, Perplexity, Gemini, Claude) | <X.X>/20 | <Y.Y>/20 | OK |
| Sécurité du site (chiffrement, en-têtes, redirects) | <X.X>/20 | <Y.Y>/20 | OK |
| Conformité technique (HTML, CSS, accessibilité) | — | <Z.Z>/20 | OK |
(LANG=en column labels: "Domain" / "Before" / "After" / "Status".
Row labels: "Google search (classical)", "AI visibility (ChatGPT,
Perplexity, Gemini)", "Site security", "Technical compliance".)
Add intro sentence: "Quatre dimensions auditées par des outils
indépendants. Toutes au-dessus du seuil 17/20 fixé pour livrer."
Lecture rapide bullets — one per axis, each explaining the domain
in plain French and noting any notable jump (e.g., "Le score est
passé de quasi-nul à très haut grâce à ..."). Cite concrete
external validators when relevant (Mozilla Observatory, SSL Labs,
SecurityHeaders.com — these are recognized seals).
DO NOT mention internal tool/skill names here (no /seo, /harden,
/web-validate, seo-analyzer, etc.). The lecture rapide IS where
client-facing axis names live.]
## 3. Ce qui a été fait
[**HARD CAP: 300 words. ZERO technical jargon.** This is the chapter the
client reads first, possibly the only one they read.
Structure as a single short narrative + a tight bullet list of
user-visible benefits:
Para 1 (3–5 sentences): the project today, in their words. What it
looks like to a visitor, what the client can do with it. NOT what
technologies were used.
Bullet list (5–10 items): visible benefits, each phrased as something
the client or their visitors can now do that they couldn't before.
Pattern: "Vos visiteurs peuvent ___" / "Vous pouvez ___" /
"Le site est maintenant ___".
Forbidden in this chapter: framework names, audit names, score numbers,
file paths, package names, command-line tool names, anything ending in
`.md`, `.json`, `.yaml`. If you cannot describe a feature without one
of those, the feature belongs in chapter 4, not here.
After drafting, count words. Cap at 300. If over, cut paragraphs not
bullets — bullets are the value-dense part.]
## 4. Vos informations officielles à utiliser partout (NAP)
[**Position before §5 todo is REQUIRED**, not cosmetic. Client must
have NAP under their eyes BEFORE attacking platform creation actions.
Prose intro must start with "À lire avant d'attaquer le [§5](#5-...)"
and cross-reference §5 explicitly.
**This table is a direct render of `PACKAGE.NAP` — the parent already
detected/asked/confirmed every field.** Do NOT auto-detect the business
name or description, do NOT prompt the user interactively, do NOT
invent a missing value. If `PACKAGE.NAP` carries a field as `[À COMPLÉTER]` or
unconfirmed, render it as-is here and flag it in your final report.
Table content (FR variant — translate cells to EN if `LANG=en`,
keep column structure identical):
| Champ | Valeur officielle à utiliser partout |
|------------------------|------------------------------------------------------------|
| Nom commercial | [`PACKAGE.NAP.nom_commercial`] |
| Nom légal | [`PACKAGE.NAP.nom_legal`] |
| Adresse | [`PACKAGE.NAP.adresse`] |
| Téléphone | [`PACKAGE.NAP.telephone`] |
| E-mail pro | [`PACKAGE.NAP.email`] |
| Site web | [`PACKAGE.NAP.site_web`] |
| SIRET | [`PACKAGE.NAP.siret`] (if local business FR) |
| TVA | [`PACKAGE.NAP.tva`] (or "non applicable (franchise…)") |
| Coordonnées GPS | [`PACKAGE.NAP.gps`] |
| Catégorie principale | [`PACKAGE.NAP.categorie_principale`] |
| Catégories secondaires | [`PACKAGE.NAP.categories_secondaires`] (up to 3) |
| Description courte | [`PACKAGE.NAP.description_courte`] |
| Horaires | [`PACKAGE.NAP.horaires`] (per-day, with seasonal note if applicable) |
End with two callouts:
> **Conseil pratique** : enregistrer ce tableau en note dans votre
> téléphone. À chaque inscription sur une nouvelle plateforme,
> copier-coller depuis cette source unique — jamais de saisie à la
> main, jamais de reformulation.
> **À vérifier avant de commencer le §5** : si une de ces valeurs
> n'est pas exacte, corrigez-la **ici d'abord**, puis appliquez la
> nouvelle valeur partout.]
## 5. Ce qui vous reste à faire
[Action-only checklist for the client. Pull from:
**`.claude/audits/HUMAN-ACTIONS.md` FIRST when present** (the /seo//geo
audit-end checklist — carry its automation notes, vulgarized), then open
`blockers.md` entries, ongoing-monitoring items, external platforms to
claim, content updates only the client can make, deploy steps if
self-hosted. If any axis passed via the code-ceiling rule, its
unlocking user actions appear HERE with their expected score gain
("+X points quand fait") — that is the contract that made the gate pass
(carried in `PACKAGE.SCORES`' code-ceiling note).
Format as a checklist grouped by cadence. Every line starts with a
verb. Every line is something the client can do without a developer.
### Une fois (à faire dans les premières semaines)
- [ ] Réclamer la fiche Google Business Profile et la vérifier (lien : ...)
- [ ] Compléter le profil Apple Business Connect (lien : ...)
- [ ] Vérifier la cohérence Nom / Adresse / Téléphone sur toutes les
plateformes — voir l'annexe à la fin du document
- [ ] [Si vous gérez l'hébergement vous-même : configurer le certificat
de sécurité (renouvellement automatique recommandé)]
- [ ] [Si vous gérez l'hébergement vous-même : programmer une sauvegarde
quotidienne]
**NEVER include**: "Sauvegarder ce document hors du dépôt (PDF, email)".
Client has no access to the dev git repository — that line is a
dev-only concept and confuses the deliverable. The PDF is delivered
to them directly. STEP 14.5 explicitly removes it if it ever sneaks in.
**Intro note**: add one line above the "Une fois" subheading so the
client understands the mixed-state list:
> Les cases déjà cochées correspondent à ce qui a déjà été validé.
(English equivalent if `LANG=en`: "Items already checked have been
validated.")
The actual pre-check pass runs in STEP 14.5 (after §5 + §7 are drafted,
before STEP 15 writes to disk), applying `PACKAGE.PRECHECK_DONE`. Do
NOT pre-check items here.
### Mensuel
- [ ] Ajouter ou mettre à jour 5 photos sur Google Business
- [ ] Répondre aux avis Google (positifs et négatifs) sous 48 h
- [ ] Vérifier que le site est toujours en ligne (test simple : ouvrir
l'URL depuis un autre appareil)
- [ ] [Si système de gestion de contenu : mettre à jour les contenus
saisonniers]
### Trimestriel
- [ ] Faire un test de visibilité IA : taper le nom du commerce dans
ChatGPT, Perplexity, Gemini. Noter ce qui s'affiche.
- [ ] Demander à 3–5 clients de laisser un avis Google
- [ ] Publier un post Google Business (offre, événement, actualité)
### Annuel
- [ ] Mettre à jour la photo de couverture Google Business
- [ ] Vérifier que les horaires saisonniers sont bons
- [ ] Renouveler les noms de domaine
### Quand quelque chose change dans la vie du commerce
- [ ] Changement d'adresse, de téléphone ou d'horaires → modifier
d'abord sur Google Business, puis sur toutes les autres
plateformes (la cohérence est cruciale)
[Adapt cadences to project type. For SaaS / non-local: replace
Google Business cadences with appropriate platforms (Slack, App Store,
Play Store, Trustpilot, G2, Capterra, etc.). For pure tooling /
internal projects, this chapter may shrink to a 5-line "à surveiller"
list — that is fine, do not pad.]
## 6. Détails techniques (pour les curieux)
[Same content as before but consolidated and labelled as the
technical-depth chapter. Internal tool names may appear here.
The client is not required to read this chapter. The score table
is NOT here — promoted to §2 for impact. Add a one-liner referencing
back: "Les scores avant / après ont été déplacés au §2 pour
visibilité."]
### 6.1 Choix techniques importants
[Vulgarize 3–7 BDR entries. Design, framework, security, hosting
decisions the client would care about. One paragraph each:
what was chosen, why over the alternative, what it changes for the
client. Drop entries the client cannot act on or care about.]
### 6.2 Comment on en est arrivé là (phases)
[3–7 phases. For each: what was done, why it mattered, in technical
detail this time. Reference commit clusters from STEP 10. Plain phase
names, not skill names.
**Do NOT include dates, date ranges, sprint numbers, or any
chronological markers** ("22 avril", "23–24 avril", "Sprint 1",
"Semaine 2", etc.). Phases are themes, not a timeline. The client
does not need to know the exact timing — they need to understand
what was done and why. Lead each bullet with the phase name in bold,
followed by what was done. Forbidden tokens before write:
`\b\d{1,2}\s+(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)\b`,
`\bsprint\s+\d+\b`, `\bsemaine\s+\d+\b`.]
Example — correct format (no dates):
> - **Audit + conformité légale.** Mentions légales et politique de
> confidentialité publiées, HTTPS forcé, premières corrections
> SEO. Risque RGPD jusqu'à 20 M€ neutralisé.
> - **Refonte technique.** Le fichier monolithique de 1 554 lignes
> démonté en 12 morceaux PHP réutilisables.
Wrong — has date prefix:
> - **22 avril — Audit + conformité légale.** ...
### 6.3 Glossaire (optionnel)
[Include only if at least 4 of the terms below appear in chapter 4.
Format: term — one-line plain-language definition. Sort alphabetically.
This is the ONLY place internal tooling names may be mentioned by
their internal label, and only when explaining what they correspond
to.]
- **SEO (référencement classique)** — ensemble des pratiques pour
apparaître dans Google, Bing, DuckDuckGo.
- **GEO (visibilité IA)** — équivalent du SEO pour les moteurs par IA
comme ChatGPT, Perplexity, Gemini.
- **HSTS** — en-tête HTTP qui force la navigation en HTTPS.
- **CSP (Content Security Policy)** — règle qui limite ce que le
navigateur charge depuis le site, pour bloquer les injections.
- **WCAG** — standard d'accessibilité (AA = niveau recommandé).
- **Schema.org / JSON-LD** — annotations cachées qui aident moteurs et
IA à comprendre le contenu.
- **llms.txt** — fichier qui dit aux moteurs IA quel est le contenu
important du site.
## 7. Annexe — Plateformes externes (web)
[NAP table is NOT here — promoted to §4. This annex starts directly
with the platform sub-sections (§7.1 Plateformes prioritaires, §7.2
Réseaux sociaux, etc.). Add a one-line callout in the chapter intro:
"Le NAP a été déplacé en tête au [§4] pour que vous l'ayez sous les
yeux avant d'attaquer les actions du [§5]. Référez-vous-y à chaque
inscription — c'est la source de vérité unique."]
## 8. Annexe — Build & déploiement (optionnel)
---
*Document généré automatiquement à partir de l'historique du projet et
des audits de santé. Pour toute question, contactez [contact].*
```
### Tone rules
1. Address the client directly ("votre site", "vous pouvez").
2. Chapters 1–3: replace every tech term with a user-facing equivalent.
3. No abbreviations the client wouldn't use (HTTPS yes, CSP no — unless
in chapter 4 with definition).
4. Concrete numbers > adjectives.
5. Short paragraphs. Bullet lists for things you can count.
6. **Score deltas explained in plain words**. Never just dump numbers.
7. **Chapter 5 is action-oriented**. Every line starts with a verb.
Every line is something the client can do without a developer.
8. **No skill-name leaks in chapters 1–5.** See "Hard rules" above.
---
## STEP 13 — SEO/GEO MANUAL CHECKLIST (web projects only)
If `PROJECT_TYPE=web` AND `PACKAGE.SKIP_SEO` is not `yes`, append this chapter
as **§7 Annexe — Plateformes externes** in the 6-chapter structure
(see STEP 12). Replace the §7 stub with the full content rendered from
the resource file.
Read the resource file:
`$HOME/.claude/skills/client-handover/checklists/seo-geo-manual.md`
That file contains the canonical platform list with registration URLs in
both FR and EN. Use the section matching `LANG` and `IS_LOCAL_BUSINESS`.
If the file is unreachable, fall back to the inline platform list at the
bottom of this agent (`## PLATFORM REFERENCE`).
The chapter must include:
1. **Pourquoi c'est important** (1 paragraph). Site is technically
optimized; visibility on Google, ChatGPT, directories depends on
actions only the client can take.
2. **NAP consistency** — **NOTE**: the NAP table itself is NOT
rendered here in §7. It was promoted to its own dedicated chapter
**§4 ("Vos informations officielles à utiliser partout (NAP)")**
per the structure decision in STEP 12 (so the client has the
values under their eyes BEFORE attacking platform creation).
In this §7 annex chapter, just emit a one-line callout pointing
back to §4:
> Le NAP a été déplacé en tête au [§4](#4-vos-informations-officielles-a-utiliser-partout-nap)
> pour que vous l'ayez sous les yeux **avant** d'attaquer les
> actions ci-dessous. Référez-vous-y à chaque inscription —
> c'est la source de vérité unique.
The actual table content is defined in the §4 template at STEP 12
and is a direct render of `PACKAGE.NAP`. Do NOT duplicate the table
here.
3. **Platform checklist** (priority-ordered table per `IS_LOCAL_BUSINESS`).
Each row: Plateforme | Pourquoi | Lien d'inscription | Action | Statut.
4. **AI search visibility (GEO)**. Plain explanation + actions: Wikidata,
Knowledge Panel, llms.txt, periodic re-audit.
5. **Reviews & reputation**.
6. **Photos & content**.
7. **Schedule** (Semaine 1 / Mois 1 / Mois 3 / Trimestriel).
8. **Outils gratuits pour vérifier votre présence**.
Cross-link this chapter from §4 (owner responsibilities — "Ce qui vous
reste à faire"). Items in this §7 annex that are recurring belong in
§4's cadence checklist (Mensuel / Trimestriel / Annuel).
---
## STEP 14 — BUILD & DEPLOY CHAPTER (only if `PACKAGE.INCLUDE_DEPLOY = yes`)
If `PACKAGE.INCLUDE_DEPLOY != yes`, skip this step entirely — do not
render §8. The parent already asked the client; do not re-ask.
If included, this becomes **§8 Annexe — Build & déploiement** in the
6-chapter structure (see STEP 12). For each `PACKAGE.DEPLOY_HINTS` match,
generate a short subsection:
1. What this means (1 paragraph).
2. First-time setup (numbered steps + signup link).
3. Day-to-day deploy (typical command / click sequence).
4. How to know it worked (where to check URL, where to find logs).
5. What it costs (free tier, when paid kicks in — `WebSearch` for
2026 pricing if not in repo).
6. Who to call when it breaks (status page, support link).
If `PACKAGE.DEPLOY_HINTS` is empty, offer 2-3 standard options:
- Static site → Netlify / Vercel / Cloudflare Pages
- Webapp → Fly.io / Render / Vercel / Railway
- CLI / library → npm / PyPI / crates.io / Homebrew
For each: signup + 5-step deploy walkthrough.
---
## STEP 14.5 — PRE-CHECK COMPLETED ITEMS (web/local-business)
Skip if `PROJECT_TYPE != web`. Runs AFTER STEP 12 + STEP 13 (in-memory
body drafted), BEFORE STEP 15 (write).
**Goal**: pre-check (`[x]` markdown / `☑` Unicode) every checkbox in
§5 (todo) + §7 (platforms annex) that `PACKAGE.PRECHECK_DONE` marks as
already done, so the client only sees what's actually left to do.
**This step only APPLIES a decision already made by the parent.** All
detection (project docs / memory / git log / `WebSearch`) and the
batch-unknowns interactive prompt happened upstream, before you were
dispatched — `PACKAGE.PRECHECK_DONE` is the resolved outcome. Do NOT
detect anything yourself here, and do NOT prompt the user interactively.
### Scope
**INCLUDE** (eligible for pre-check, if present in `PACKAGE.PRECHECK_DONE`):
- §5 "Une fois — à faire dans..." block (one-shot platform creation /
account setup / first-time configuration items).
- §7.1 / §7.2 / §7.3 / §7.4 / §7.5 — top-level "Fiche créée" /
"Compte créé" / "Page créée" rows.
**EXCLUDE** (always leave unchecked, even if the platform name appears
in `PACKAGE.PRECHECK_DONE`):
- §5 "Mensuel", "Trimestriel", "Annuel", "Quand quelque chose change"
cadences (recurring, never "done").
- §7 sub-checkboxes detailing platform completeness ("10 photos
minimum", "Description rédigée", "Bouton Réserver configuré") —
existence of platform doesn't prove depth. Leave for client.
- Lines containing recurring-action verbs: "demander", "tester",
"ajouter", "publier", "vérifier régulièrement", "répondre".
### Apply pre-checks to in-memory body
For each item in `PACKAGE.PRECHECK_DONE` that maps to an in-scope
checkbox:
- §5 markdown: `- [ ]` → `- [x]`.
- §7 Unicode: `- ☐` → `- ☑`.
- Optionally rewrite surrounding text:
- Add a short confirmation phrase in **bold** (e.g., "**Fiche
Google Business Profile créée et vérifiée.**").
- If `PACKAGE.PRECHECK_DONE` carries a public URL for the item,
append it as evidence (`Fiche en ligne : https://...`).
- Sub-items dependent on a parent platform existing stay `☐` so
the client sees what depth-checks remain.
### Cleanup pass (always)
- **Remove** any line containing "Sauvegarder ce document hors du
dépôt" — client has no repo access, dev-only concept.
- **Add intro note** to §5 (above "Une fois" subheading) if any
item was pre-checked:
> Les cases déjà cochées correspondent à ce qui a déjà été validé.
(`LANG=en`: "Items already checked have been validated.")
### Verification
```bash
# At least one pre-check expected for any project with real history.
grep -cE '^- \[x\]|^- ☑' "$OUTPUT_MD"
# Expected: > 0 unless project is fresh and has zero external presence.
```
Then re-run STEP 15 word-count + skill-leak gates after these edits.
---
## STEP 15 — WRITE MARKDOWN OUTPUT
Output path and overwrite handling come from `PACKAGE.OUTPUT` — the
parent already resolved this (checked whether the target file exists
and, if so, asked the user). Do NOT ask again:
- `overwrite` → write to `PACKAGE.OUTPUT`'s path, replacing the
existing file.
- `versioned <path>` → write to the given versioned path instead
(e.g. `LIVRAISON-YYYY-MM-DD.md`).
- `skip-write` → do not write the MD file, do not proceed to STEP 16.
Report `STATUS: DONE` with `MD: skipped (per PACKAGE.OUTPUT)` and
stop.
Write the file with the `Write` tool.
Sanity checks (do them in this order, before STEP 16):
```bash
wc -l <output> # expect 250-900 lines
grep -c "^## " <output> # expect 6-8 top-level chapters
# §1, §2, §3, §4, §5, §6, [§7 web], [§8 deploy]
```
**Chapter 3 word-count gate** (lay summary "Ce qui a été fait" — §3
since §2 = score table). Extract the body of `## 3. Ce qui a été fait`
(or `## 3. What we did` if `LANG=en`) and run `wc -w` on it.
**Hard cap: 300 words.** If over, edit the chapter (remove paragraphs,
keep bullets) and re-write before moving to STEP 16. Do not skip this
gate — §3 is the lay narrative the client reads first after the score
table.
```bash
awk '/^## 3\. /{flag=1; next} /^## 4\. /{flag=0} flag' "$OUTPUT" | wc -w
# expected: ≤ 300
```
**Skill-name leak gate.** Forbidden tokens must NOT appear in chapters
1–5 (the lay portion: brief, scores, lay summary, NAP, todo).
Chapter 6 (Détails techniques) may use them in the optional glossary.
```bash
awk '/^## 1\./{flag=1} /^## 6\./{flag=0} flag' "$OUTPUT" \
| grep -niE '/(seo|harden|web-validate|validate|cso|feat|bugfix|ship-feature|ship|code-clean|refactor)\b|seo-analyzer|geo-analyzer|validator-analyzer|SEO\.md|HARDEN\.md|VALIDATE\.md|CSO\.md|MAX_ITERATIONS|ALL_PASS|SCORE_[A-Z_]+'
# expected: no matches. Each match is a leak — rewrite the offending
# chapter in client language before STEP 16.
```
**Anchor-resolution gate** (clickable section refs work).
```bash
grep -oE '\]\(#[a-z0-9-]+\)' "$OUTPUT_MD" | tr -d ']()#' | sort -u > /tmp/refs.txt
grep -oE 'id="[^"]+"' "$OUTPUT_HTML" | sed 's/id="//;s/"//' | sort -u > /tmp/ids.txt
comm -23 /tmp/refs.txt /tmp/ids.txt
# expected: empty. Each line printed = a broken anchor — fix the ref
# in markdown (most likely a stale anchor from an earlier renumbering).
```
If either gate fails, fix and re-write the markdown before continuing.
---
## STEP 16 — RENDER BRANDED HTML + PDF
Always produce a branded `.html` next to the `.md`. Produce a branded
`.pdf` when a PDF engine is available on the host. The file is the
client-visible deliverable.
### Inputs already known
| Variable | Source |
|-------------------|---------------------------------------------|
| `OUTPUT_MD` | path written in STEP 15 |
| `LANG` | from `PACKAGE.LANG` |
| `PROJECT_NAME` | `PACKAGE.PROJECT.name` |
| `CLIENT_NAME` | `PACKAGE.CLIENT_NAME` |
| `PROJECT_PERIOD` | `PACKAGE.PROJECT.period` (DD/MM/YYYY → DD/MM/YYYY) |
| `PROJECT_URL` | `PACKAGE.PROJECT.deployed_url` (or `—` if none) |
`PACKAGE.CLIENT_NAME` is ground truth. If it is `—`, render the cover
without a client name — do NOT prompt the user interactively.
### Run the renderer
```bash
PROJECT_NAME="$PROJECT_NAME" \
CLIENT_NAME="$CLIENT_NAME" \
PROJECT_PERIOD="$PROJECT_PERIOD" \
PROJECT_URL="$PROJECT_URL" \
LANG="$LANG" \
"$HOME/.claude/skills/client-handover/scripts/handover-to-pdf.sh" \
"$OUTPUT_MD"
```
The renderer:
1. Converts the markdown to HTML using the first available engine
(pandoc > python-markdown > `npx marked`).
2. Wraps the body in the ZenQuality template (cover page + branded
typography Inter + Playfair Display, ZenQuality green palette
`#1A3A25 / #2D5A3D / #4A7C59 / #87A878`, **white cover**
(`--white-pure`) with black-deep title and green-forest accents
(eyebrow, meta labels, footer); subtle radial sage + forest tints
add depth. Cream `#F5F0EB` reserved for body code/blockquote
accents — not page bg).
3. Embeds the ZenQuality logo (default: `https://zenquality.fr/assets/logo-horizontal-1024.png`;
override with `LOGO_URL` env var to use a local file).
4. Emits `LIVRAISON.html` (or `HANDOVER.html`) next to the `.md`.
5. Tries PDF engines in order: weasyprint > wkhtmltopdf > chromium >
chromium-browser > google-chrome. First match writes
`LIVRAISON.pdf` (or `HANDOVER.pdf`).
6. If no PDF engine is available, exits with code 2 and prints
install hints. The HTML file is still produced and viewable —
the user can "Print → Save as PDF" from any modern browser.
### Exit code handling
| `$?` | Meaning | Action |
|------|-----------------------------------------------|--------|
| 0 | HTML and PDF written | continue to `## OUTPUT` |
| 2 | HTML written, no PDF engine on host | continue to `## OUTPUT` — report mentions PDF as MISSING and lists install commands |
| 1 | Fatal (bad args, unwritable dir, conv error) | report `STATUS: BLOCKED` with the script's stderr |
### Re-rendering when `PACKAGE.OUTPUT` is `versioned <path>`
If `PACKAGE.OUTPUT` resolved to a versioned path (e.g.
`LIVRAISON-YYYY-MM-DD.md`), the renderer produces matching
`LIVRAISON-YYYY-MM-DD.html` and `LIVRAISON-YYYY-MM-DD.pdf`. Pass the
versioned path as `$OUTPUT_MD`.
---
## PLATFORM REFERENCE (fallback if checklists/seo-geo-manual.md missing)
Local-business priority order with 2026 signup URLs:
1. Google Business Profile — https://www.google.com/business/
2. Apple Business Connect — https://businessconnect.apple.com/
3. Bing Places for Business — https://www.bingplaces.com/
4. Pages Jaunes (FR) — https://www.pagesjaunes.fr/pro/inscription
5. Facebook Page — https://www.facebook.com/pages/create
6. Instagram Business — https://business.instagram.com/
7. TripAdvisor (hospitality) — https://www.tripadvisor.com/Owners
8. TheFork / La Fourchette (restaurants FR) — https://www.thefork.com/restaurant
9. Yelp — https://biz.yelp.com/
10. Mappy (FR) — https://corporate.mappy.com/
11. Waze — https://www.waze.com/business/
12. Foursquare for Business — https://business.foursquare.com/
13. Bottin / Justacote (FR) — https://www.justacote.com/
14. Hoodspot (FR) — https://www.hoodspot.fr/
15. Trustpilot — https://business.trustpilot.com/
16. Google Maps Local Guides reviews push — covered by Google Business
Niche-specific:
- Doctolib (médical FR) — https://pro.doctolib.fr/
- Booking.com (hôtellerie) — https://www.booking.com/business
- Airbnb (locations) — https://www.airbnb.com/host/homes
- LinkedIn Company Page — https://www.linkedin.com/company/setup/new/
- TikTok Business — https://www.tiktok.com/business/
- Pinterest Business — https://business.pinterest.com/
Non-local web priority:
1. Google Search Console — https://search.google.com/search-console
2. Bing Webmaster Tools — https://www.bing.com/webmasters
3. Wikidata entry — https://www.wikidata.org/wiki/Special:CreateAccount
4. LinkedIn Company Page (B2B)
5. Product Hunt (launches) — https://www.producthunt.com/posts/new
6. Crunchbase (startups) — https://www.crunchbase.com/add-new
7. G2 / Capterra (SaaS reviews) — https://www.g2.com/, https://www.capterra.com/
8. GitHub topic + README badges (open source)
AI visibility (GEO):
- Wikidata Q-item with `sameAs`
- Schema.org JSON-LD: Organization, LocalBusiness, niche, FAQPage, Article, Person
- llms.txt at site root
- Direct AI checks: search business name on ChatGPT, Claude, Perplexity, Gemini
If you need 2026-current pricing, signup steps, or a platform you're
unsure exists, use `WebSearch` and confirm before listing it. Do NOT
invent links.
---
## FORBIDDEN
- `git commit`, branch creation/switch, `git push`.
- Installing new dependencies.
- Dispatching subagents (no `Agent` tool — none available).
- Prompting the user interactively — every interactive decision
travels in the PACKAGE; if something is missing, report
`STATUS: BLOCKED` instead of asking.
- Editing anything under `.claude/**`.
- Attribution trailers of any kind in any file this agent writes.
---
## OUTPUT
End every run with a `HANDOVER-DOC REPORT` block:
```
HANDOVER-DOC REPORT
STATUS: DONE | BLOCKED
MD: <path written, or "skipped (per PACKAGE.OUTPUT)", or "—" if BLOCKED>
HTML: <path written, or "—" if not reached>
PDF: <path written, or "no engine" (exit 2), or "—" if not reached>
GATES: word-count=<pass/fail + word count> skill-leak=<pass/fail> anchor=<pass/fail>
NOTES: <memory/audit availability caveats, [À COMPLÉTER] markers left in
NAP, pre-check items applied, deploy chapter included/skipped, or the
BLOCKED reason + which PACKAGE field was missing/malformed>
```
@@ -1742,34 +1742,212 @@ NOTES : <BLOCKED: the blocker verbatim; DONE: none>
---
# WAVE 4 — client-handover whole-writer dispatch (spec §5, user directive 2026-07-15)
# WAVE 4 — client-handover: dispatch the doc-generation to sonnet (redaction-only, spec §5, user directive 2026-07-16)
**Status: NOT YET SPEC'd — needs a dedicated design pass.** The user chose the
"dispatch the whole writer" variant of spec §5 (over the lighter redaction-only
split). This converts `agents/client-handover-writer.md` (1774 lines) from an
inline-loaded session-model agent into a dispatched sonnet subagent. It is the
single largest conversion in this effort and requires designing a resumable-gate
protocol before task decomposition. Key constraints already established:
**Shape DECIDED (user, 2026-07-16): redaction-only**, NOT whole-writer. Rationale
(from the full read of the 1774-line writer): the nested audit dispatches
(STEP 3/4/7 run `/seo`, `/harden`, `/web-validate`) must run on the BIG model
either way — those skills are gated themselves (wave 1), so a sonnet parent
would force-pin them anyway or trip their own gate. So the only work that truly
belongs on sonnet is the DOC GENERATION (writing the deliverable). Whole-writer
would add ~7 extra gate-yields + a resumable state machine on a client-facing
pipeline for ~zero extra sonnet work. Redaction-only gets the same sonnet
savings with the pipeline + all interactive gates staying NATIVE in the big
main loop.
- The writer has ~8–11 mid-pipeline `AskUserQuestion` gates (STEP 4 fix-loop
escalation, STEP 5 push + push-failed, STEP 6 deploy pause + deployed-URL,
STEP 11 Q1/Q2, STEP 13 NAP asks, …). A dispatched subagent cannot ask.
Convert each to a `GATE NEEDED: <id> <payload>` yield: the writer STOPs and
returns it; the dispatcher (`skills/client-handover/SKILL.md`, main loop)
runs the `AskUserQuestion`; then RESUMES the writer via SendMessage with the
answer. Remove `AskUserQuestion` from the writer's tools.
- **CORRECTNESS (spec §5 OPEN VERIFY POINT — resolved: force big):** the
writer's nested audit dispatches (STEP 3 baseline SEO/HARDEN/CSO, STEP 4 fix
loops, STEP 7 web-validate — all `general-purpose`) MUST carry an explicit
big-model `model` param so audits do NOT inherit the sonnet parent. Running
audits on sonnet would silently violate the "audits on the big model" rule.
The fix-application re-dispatches (execution) stay sonnet.
- Dispatcher collects params inline (URL, logo, options), then
`Agent(subagent_type="client-handover-writer")`; writer keeps `Agent` (nested
dispatches) + gains no `AskUserQuestion`.
- Add the MODEL GATE to `skills/client-handover/SKILL.md` (it orchestrates
audits = reflection) and add it to the census wired list.
- Census + README/CHANGELOG + BDR-066 wave-4 bullet + journal + TODO.
## Architecture
Tasks 19+ to be written after reading the writer's STEP 12–14 (doc synthesis +
render + remaining gates, lines 1123–1774) and mapping every gate to a yield id.
- **`agents/client-handover-writer.md`** stays INLINE-LOADED by the skill →
runs on the big session model (its `model: opus` frontmatter is inert under
inline-load; leave or drop — see Task 20). It becomes the **pipeline +
delegator**: STEP 1–8 unchanged (pre-flight, detect, baseline audits, fix
loops, commit/push, deploy pause, web-validate, gate eval) — all its
interactive gates (STEP 4 escalation, STEP 5 push/push-failed, STEP 6 deploy
pause + URL) work NATIVELY (main loop) and its nested audit dispatches inherit
the big session model with NO force-pinning. Then it does the INTERACTIVE +
detection parts of doc-gen — STEP 11 questions (Q1 deploy-chapter, Q2
language), the STEP 12 §4 NAP-table build (incl. the business-name ask),
STEP 14.5 platform detection + the batch-unknowns `AskUserQuestion`, and
resolves the output path + overwrite decision (STEP 15 gate) + `CLIENT_NAME`
(STEP 16 gate). It assembles a PACKAGE and dispatches the doc-writer, then
reports the returned deliverable. Keeps `AskUserQuestion` + `Agent`.
- **`agents/handover-doc-writer.md`** (NEW, `model: sonnet`, tools
`Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch` — **NO
AskUserQuestion, NO Agent**): the pure writer. Reads material itself (STEP 9
memory, STEP 10 git history) and, from the PACKAGE, does STEP 12 synthesis +
STEP 13 §7 checklist content + STEP 14 §8 (only if `INCLUDE_DEPLOY`) +
STEP 14.5 apply-the-given-precheck-set + STEP 15 write MD + the three gates
(word-count ≤300 on §3, skill-leak, anchor-resolution) + STEP 16 render
(HTML always, PDF when an engine is present). **Gate-free** — every
interactive decision was resolved by the parent and travels in the PACKAGE.
## The PACKAGE (parent → doc-writer dispatch prompt)
A single structured block the doc-writer treats as ground truth:
`LANG`; `PROJECT` (name, root, type, sub-type, is_local_business, deployed_url,
period first→last commit); `SCORES` (seo/geo/harden/validate or cso — before &
after, each with pass-status + any code-ceiling note); `AUDIT_REPORTS` (paths to
`.claude/audits/*.md` + HUMAN-ACTIONS/THRESHOLD-OVERRIDE if present, for §6
sourcing); `INCLUDE_DEPLOY` (yes|no); `NAP` (the full resolved §4 table) +
`PRECHECK_DONE` (platforms already confirmed, for §5/§7 checkboxes);
`CLIENT_NAME` (string or `—`); `OUTPUT` (final md path + overwrite decision
`overwrite | versioned <path> | skip-write`).
## Global Constraints (wave 4)
Branch `feature/client-handover-dispatch` (off develop, already checked out).
Same as prior waves: no merge, no attribution trailers, `make test` green per
commit, shellcheck clean, config-protection sentinel before each `lib/tests/*`
write (controller applies), YAML `safe_load`-parseable frontmatter. **Preserve
every deliverable invariant** (6-chapter structure, §2=scores, §4 NAP before §5,
§3 ≤300 words + zero jargon, skill-leak gate over chapters 1–5, clickable
anchors, ZenQuality render) — a dropped gate degrades a client deliverable.
---
### Task 19: create `agents/handover-doc-writer.md` (sonnet, gate-free doc generator)
**Files:** Create `agents/handover-doc-writer.md`.
Extract the doc-generation half of `agents/client-handover-writer.md` (its
STEP 9, 10, 12, 13, 14, 14.5-apply, 15, 16 — lines 835–1774, MINUS the
interactive detection/questions that the parent now owns) into a new standalone
sonnet agent driven by the PACKAGE.
- [ ] **Step 1:** Frontmatter: `name: handover-doc-writer`;
`description:` (one line — "Deliverable writer — dispatched by
client-handover with a resolved PACKAGE. Synthesizes the 6-chapter client doc,
writes the MD, renders branded HTML+PDF. No audits, no questions.");
`tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch`;
`model: sonnet`. NO `AskUserQuestion`, NO `Agent`.
- [ ] **Step 2:** Body. Open with an `## INPUT — the PACKAGE` section listing the
fields above and stating they are ground truth (never re-ask, never re-audit).
Then port, in order:
- STEP 9 LOAD MEMORY (verbatim — reads `.claude/memory/*`) and STEP 10 GIT
HISTORY (verbatim; keep the ≥200-commit clustering, but if it delegates to a
sub-agent, DROP that — a sonnet doc-writer has no `Agent`; do the clustering
inline).
- STEP 12 SYNTHESIZE — the full 6-chapter structure + ALL "Hard rules"
(clickable anchors, no skill names in ch.1–5, §3 ≤300 words, §2 score table
from `SCORES`, §4 NAP from `PACKAGE.NAP` before §5). Verbatim from source.
- STEP 13 §7 SEO/GEO checklist content + STEP 14 §8 deploy chapter (render
ONLY if `INCLUDE_DEPLOY=yes`).
- STEP 14.5 APPLY-ONLY: apply `PACKAGE.PRECHECK_DONE` to §5 `- [ ]`→`- [x]`
and §7 `- ☐`→`- ☑` + the cleanup pass. DROP the detection + the
batch-unknowns `AskUserQuestion` (the parent did both; the doc-writer only
applies the resolved set).
- STEP 15 WRITE — honor `PACKAGE.OUTPUT` (path + overwrite decision; NO
overwrite `AskUserQuestion` — obey the decision). Keep all three gates
verbatim: `wc -w` ≤300 on §3, the skill-leak grep over ch.1–5, the anchor
`comm -23` check. A gate failure → fix the MD and re-check (as today).
- STEP 16 RENDER — use `PACKAGE.CLIENT_NAME` (no `AskUserQuestion`); run
`scripts/handover-to-pdf.sh` with the env vars as today.
- FORBIDDEN block: `git commit`/branch ops/push, new deps, `Agent` dispatch,
`AskUserQuestion`, editing `.claude/**`, attribution trailers.
- End with a `HANDOVER-DOC REPORT` (STATUS DONE|BLOCKED; MD path; HTML path;
PDF path or "no engine"; the three gate results; NOTES).
- [ ] **Step 3:** YAML check
(`python3 -c "import yaml; yaml.safe_load(open('agents/handover-doc-writer.md').read().split('---')[1]); print('YAML OK')"`);
`grep -c 'AskUserQuestion\|subagent_type\|Agent(' agents/handover-doc-writer.md` → 0.
`make test` green (new agent isn't yet referenced — pure addition).
```bash
git add agents/handover-doc-writer.md
git commit -m "feat(model-routing): handover-doc-writer — sonnet gate-free deliverable generator (wave 4)"
```
---
### Task 20: trim `agents/client-handover-writer.md` to pipeline + delegator
**Files:** Modify `agents/client-handover-writer.md`.
- [ ] **Step 1:** Keep STEP 1–8 verbatim (pipeline; native gates; nested audit
dispatches unchanged — they inherit the big session model since this agent is
inline-loaded and runs big).
- [ ] **Step 2:** Replace STEP 9–16 with a **doc-gen orchestration** section that:
(a) runs STEP 11 questions inline (Q1 deploy-chapter → `INCLUDE_DEPLOY`, Q2
language); (b) builds the §4 NAP table inline (incl. the business-name
`AskUserQuestion` at today's line ~1107); (c) runs STEP 14.5 platform
DETECTION + the batch-unknowns `AskUserQuestion` inline → `PRECHECK_DONE`;
(d) resolves the output path + overwrite (`test -f` then the STEP 15 question)
and `CLIENT_NAME` (detect or the STEP 16 question); (e) assembles the PACKAGE
and dispatches:
```
Agent(subagent_type="handover-doc-writer")
prompt: "PACKAGE:\n<the resolved fields>\nSynthesize + write + render the
deliverable per your steps. Report the HANDOVER-DOC REPORT."
```
then parses `HANDOVER-DOC REPORT` and reports the deliverable paths to the
user (surface BLOCKED verbatim). Keep `AskUserQuestion` + `Agent` in tools.
- [ ] **Step 3:** Frontmatter — drop the now-misleading `model: opus` line (this
agent inherits the session model like the other big-model reflection agents;
inline-load already made the pin inert). Update its `description` to say it
runs the ship pipeline then DELEGATES the deliverable writing to the sonnet
`handover-doc-writer`.
- [ ] **Step 4:** YAML check; `make test` green.
```bash
git add agents/client-handover-writer.md
git commit -m "feat(model-routing): client-handover-writer trimmed to pipeline + delegates doc-gen to sonnet doc-writer"
```
---
### Task 21: `skills/client-handover/SKILL.md` — MODEL GATE + updated overview
**Files:** Modify `skills/client-handover/SKILL.md`.
- [ ] **Step 1:** Add the orchestrator MODEL GATE block right under the H1 /
before the `Load and follow strictly:` line (client-handover orchestrates
audits = reflection → it MUST be gated):
```
MODEL GATE (blocking): run `$HOME/.claude/lib/model-gate.md` BEFORE loading
the agent below. Verdict `small` → STOP — print the gate's remedy, end the
turn, do not load the agent.
```
Keep the inline-load of `client-handover-writer.md` (it runs the big-model
pipeline). Update the overview prose: the writer runs the audit/fix/gate
pipeline on the big model, then delegates the deliverable writing to the
sonnet `handover-doc-writer`.
- [ ] **Step 2:** `grep -c 'lib/model-gate.md' skills/client-handover/SKILL.md` → ≥1;
`make test` green.
```bash
git add skills/client-handover/SKILL.md
git commit -m "feat(model-routing): client-handover MODEL GATE (pipeline orchestrates audits = reflection)"
```
---
### Task 22: wave-4 census + docs + memory
**Files:** `lib/tests/model-routing.test.sh` (guarded — CONTROLLER), `README.md`,
`CHANGELOG.md`, `.claude/memory/decisions.md`, `.claude/memory/journal.md`,
`.claude/tasks/TODO.md`.
- [ ] **Step 1 (CONTROLLER — guarded):** sentinel, then add to
`lib/tests/model-routing.test.sh`: add `client-handover` to the wired-gate
loop (`# 1)`); a `# 9) wave-4` block —
`has skills/client-handover/SKILL.md 'lib/model-gate.md'` (redundant w/ loop —
keep in the loop), `has agents/handover-doc-writer.md 'model: sonnet'`,
`lacks agents/handover-doc-writer.md 'AskUserQuestion'`,
`has agents/client-handover-writer.md 'subagent_type="handover-doc-writer"'`.
Update the printed count; flip-test one new assertion.
- [ ] **Step 2:** README agent-model table — add `handover-doc-writer` (sonnet,
deliverable writer); move `client-handover-writer` from its old "opus (pinned,
inert)" row into the "inherit session" reflection row (it now runs the
big-model pipeline). CHANGELOG Unreleased `### Changed` — wave-4 bullet.
- [ ] **Step 3:** BDR-066 `**Wave 4**` bullet (redaction-only chosen over
whole-writer + why: audits big either way; doc-gen → sonnet doc-writer;
pipeline + all gates native on big; client-handover joins the gated group).
Journal line + TODO tick.
```bash
git add lib/tests/model-routing.test.sh README.md CHANGELOG.md .claude/memory/decisions.md .claude/memory/journal.md .claude/tasks/TODO.md
git commit -m "chore(model-routing): wave-4 census + docs + BDR-066 (client-handover doc-gen → sonnet)"
```
- [ ] **Step 4: Final wave-4 review** — dispatch a whole-branch reviewer (opus)
over the wave-4 range: verify the doc-writer preserves EVERY deliverable
invariant (6 chapters, §2 scores, §4-before-§5, §3 ≤300 words, skill-leak
gate, anchors, render), is gate-free (no AskUserQuestion/Agent), and that the
parent still owns all interaction + assembles a complete PACKAGE (no field the
doc-writer needs is missing). Report `git log --oneline develop..HEAD`. Do NOT
merge.
+7 -2
View File
@@ -9,8 +9,8 @@ has() { if grep -qF "$2" "$R/$1"; then ok; else ko "$1 missing: $2"; fi; }
lacks() { if grep -qF "$2" "$R/$1"; then ko "$1 must NOT contain: $2"; else ok; fi; }
fm_lacks() { if awk 'NR<=10' "$R/$1" | grep -qF "$2"; then ko "$1 frontmatter must NOT contain: $2"; else ok; fi; }
# 1) gate wired in the 13 reflection orchestrators
for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean hotfix; do
# 1) gate wired in the 14 reflection orchestrators
for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean hotfix client-handover; do
has "skills/$s/SKILL.md" 'lib/model-gate.md'
done
# 2) gate NOT wired in the excluded skills (encodes the spec exclusion list)
@@ -48,6 +48,11 @@ lacks "agents/bugfixer.md" 'AskUserQuestion'
has "skills/code-clean/SKILL.md" 'subagent_type="code-cleaner"'
has "agents/code-cleaner.md" 'model: sonnet'
lacks "agents/code-cleaner.md" 'AskUserQuestion'
# 9) wave-4 — client-handover: pipeline (big) inline + gated, doc-gen dispatched to sonnet
has "agents/handover-doc-writer.md" 'model: sonnet'
lacks "agents/handover-doc-writer.md" 'AskUserQuestion'
lacks "agents/handover-doc-writer.md" 'Agent('
has "agents/client-handover-writer.md" 'subagent_type="handover-doc-writer"'
printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail"
[ "$fail" -eq 0 ]
+8 -1
View File
@@ -21,10 +21,17 @@ allowed-tools:
- Agent
---
MODEL GATE (blocking): run `$HOME/.claude/lib/model-gate.md` BEFORE loading
the agent below. Verdict `small` → STOP — print the gate's remedy, end the
turn, do not load the agent.
Load and follow strictly:
- $HOME/.claude/agents/client-handover-writer.md
Execute the CLIENT HANDOVER WRITER agent on this project.
Execute the CLIENT HANDOVER WRITER agent on this project. It runs the
audit/fix/gate pipeline INLINE on the big session model (gated above), then
delegates the client deliverable (Markdown + branded HTML + PDF) to the
sonnet-pinned `handover-doc-writer` subagent (BDR-066).
The agent runs a **ship-and-handover pipeline** with explicit gates: