From 655e364e806e33ce3fac286202d9266d7258ed53 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Mon, 20 Jul 2026 16:40:58 +0200 Subject: [PATCH] chore(docs): purge transient plan/spec artifacts missed by post-merge cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/plans + docs/specs (deploy-skill 2026-06-27): predate the BDR-065 lifecycle codification, never swept - docs/superpowers/{plans,specs} (model-routing 2026-07-15): 6-wave chantier — final W6 merge closed it without the purge step Git history at the feature commits is the archive (BDR-065). --- docs/plans/2026-06-27-deploy-skill.md | 385 ---- docs/specs/2026-06-27-deploy-skill-design.md | 165 -- .../plans/2026-07-15-model-routing.md | 1953 ----------------- .../specs/2026-07-15-model-routing-design.md | 143 -- 4 files changed, 2646 deletions(-) delete mode 100644 docs/plans/2026-06-27-deploy-skill.md delete mode 100644 docs/specs/2026-06-27-deploy-skill-design.md delete mode 100644 docs/superpowers/plans/2026-07-15-model-routing.md delete mode 100644 docs/superpowers/specs/2026-07-15-model-routing-design.md diff --git a/docs/plans/2026-06-27-deploy-skill.md b/docs/plans/2026-06-27-deploy-skill.md deleted file mode 100644 index be01332..0000000 --- a/docs/plans/2026-06-27-deploy-skill.md +++ /dev/null @@ -1,385 +0,0 @@ -# Deploy Skill — Implementation Plan - -> **Superseded by BDR-054** (`52f6678`): the shipped skill has NO `NEXT.sh` file and NO -> AskUserQuestion hand-back — see `skills/deploy/SKILL.md` for current behavior. This -> plan is kept as historical record; do not implement its NEXT.sh/hand-back sections. - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Build a `deploy` skill — a per-project shell runbook that re-instantiates from the delta since the last deploy, hands control to the user for out-of-band execution, resumes cold (even in a new session), and learns from deploy errors in place. - -**Architecture:** A surgical-commit helper (`lib/deploy-commit.sh`, allowlist-scoped to `.claude/deploy/`) is the foundation. Five per-project artifacts under `.claude/deploy/` carry runbook, incident ledger, deploy oracle, in-flight bridge, and the instantiated checklist. The skill is a two-moment SKILL.md (before → user deploys out-of-band → after, on the user's report), resumable cold from the JSON bridge per the `audit-delta` state-file convention. Bootstrap scaffolds the runbook for a project that has none. - -**Tech Stack:** Bash (helper + git), Markdown (SKILL.md + runbook + ledger), JSON (oracle + bridge). No new runtime deps — Claude reads JSON natively in skill steps; the helper never parses JSON. - -## Global Constraints - -- Surgical commits only: `deploy-commit.sh` commits via explicit argv pathspec, never `git add -A`. (mirror BDR-034/036) -- Allowlist scope = `.claude/deploy/` ONLY; any other path is a loud rc-4 refusal. Inverse of `doc-commit.sh`'s `.claude/**` exclusion (BDR-022). Verified: real `doc-commit.sh` returns rc 4 on `.claude/deploy/PROCEDURE.md`. -- Delta = `git diff --name-only HEAD` — **explicit two endpoints, no dots** (two-dot ≡ this; three-dot undercounts — verified). Never `git rev-list` ancestry (phantom deltas on rebase — verified). -- First-deploy detection = `[ -f .claude/deploy/STATE.json ]` (deterministic). NEVER `git describe` (hard-errors rc 128 on no tag — verified). -- Resume convention = `audit-delta`: "the state file is the only memory between runs; never infer prior scope from context." Bridge read at STEP 0. -- Helper inherits from `lib/memory-commit.sh`/`lib/doc-commit.sh`: rc 3 on unsafe git state (detached/merge/rebase/cherry-pick), short-hash on stdout only on a real commit, per-file changed-paths filter, diagnostics to stderr. -- User executes the deploy out-of-band (prod ssh) — the skill NEVER runs deploy commands itself. -- Registries/spec language English; the spec of record is `docs/specs/2026-06-27-deploy-skill-design.md`. - ---- - -## Decisions resolved at plan time - -**§10 (cross-session state) — TRANCHÉ: separate bridge artifact.** -- Bridge = `.claude/deploy/PENDING.json` (JSON), **distinct from the ephemeral `NEXT.sh`**, **uncommitted** (transient local working state; gitignored). Schema: - ```json - { "base_sha": "", "target_sha": "", - "delta": ["supabase/migrations/0033_x.sql", "docker-compose.yml"], - "step_reached": "awaiting-user", "started_at": "", "runbook_rev": "" } - ``` -- Follows `audit-delta` ("state file is the only memory between runs"). Resolves the n°1↔n°3 coupling: NEXT.sh stays ephemeral per §3; the bridge persists and carries base+target+delta so moment 3 lays the correct marker and capitalizes the correct incident — **without re-parsing shell**, readable cold. -- Form-novelty (mid-flow pause-resume) is new → `writing-skills` formalizes the convention in Task 3. -- **LIMIT (acknowledged, not to be discovered):** `PENDING.json` is gitignored ⇒ cold-resume is **same-machine only** — it does not survive a clone or a move to another machine. Acceptable because a project's deploys run from one local; recorded as a constraint, not assumed away. - -**§8 item 1 — tag push:** annotated tag `git tag -a deploy/ -m ""` laid in MARK (success). **Project knob `# @config push_deploy_tags=true|false`** in the `PROCEDURE.md` header (default `false`): when true, MARK runs `git push origin deploy/` — always **best-effort/non-fatal** (the push never blocks the deploy; tag is a bookmark, STATE.json is the oracle). Same-day re-deploy → suffix `-N`. - -**§8 item 2 — INCIDENTS ID/name:** `.claude/deploy/INCIDENTS.md`, append-only, entries `DEP-NNN` (next = `grep '^## DEP-' | max+1`), fields mirror `blockers.md`: date, step, error (verbatim), root cause, fix. Resolution derivable from git: the commit that adds the entry IS the fix (atomic patch+incident); recover via `git log -S 'DEP-NNN' -- .claude/deploy/INCIDENTS.md`. Name confirmed `INCIDENTS.md` (not `ERRORS-LEARNED.md`). - -**§8 item 3 — `@delta:` grammar:** directives on a runbook step's preceding comment line, patterns matched against the delta file list. `glob=` carries TWO required semantics (a single "checklist-only" reading was REJECTED — it breaks the game example, where step 3 runs `psql -f 0033` THEN `psql -f 0034` = one command PER file): -- `# @delta: glob=:each` — **repeat**: emit the step's command once per delta file matching `` (e.g. `psql -f `). -- `# @delta: glob=:list` — **checklist**: emit the command once, with matching files as `# VERIFY:` items (e.g. `supabase migration up`). -- `# @delta: when=[,...]` — **conditional**: include the step only if the delta intersects any pattern (e.g. rebuild when compose/Dockerfile changed). -- Patterns are git-pathspec/shell-glob; comma-separates alternatives. **Un-annotated step = fixed**, always emitted verbatim. The exact `:each`/`:list` keyword spelling is DEFERRED to `writing-skills` (Task 3); both semantics are mandatory. - -**§8 item 4 — frontmatter / gates:** -```yaml -name: deploy -description: | - Use when deploying a project via its per-project runbook — instantiates the - delta since last deploy, hands off for out-of-band execution, resumes cold, - learns from errors. - Triggers: "deploy", "déploie", "run the deploy", "ship to prod", "deploy runbook". -allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion] -``` -Gate vocabulary reused from `capitalize`/`client-handover`: `all / pick / edit / skip-all`. Gates marked **[GATE]** in Task 3. - ---- - -## File Structure - -- Create `lib/deploy-commit.sh` — surgical commit helper, allowlist `.claude/deploy/`. (Task 1) -- Create `lib/tests/deploy-commit.test.sh` — real-git behavioral tests. (Task 1) -- Create `skills/deploy/SKILL.md` — the two-moment skill. (Task 3) -- Create `templates/deploy/PROCEDURE.md` — annotated starter runbook (scaffold source). (Task 2/4) -- Create `templates/deploy/INCIDENTS.md` — empty ledger header. (Task 2) -- Modify `.gitignore` — ignore `.claude/deploy/NEXT.sh` and `.claude/deploy/PENDING.json`. (Task 2) -- Per-project, created at runtime (NOT in this repo): `.claude/deploy/{PROCEDURE.md, INCIDENTS.md, STATE.json, PENDING.json, NEXT.sh}`. - -**Artifact lifecycle:** - -| Artifact | Committed? | Lifecycle | -|---|---|---| -| `PROCEDURE.md` | yes (deploy-commit) | in-place edits (learning) | -| `INCIDENTS.md` | yes (deploy-commit) | append-only `DEP-NNN` | -| `STATE.json` | yes (deploy-commit) | overwritten on success = oracle | -| `PENDING.json` | **no** (gitignored) | written at hand-back, deleted on success = cold-resume bridge | -| `NEXT.sh` | **no** (gitignored) | regenerated per deploy, ephemeral checklist | - ---- - -### Task 1: `lib/deploy-commit.sh` — surgical commit helper (FOUNDATION, TDD) - -**Files:** -- Create: `lib/deploy-commit.sh` -- Test: `lib/tests/deploy-commit.test.sh` - -**Interfaces:** -- Produces: `deploy-commit.sh pending ...` → exit 0 if any passed file in-scope has changes, else 1. `deploy-commit.sh commit "" ...` → commits ONLY passed in-scope files, prints short hash on stdout; rc 0 success, rc 1 clean/no-op, rc 3 unsafe git state, rc 4 out-of-scope path. -- Consumes: nothing (foundation). - -- [ ] **Step 1: Write the failing test harness** - -```bash -# lib/tests/deploy-commit.test.sh -#!/usr/bin/env bash -set -u -H="$(cd "$(dirname "$0")/.." && pwd)/deploy-commit.sh" -pass=0; fail=0 -mkrepo() { local d; d=$(mktemp -d); git -C "$d" init -q; git -C "$d" config user.email t@t; - git -C "$d" config user.name t; mkdir -p "$d/.claude/deploy"; printf 'x\n' >"$d/seed"; - git -C "$d" add seed; git -C "$d" commit -q -m seed; printf '%s' "$d"; } -check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1)); - printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; } - -d=$(mkrepo); printf 'run\n' >"$d/.claude/deploy/PROCEDURE.md" -out=$( cd "$d" && bash "$H" commit "docs(deploy): t" .claude/deploy/PROCEDURE.md ); rc=$? -check T1-rc "$rc" 0 -check T1-committed-only "$(git -C "$d" show --name-only --format= HEAD)" ".claude/deploy/PROCEDURE.md" -check T1-hash-nonempty "$([ -n "$out" ] && echo y || echo n)" y - -d=$(mkrepo); printf 'b\n' >"$d/src.txt" -( cd "$d" && bash "$H" commit "x" src.txt ) >/dev/null 2>&1; check T2-out-of-scope-rc "$?" 4 - -d=$(mkrepo) -( cd "$d" && bash "$H" commit "x" ".claude/deploy/../memory/secret" ) >/dev/null 2>&1 -check T3-traversal-rc "$?" 4 - -d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md"; printf 's\n' >"$d/src.txt" -( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md src.txt ) >/dev/null 2>&1 -check T4-mixed-refuses-all "$?" 4 -check T4-nothing-committed "$(git -C "$d" rev-list --count HEAD)" 1 - -d=$(mkrepo); git -C "$d" checkout -q --detach -printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md" -( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md ) >/dev/null 2>&1 -check T5-unsafe-rc "$?" 3 - -d=$(mkrepo) -( cd "$d" && bash "$H" pending .claude/deploy/PROCEDURE.md ); check T6-pending-clean-rc "$?" 1 - -d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md" -printf 'i\n' >"$d/.claude/deploy/INCIDENTS.md"; printf '{}\n' >"$d/.claude/deploy/STATE.json" -( cd "$d" && bash "$H" commit "docs(deploy): learn" .claude/deploy/PROCEDURE.md \ - .claude/deploy/INCIDENTS.md .claude/deploy/STATE.json ) >/dev/null 2>&1 -check T7-atomic-rc "$?" 0 -check T7-three-files "$(git -C "$d" show --name-only --format= HEAD | grep -c deploy)" 3 - -printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ] -``` - -- [ ] **Step 2: Run the test, verify it FAILS** - -Run: `bash lib/tests/deploy-commit.test.sh` -Expected: FAIL (helper absent) — every check fails or the harness errors on missing `lib/deploy-commit.sh`. - -- [ ] **Step 3: Implement `lib/deploy-commit.sh`** - -```bash -#!/usr/bin/env bash -# deploy-commit.sh — surgical commit for the .claude/deploy/ runbook family. -# Allowlist scope = .claude/deploy/ ONLY (inverse of doc-commit's .claude exclusion). -set -u - -_in_git_repo() { git rev-parse --is-inside-work-tree >/dev/null 2>&1; } - -_unsafe_state() { # 0 = unsafe - local g; g=$(git rev-parse --git-dir 2>/dev/null) || return 0 - git symbolic-ref -q HEAD >/dev/null 2>&1 || return 0 # detached HEAD - [ -e "$g/MERGE_HEAD" ] || [ -d "$g/rebase-merge" ] || \ - [ -d "$g/rebase-apply" ] || [ -e "$g/CHERRY_PICK_HEAD" ] && return 0 - return 1 -} - -_out_of_scope() { # 0 = forbidden, 1 = in scope - case "$1" in - *..*) return 0 ;; # traversal — forbidden FIRST - .claude/deploy/*) return 1 ;; # allowed - *) return 0 ;; # everything else forbidden - esac -} - -_scope_violations() { local p; for p in "$@"; do _out_of_scope "$p" && printf '%s\n' "$p"; done; } - -_changed_only() { # echo passed files that actually have changes - local p; for p in "$@"; do - [ -n "$(git status --porcelain -- "$p" 2>/dev/null)" ] && printf '%s\n' "$p"; done -} - -cmd="${1:-}"; shift || true -_in_git_repo || { echo "deploy-commit: not a git repo" >&2; exit 2; } - -case "$cmd" in - pending) - [ "$#" -gt 0 ] || { echo "deploy-commit: pending needs file args" >&2; exit 2; } - [ -n "$(_changed_only "$@")" ] && exit 0 || exit 1 ;; - commit) - msg="${1:-}"; shift || true - [ -n "$msg" ] && [ "$#" -gt 0 ] || { echo "deploy-commit: commit needs ..." >&2; exit 2; } - viol=$(_scope_violations "$@") - if [ -n "$viol" ]; then - { echo "deploy-commit: REFUSED — path(s) outside .claude/deploy/ allowlist:"; - printf ' - %s\n' $viol; - echo "deploy-commit: NOTHING committed. Caller must pass only .claude/deploy/ files."; } >&2 - exit 4 - fi - _unsafe_state && { echo "deploy-commit: unsafe git state (detached/merge/rebase) — not committing" >&2; exit 3; } - mapfile -t changed < <(_changed_only "$@") - [ "${#changed[@]}" -gt 0 ] || exit 1 - git commit -q -m "$msg" -- "${changed[@]}" || { echo "deploy-commit: git commit failed" >&2; exit 1; } - git rev-parse --short HEAD ;; - *) echo "usage: deploy-commit.sh pending ... | commit \"\" ..." >&2; exit 2 ;; -esac -``` - -- [ ] **Step 4: Run the test, verify it PASSES** - -Run: `bash lib/tests/deploy-commit.test.sh` -Expected: `PASS=12 FAIL=0` (exit 0). - -- [ ] **Step 5: shellcheck** - -Run: `shellcheck lib/deploy-commit.sh lib/tests/deploy-commit.test.sh` -Expected: clean (matches repo Health Stack norm). - -- [ ] **Step 6: Commit** - -```bash -git add lib/deploy-commit.sh lib/tests/deploy-commit.test.sh -git commit -m "feat(deploy): deploy-commit.sh — allowlist surgical commit for .claude/deploy/" -``` - ---- - -### Task 2: Artifacts + bridge formats (§10 materialized) - -**Files:** -- Create: `templates/deploy/PROCEDURE.md`, `templates/deploy/INCIDENTS.md` -- Modify: `.gitignore` - -**Interfaces:** -- Produces: the on-disk shapes the skill reads/writes — `PROCEDURE.md` annotation grammar, `INCIDENTS.md` `DEP-NNN` template, `STATE.json` and `PENDING.json` schemas. -- Consumes: nothing. - -- [ ] **Step 1: Write `templates/deploy/PROCEDURE.md`** (annotated starter — fixed steps verbatim, dynamic steps annotated) - -```bash -#!/usr/bin/env bash -# === deploy runbook (reference) — NOT run directly. Instantiated to NEXT.sh per delta. === -# Fixed steps run every deploy; `# @delta:` steps re-instantiate from the delta. -# @config push_deploy_tags=false -# NOTE grammar: glob=:each repeats the command per matching file (e.g. psql -f ); -# glob=:list runs once + lists matching files as VERIFY items; when= is conditional. - -# 1) backup BEFORE any forward-only migration -ssh "$DEPLOY_HOST" 'pg_dump "$DB" > ~/backups/pre-deploy-$(date +%F-%H%M).sql' # VERIFY: dump size > 0 - -# @delta:migrations glob=supabase/migrations/*.sql:list -# 2) apply NEW migrations (one command; skill lists the delta migrations to VERIFY) -ssh "$DEPLOY_HOST" 'supabase migration up' # VERIFY: "Applied" for each - -# @delta:rebuild when=docker-compose*.yml,Dockerfile,Dockerfile.* -# 3) rebuild + restart services (only if build inputs changed) -ssh "$DEPLOY_HOST" 'docker compose up -d --build' # VERIFY: docker compose ps healthy - -# @delta:deps when=package.json,*lock*,requirements.txt,pyproject.toml -# 4) install deps (only if manifests changed) -ssh "$DEPLOY_HOST" 'cd app && npm ci' # VERIFY: exit 0 - -# 5) reload cache + smoke test (fixed) -ssh "$DEPLOY_HOST" 'systemctl reload app' -curl -fsS https://$DEPLOY_HOST/health # VERIFY: HTTP 200 -``` - -- [ ] **Step 2: Write `templates/deploy/INCIDENTS.md`** (ledger header) - -```markdown -# Deploy incidents (append-only) — DEP-NNN - - - - -``` - -- [ ] **Step 3: Record the JSON schemas** (no parsing in shell — Claude reads them in skill steps) - -`STATE.json` (committed oracle, overwritten on success): -```json -{ "deployed_sha": "", "deployed_at": "", "outcome": "ok", - "tag": "deploy/" } -``` -`PENDING.json` (gitignored bridge, deleted on success): schema as in "Decisions resolved at plan time / §10". - -- [ ] **Step 4: Update `.gitignore`** - -```gitignore -# deploy: transient per-deploy state (the runbook/ledger/oracle ARE committed) -.claude/deploy/NEXT.sh -.claude/deploy/PENDING.json -``` - -- [ ] **Step 5: Verify templates are well-formed** - -Run: `bash -n templates/deploy/PROCEDURE.md && grep -c '^# @delta:' templates/deploy/PROCEDURE.md` -Expected: no syntax error; `3` annotations. - -- [ ] **Step 6: Commit** - -```bash -git add templates/deploy/PROCEDURE.md templates/deploy/INCIDENTS.md .gitignore -git commit -m "feat(deploy): runbook/ledger templates + bridge schemas + gitignore transient state" -``` - ---- - -### Task 3: `skills/deploy/SKILL.md` — the two-moment skill (REQUIRES writing-skills) - -> **At this task, invoke `superpowers:writing-skills`** to shape SKILL.md to house conventions AND to formalize the **cross-session cold-resume** form (deploy's defining novelty; `audit-delta` is the state-file precedent, `client-handover` only an in-context pause). The step behaviors below are the contract; writing-skills governs structure/frontmatter/spine. - -**Files:** -- Create: `skills/deploy/SKILL.md` - -**Interfaces:** -- Consumes: `lib/deploy-commit.sh` (Task 1); artifact shapes (Task 2). -- Produces: the runtime behavior. STEP spine below. - -**STEP spine (each = a SKILL.md section; [GATE] = mandatory stop):** - -- [ ] **STEP 0 — PRE-FLIGHT + RESUME BRANCH.** Read `.claude/deploy/PENDING.json` FIRST (state file = only memory between runs). - - `PENDING.json` present → **RESUME**: jump to STEP 3 with its `{base, target, delta, step_reached}` (do not recompute). - - else `PROCEDURE.md` absent → **BOOTSTRAP** (Task 4). - - else → FRESH: continue STEP 1. -- [ ] **STEP 1 — DELTA.** `base = STATE.json.deployed_sha` (or, if `STATE.json` absent, first-deploy = full runbook). `git diff --name-only HEAD` → delta file list. `target = git rev-parse HEAD`. -- [ ] **STEP 2 — INSTANTIATE + [GATE].** Expand `PROCEDURE.md`: emit fixed steps verbatim; expand `@delta:glob=…:each` steps by repeating the command per matching delta file, and `@delta:glob=…:list` steps once with matching files as `# VERIFY:` items; include `@delta:when=` steps only if the delta intersects. Read `INCIDENTS.md` and prepend matching `# PRE-WARN: DEP-NNN …` notes. Write `NEXT.sh`. **[GATE]** present `NEXT.sh` → `all / edit / skip-all`. On approve: write `PENDING.json` (`step_reached: awaiting-user`), then **hand back** (AskUserQuestion: "Run NEXT.sh step by step. Report back: Deployed OK / Failed at step X / Not yet"). -- [ ] **STEP 3 — RESUME / REACT** (entry point on the user's report; may be a fresh session). - - "Deployed OK" → STEP 5. - - "Failed at step X: " → STEP 4. - - "Not yet" → re-state pending, stop. -- [ ] **STEP 4 — LEARN + [GATE] + ATOMIC COMMIT.** Diagnose. Draft: (a) in-place `PROCEDURE.md` patch to step X; (b) `INCIDENTS.md` append `DEP-NNN` (error verbatim). **[GATE]** `all / pick / edit / skip-all` (significant edit). On approve: write both, then **one atomic** `bash lib/deploy-commit.sh commit "docs(deploy): patch — recovered from " .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. The commit that adds `DEP-NNN` IS its resolution (derive via git later). Then bump `PENDING.json.runbook_rev` to the new `PROCEDURE.md` commit sha (keep `step_reached` at X). **Resume = REGENERATE `NEXT.sh` from `step_reached` against the PATCHED runbook** (steps X…end — X+1…end never ran), NOT replay a single step. The bumped `runbook_rev` is exactly the trigger: runbook changed ⇒ prior `NEXT.sh` is stale ⇒ regenerate. Re-present via STEP 2's hand-back. -- [ ] **STEP 5 — MARK (success).** Write `STATE.json` (`deployed_sha = PENDING.target_sha`, outcome ok, tag). `git tag -a deploy/ -m ""`; **if `@config push_deploy_tags=true`** then `git push origin deploy/` (best-effort, non-fatal). `bash lib/deploy-commit.sh commit "chore(deploy): mark @ " .claude/deploy/STATE.json`. **Delete `PENDING.json`** (+ `NEXT.sh`). Report. - -- [ ] **Verification scenarios** (dry-run walkthroughs, no prod): - - First deploy (no `STATE.json`): full runbook fires; STATE laid; PENDING deleted. - - Delta deploy: only changed-bucket steps instantiate; `git diff` form is ` HEAD`. - - **Cold resume**: write a `PENDING.json` by hand, start `deploy` in a *fresh* context → STEP 0 detects it, resumes at STEP 3 from disk alone (no conversation memory). - - Failure→learn: report "failed at step X" → patch + DEP append committed atomically (one sha, both files). -- [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): two-moment cross-session skill (resumes cold from PENDING.json)"` - ---- - -### Task 4: Bootstrap (project without a runbook) - -**Files:** -- Modify: `skills/deploy/SKILL.md` (STEP 0 BOOTSTRAP branch) - -**Interfaces:** -- Consumes: `templates/deploy/*` (Task 2); STEP spine (Task 3). - -- [ ] **Step 1 — BOOTSTRAP branch + [GATE].** When `PROCEDURE.md` absent, offer two paths (AskUserQuestion): - - **Paste** — user provides an existing runbook → adopt verbatim, then propose `@delta:` annotations for migration/build/deps steps. - - **Scaffold** — detect artifacts (`supabase/migrations/`, `docker-compose*.yml`/`Dockerfile`, `package.json`/lockfiles, `.env*`) + short interview (ssh host, backup cmd, health URL, rollback note) → fill `templates/deploy/PROCEDURE.md`. - - **[GATE]** present drafted `PROCEDURE.md` → `all / edit / skip-all`. On approve: write `PROCEDURE.md` + empty `INCIDENTS.md`; `bash lib/deploy-commit.sh commit "feat(deploy): bootstrap runbook" .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. First deploy then proceeds (no STATE.json ⇒ full runbook). -- [ ] **Step 2 — Verify:** dry-run on a repo with `supabase/migrations/` + `docker-compose.yml` present → scaffold proposes migration + rebuild steps annotated; on a bare repo → interview-only path. -- [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): bootstrap — paste-or-scaffold initial runbook"` - ---- - -## Gates identified - -- **[GATE] STEP 2** — approve instantiated `NEXT.sh` before hand-back. -- **[GATE] STEP 4** — approve runbook patch + `DEP-NNN` incident before the atomic learning commit. -- **[GATE] STEP 0/Task 4** — approve scaffolded `PROCEDURE.md` before first write. -- **Hand-back (STEP 2→3)** — AskUserQuestion is the resume point; the user executes out-of-band. -- **Task gates** — each Task ends test-green + shellcheck-clean + committed before the next (deps: 1 → 2 → 3 → 4). - -## Self-review - -- **Spec coverage:** 4 artifacts + bridge (§3/§10) → Task 2; STATE-oracle + ` HEAD` delta (§4) → Task 1 constraints + STEP 1; runbook+INCIDENTS learning, atomic couple (§5) → STEP 4; `deploy-commit.sh` inverse allowlist (§6) → Task 1; bootstrap (§7) → Task 4; two-moment cold resume (§10) → STEP 0/2/3 + PENDING.json. All §8 items resolved above. ✓ -- **Placeholder scan:** none — helper code, test code, schemas, annotation grammar all concrete. -- **Type consistency:** `STATE.json.deployed_sha` (STEP 1 base, STEP 5 write), `PENDING.json.{base_sha,target_sha,delta,step_reached}` (STEP 0 read, STEP 2 write, STEP 4 update), `deploy-commit.sh commit "" ...` (Tasks 1/3/4) — names align. -- **Open at execution (not assumed):** the `writing-skills` consultation in Task 3 may rename/restructure SKILL.md sections to match the formalized cold-resume convention, and finalizes the `@delta:` `:each`/`:list` keyword spelling (both semantics mandatory); STEP behaviors and the §6 helper contract above are fixed regardless. - -## Execution Handoff - -Build order is strict by dependency: **Task 1 (helper, foundation) → Task 2 (formats) → Task 3 (skill, writing-skills) → Task 4 (bootstrap)**. diff --git a/docs/specs/2026-06-27-deploy-skill-design.md b/docs/specs/2026-06-27-deploy-skill-design.md deleted file mode 100644 index a70ced8..0000000 --- a/docs/specs/2026-06-27-deploy-skill-design.md +++ /dev/null @@ -1,165 +0,0 @@ -# Deploy skill — design spec - -> **Superseded by BDR-054** (`52f6678`): the shipped skill has NO `NEXT.sh` file and NO -> AskUserQuestion hand-back — see `skills/deploy/SKILL.md` for current behavior. This -> spec is kept as historical record; do not implement its NEXT.sh/hand-back sections. - -- **Date:** 2026-06-27 -- **Status:** Design approved (5 knobs settled). **No skill code written yet.** Next step = implementation plan. -- **Scope:** A new `deploy` skill = a per-project shell RUNBOOK that lives in `.claude/deploy/`, gets re-instantiated from the delta since the last deploy, and LEARNS from deploy errors in place. - -## 1. Vision — deployment memory that learns - -Three moments: - -1. **BEFORE** — produce the *instantiated* runbook: reference runbook + delta since last deploy, parameterized steps rewritten with the real artifacts (e.g. the migration step lists the migrations actually added since last deploy, not the runbook's examples). -2. **DURING** — the **user executes out-of-band** (prod ssh — Claude must not run it) and reports `deployed and tested` OR `failed at step X, here is the error` → fix together until success. -3. **AFTER** — on confirmed success: (a) if errors were hit + fixed, update the reference runbook so the next deploy does not repeat them; (b) lay the marker "deployed up to here" for the next diff. - -Structural ancestor in the corpus: `client-handover` (BEFORE baseline → DURING user-deploy gate via `AskUserQuestion` → AFTER validate + react). No existing skill owns a learning per-project runbook — clean gap, no `.claude/deploy/` precedent. - -## 2. Locked decisions - -| # | Knob | Decision | -|---|------|----------| -| 1 | Marker / oracle | **STATE file is the oracle** (deployed SHA), **annotated tag** added as a human bookmark only | -| 2 | Learning storage | **In-place runbook edits + append-only `INCIDENTS.md`** (distinct jobs, atomic coupling) | -| 3 | Parameterization | **`# @delta:` annotations** bind dynamic steps to path-patterns; un-annotated steps are fixed | -| 4 | Bootstrap | **Offer both** — user pastes an existing runbook OR skill scaffolds via artifact detection + interview | -| 5 | Execution model | **`NEXT.sh` is a step-by-step CHECKLIST** — runnable shell, but driven by hand with manual `# VERIFY:` gates; never `bash NEXT.sh` unattended | - -**Why #5 is design-time, not impl:** the execution model is load-bearing for moments 2 and 3. Moment 2 is defined as "user reports *failed at step X*", and moment 3's LEARN loop must know *which* step failed to patch it. A single `bash NEXT.sh` blob collapses both into "exited non-zero somewhere" and can strand a prod deploy (migrations, restarts) in partial state with no step control. Checklist is *entailed* by the three-moment structure, not merely safer. - -Treated as settled corollaries: user executes out-of-band; a **new** `lib/deploy-commit.sh` helper (existing helpers cannot commit the runbook — see §6, verified). - -## 3. Architecture - -``` -.claude/deploy/ - PROCEDURE.md reference runbook — fixed shell + `# @delta:` annotated steps (edited IN-PLACE) - INCIDENTS.md DEP-NNN incident ledger: date, step, error verbatim, root cause, - fix (APPEND-ONLY; resolution = introducing commit, derive via git) - STATE.json deployed SHA + timestamp + outcome — the diff oracle (overwritten each deploy) - NEXT.sh instantiated runbook — EPHEMERAL, not committed ; run STEP-BY-STEP - (checklist, manual # VERIFY: gates) — never `bash NEXT.sh` unattended - -lib/deploy-commit.sh surgical commit, allowlist = .claude/deploy/ , rc3 unsafe-git guard, short-hash stdout - -Skill STEP spine (PRE-FLIGHT -> PROPOSE+GATE -> WRITE+COMMIT, house style): - 0 PRE-FLIGHT runbook present? absent -> bootstrap (paste | scaffold+interview) - 1 DELTA STATE absent -> first deploy = full runbook ; else diff HEAD - 2 INSTANTIATE expand @delta steps + read INCIDENTS pre-warns -> NEXT.sh -> GATE - 3 (user executes out-of-band; reports "done" | "failed at step X: ") - 4 LEARN on failure: patch PROCEDURE step + append DEP-NNN -> GATE -> deploy-commit (ATOMIC) - 5 MARK on success: write STATE@sha ; annotate + push tag ; optional doc -``` - -## 4. Delta mechanism — verified (git 2.53.0) - -All three facts re-run live before writing this spec; observed output recorded, not assumed. - -**First-deploy detection = STATE-absent, deterministic. `describe` is off the detection path.** -``` -[ -f .claude/deploy/STATE.json ] => exit 1 (absent = first deploy) <- THE detector -git describe --tags --match 'deploy/*' => fatal: No names found ; exit 128 <- only the reason NOT to use describe -[ -f .claude/deploy/STATE.json ] => exit 0 (present = delta path) -``` - -**Delta = `git diff --name-only HEAD`** (two explicit endpoints; no dots, so it cannot be misread as three-dot). -``` -LINEAR git diff --name-only HEAD => 0033_new.sql, svc.yml (== two-dot == three-dot; merge-base == STATE) -DIVERGED two-dot sideA sideB => fileA.txt, fileB.txt (both endpoints = true tree delta) -DIVERGED three-dot sideA...sideB => fileB.txt (merge-base — UNDERCOUNTS) -``` -Two-dot/explicit-endpoints is the literal tree difference between the deployed tree and HEAD = what deploy needs. It is also rebase-robust: an orphaned marker still yields the correct tree diff, whereas `git rev-list A..B` (ancestry) reports phantom deltas after history rewrite (LRN-054's trap; verified in an earlier run). **Never use `rev-list` ancestry for the artifact list.** - -**delta -> steps:** `# @delta:` annotations bind a dynamic step to the path-pattern that feeds it; the diff buckets straight into steps: -``` -# @delta:migrations glob=supabase/migrations/*.sql -# @delta:rebuild when=docker-compose*.yml,Dockerfile -# @delta:deps when=package.json,*lock* -``` - -## 5. Learning model — runbook + INCIDENTS, non-redundant - -| Artifact | Job | Lifecycle | -|---|---|---| -| `PROCEDURE.md` | The corrected procedure you run. A fix is baked into the step so the next run cannot repeat it. | in-place | -| `INCIDENTS.md` | The incident ledger; **read at BEFORE-time to pre-warn** ("0033 hit a lock timeout last deploy; runbook already carries `--timeout`, watch for it"). | append-only | - -The pre-warn read is the function `git log` serves badly — that is why the ledger is not duplication. This mirrors the memory system's own split (append-only `journal.md`/`blockers.md` alongside in-place TODO/code). - -**Coupling invariant:** one incident → **one in-place `PROCEDURE.md` patch + one `INCIDENTS.md` append, committed atomically in a single `deploy-commit.sh` call.** Never one without the other (mirrors BDR-034/036 "couple the commit to the integration step"). Significant patch (changes a prod path) → surface + approve before writing. - -## 6. `lib/deploy-commit.sh` — new helper, inverse `.claude/` rule (verified) - -Neither existing helper can commit the runbook — confirmed live: -``` -REAL doc-commit.sh .claude/deploy/PROCEDURE.md => rc 4 "REFUSED — out-of-scope ... BDR-022 ... NOTHING committed" -REAL memory-commit.sh pending (deploy changed) => rc 1 (ignores it; allowlist = .claude/memory|tasks only) -``` -`doc-commit.sh` is built to keep `.claude/**` *out* of public-doc commits; `.claude/deploy/` is under `.claude/`, so reuse is not just blocked, it is semantically wrong. `deploy-commit.sh` needs the **inverse** rule: a TARGET allowlist for `.claude/deploy/*`, modeled on `memory-commit.sh` (rc 3 unsafe-git guard, short-hash on stdout, `chore(deploy):`/`docs(deploy):` messages). - -Allowlist guard — traversal reject ordered FIRST. Prototype matrix verified live: -```sh -_in_deploy_scope() { - case "$1" in - *..*) return 1 ;; # reject path traversal FIRST - .claude/deploy/*) return 0 ;; # ALLOW the deploy family only - *) return 1 ;; # reject everything else - esac -} -``` -``` -ALLOW .claude/deploy/{PROCEDURE.md,INCIDENTS.md,STATE} -REJECT .claude/memory/* .claude/tasks/* .claude/secret CLAUDE.md src/* -REJECT .claude/deploy (bare dir, no slash) -REJECT .claude/deploy-other/x (trailing-slash requirement closes prefix confusion) -REJECT .claude/deploy/../memory/secret (traversal closed by *..* matched first) -``` - -## 7. Bootstrap - -`STEP 0 PRE-FLIGHT`: `PROCEDURE.md` present? Absent → bootstrap, two offered paths: -1. **Paste** — user supplies an existing runbook (the game example); skill adopts + annotates it. -2. **Scaffold** — skill detects deploy artifacts (migrations dir, compose/Dockerfile, package scripts, `.env`) + a short interview (ssh target, backup cmd, rollback note) → writes an annotated `PROCEDURE.md`. - -First deploy has no marker → STATE-absent ⇒ full runbook fires; then lay STATE at the deployed SHA. The first deploy *is* the creation of the runbook + the first marker. - -## 8. Open items (for the implementation plan) - -> `NEXT.sh` execution model resolved → decision #5 (checklist), promoted to design-time. - -- Tag push: tags don't push by default → AFTER step should `git push --tag deploy/` or remind. -- `INCIDENTS.md` ID/format detail (mirror `blockers.md` `DEP-NNN`); confirm name vs `ERRORS-LEARNED.md`. -- `@delta:` annotation grammar (glob= vs when=) — finalize the small DSL. -- Frontmatter `allowed-tools` set; STEP gate wording reuse from `capitalize`/`client-handover`. - -## 9. Build sequencing & a structural flag - -**Two distinct disciplines, in order — do not conflate:** -1. `writing-plans` — global task ordering (helper → skill → bootstrap), dependencies, gates. The build plan. -2. → execution → -3. At the *skill* task ONLY: `writing-skills` — the discipline for the SKILL.md itself (structure, frontmatter, spine, config conventions). Used WHEN we reach the skill task, **not before** (it does not fire at plan time). - -**Structural flag for `writing-skills` to resolve — do NOT assume the linear-spine convention suffices:** -deploy's spine is unusual — **two parts split by out-of-band execution**: STEP 0–2 before → *user deploys by hand* → STEP 4–5 after, on the `done`/`failed` report. A skill that **hands back control mid-run and resumes**. - -Preliminary recon (confirm at the skill task — NOT verified now): -- The 6 completion flux (close, ship-feature, feat, bugfix, hotfix, commit-change) appear linear one-shot — synchronous gates at most, no out-of-band hand-back. -- The relevant precedent is OUTSIDE those 6: `client-handover` already hands back — a synchronous "Deploy done?" `AskUserQuestion` pause (STEP 5) — but it holds state in *conversation context*, not on disk. -- deploy's genuinely-new bit *may* be **disk-bridged resume** (`NEXT.sh` + `STATE` on disk as the bridge) — but **whether `NEXT.sh` alone suffices to resume cross-session is an OPEN design question, not a settled answer** (see §10). An earlier draft of this spec framed it as resolved; it is not. `writing-skills` must establish the convention (how to mark "I wait for your return here", detect + resume a pending deploy, hold state across the gap) — confirm there, do not assume the linear mould suffices. - -## 10. Open design question (DESIGN-TIME, unresolved) — state across the two moments - -deploy is a **two-moment skill**: moments 0–2 (BEFORE) → user deploys out-of-band → moment 3 (AFTER) on the `done`/`failed` report. **The report may arrive in a different session.** So the design must answer how state crosses the gap and what moment 3 must know to resume correctly. - -> **`skill deux-temps, état entre temps = [à concevoir : NEXT.sh seul suffit-il pour reprendre cross-session ?]`** - -Sub-questions (to settle when we resume — NOT now, NOT assumed): -- **What must the bridge record?** Moment 3 must (a) lay the correct marker = `STATE ← target sha`, and (b) capitalize the correct incident (which step, which delta). HEAD may have moved since NEXT.sh was generated → "current HEAD" is unsafe. The bridge must persist at least **{base STATE sha, target sha, delta manifest}** — inside NEXT.sh (header block) or a sidecar (`.claude/deploy/PENDING`)? Undecided. -- **Resume detection (re-entrancy):** STEP 0 PRE-FLIGHT must detect "a deploy is pending, awaiting your report" — likely *pending-bridge present + STATE not advanced to target* — and branch RESUME (ask done/failed) vs FRESH. Is moment 3 a new `deploy` call that re-detects from disk, or a `deploy --report`? Undecided. -- **Ephemeral vs persistent tension — LINKED to sub-question 1 (not independent).** §3 calls NEXT.sh "EPHEMERAL, not committed", yet a cross-session bridge MUST survive on disk. So: **if the bridge must persist, NEXT.sh-as-bridge is impossible while NEXT.sh stays ephemeral.** Likely *binary* resolution at plan time — either (a) NEXT.sh becomes persistent (contradicts §3), or (b) the bridge is a **separate** "deploy-in-progress" artifact `{base/target/delta}` distinct from NEXT.sh. Settle with `writing-skills`. (Uncommitted local state is fine; note the single-machine assumption — an uncommitted bridge won't follow a clone.) -- **Form-novelty — deploy's DEFINING characteristic: cross-session COLD resume.** `client-handover` is a *near* precedent, not exact: it hands back **in-context** (same conversation, state held in memory). deploy must resume with the **context lost** — so the **disk alone must carry everything to resume cold**. No existing skill resumes without context; that is what sets deploy apart, and it makes sub-question 1 **load-bearing** (disk must suffice for a cold restart). deploy likely introduces a NEW skill form → `writing-skills` establishes the convention. Confirm there. - -**Next step:** `writing-plans` to turn this spec into an implementation plan (helper first, then skill); at the skill task, `writing-skills` to shape it to convention and **resolve the §10 two-moment state question** — which is design-time, deferred only because we are stopped here, not because it is impl detail. diff --git a/docs/superpowers/plans/2026-07-15-model-routing.md b/docs/superpowers/plans/2026-07-15-model-routing.md deleted file mode 100644 index 6c76e2f..0000000 --- a/docs/superpowers/plans/2026-07-15-model-routing.md +++ /dev/null @@ -1,1953 +0,0 @@ -# Model Routing Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Reflection (planning, audits, loop decisions) stays on the session big model behind a blocking gate; execution (code from a closed plan, fix-bundle application) runs on sonnet-pinned subagents. - -**Architecture:** A deterministic witness (`lib/model-check.sh`) + a blocking include (`lib/model-gate.md`) wired into 12 reflection orchestrators; frontmatter `model:` pins on executor agents; `/feat` re-architected from inline playbook to "plan inline → dispatch sonnet executor"; SDD implementation subagents and web-validate fix application routed to sonnet. - -**Tech Stack:** bash (shellcheck-clean), Claude Code SKILL.md/agent.md markdown, agent frontmatter `model:` field, Makefile test loop. - -**Spec:** `docs/superpowers/specs/2026-07-15-model-routing-design.md` (approved 2026-07-15). - -## Global Constraints - -- Work on branch `feature/model-routing` (already checked out). Commit per task. NEVER merge/finish — human gate. -- NO commit attribution trailers of any kind (Co-Authored-By, Claude-Session) — user ban, guards will red. -- `make test` must be green at every commit (run from repo root `/home/bchanot/Documents/claude`). -- New/edited `.sh` files: `shellcheck ` clean and `bash -n ` clean. -- The `config-protection` PreToolUse hook BLOCKS Edit/Write on `lib/tests/*`, `hooks/*`, `settings.json`, `lib/gitflow.sh`. Before EACH Edit/Write to `lib/tests/*` in this plan, write the one-shot bypass sentinel (consumed per use): `printf 'model-routing plan: ' > .claude/.config-edit-ok` -- Agent frontmatter must stay `yaml.safe_load`-parseable (job9 gate): if a value contains `: `, quote it. -- Memory registries: append-only, caveman format, English. -- SPEC §5 (client-handover conversion) is DEFERRED to a separate plan — do NOT touch `agents/client-handover-writer.md` or `skills/client-handover/SKILL.md` in this plan. - ---- - -### Task 1: `lib/model-check.sh` witness + flip-tests - -**Files:** -- Create: `lib/model-check.sh` -- Test: `lib/tests/model-check.test.sh` (guarded path — sentinel required) - -**Interfaces:** -- Consumes: `$HOME/.claude/settings.json` `"model"` key; env override `MODEL_CHECK_SETTINGS=` for fixtures. -- Produces: stdout `:` where class ∈ `big|small|unknown`; exit `0`=big, `2`=small, `3`=unknown. Task 2's `lib/model-gate.md` calls `bash "$HOME/.claude/lib/model-check.sh"` and branches on these exact codes. - -- [ ] **Step 1: Write the failing test** - -```bash -printf 'model-routing plan: create model-check flip-tests' > .claude/.config-edit-ok -``` - -Then create `lib/tests/model-check.test.sh` with exactly: - -```bash -#!/usr/bin/env bash -# lib/tests/model-check.test.sh — flip-tests for lib/model-check.sh (LRN-096) -set -u -S="$(cd "$(dirname "$0")/../.." && pwd)/lib/model-check.sh" -pass=0; fail=0 -check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1)); - printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; } -T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT - -fx() { printf '{"model": "%s"}' "$1" > "$T/s.json"; } -run() { MODEL_CHECK_SETTINGS="$T/s.json" bash "$S" >"$T/out" 2>&1; echo "$?"; } - -fx 'claude-fable-5[1m]'; check T1-fable-exit "$(run)" 0 -check T1-fable-class "$(cut -d: -f1 <"$T/out")" big -fx 'claude-opus-4-8'; check T2-opus "$(run)" 0 -fx 'claude-sonnet-5'; check T3-sonnet "$(run)" 2 -fx 'claude-haiku-4-5-20251001'; check T4-haiku "$(run)" 2 -fx 'opusplan'; check T5-opusplan "$(run)" 3 -fx 'gpt-9-mega'; check T6-foreign "$(run)" 3 -printf '{"no_model": true}' > "$T/s.json"; check T7-no-key "$(run)" 3 -printf '{broken' > "$T/s.json"; check T8-malformed "$(run)" 3 -check T9-missing-file "$(MODEL_CHECK_SETTINGS="$T/absent.json" bash "$S" >/dev/null 2>&1; echo $?)" 3 - -printf 'model-check: %d pass, %d fail\n' "$pass" "$fail" -[ "$fail" -eq 0 ] -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `bash lib/tests/model-check.test.sh` -Expected: FAIL on every check (script missing → bash exits non-zero, got[127]-style mismatches), final line `model-check: 1 pass, 9 fail` or similar non-zero fail count, exit 1. (T1-fable-class may pass vacuously on empty output only if cut returns empty — any red is enough: the suite CAN fail.) - -- [ ] **Step 3: Write the implementation** - -Create `lib/model-check.sh` with exactly: - -```bash -#!/usr/bin/env bash -# lib/model-check.sh — classify the persisted session model: big | small | unknown -# -# Witness for lib/model-gate.md (reflection requires a big model). Reads the -# "model" key of the user-scope settings (the file /model rewrites — LRN-098). -# Override the source with MODEL_CHECK_SETTINGS (tests use fixtures). -# -# stdout : : (raw = value found, empty if none) -# exit : 0 = big (fable/opus) · 2 = small (sonnet/haiku) · 3 = unknown -set -u - -SETTINGS="${MODEL_CHECK_SETTINGS:-$HOME/.claude/settings.json}" - -raw="" -if [ -f "$SETTINGS" ]; then - raw="$(python3 - "$SETTINGS" 2>/dev/null <<'PY' -import json, sys -try: - v = json.load(open(sys.argv[1])).get("model", "") - print(v if isinstance(v, str) else "") -except Exception: - print("") -PY -)" -fi - -norm="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')" -case "$norm" in - *opusplan*) printf 'unknown:%s\n' "$raw"; exit 3 ;; # opus-for-plan, sonnet otherwise — ambiguous - *fable*|*opus*) printf 'big:%s\n' "$raw"; exit 0 ;; - *sonnet*|*haiku*) printf 'small:%s\n' "$raw"; exit 2 ;; - *) printf 'unknown:%s\n' "$raw"; exit 3 ;; -esac -``` - -(The heredoc passes the settings path as `sys.argv[1]` — never pipe INTO a heredoc'd interpreter, LRN-012.) - -- [ ] **Step 4: Run test to verify it passes** - -Run: `bash lib/tests/model-check.test.sh` -Expected: `model-check: 10 pass, 0 fail`, exit 0. - -- [ ] **Step 5: Lint** - -Run: `shellcheck lib/model-check.sh lib/tests/model-check.test.sh && bash -n lib/model-check.sh` -Expected: no output (clean), exit 0. - -- [ ] **Step 6: Full suite + commit** - -Run: `make test` -Expected: every suite line green, exit 0. - -```bash -git add lib/model-check.sh lib/tests/model-check.test.sh -git commit -m "feat(model-routing): model-check witness (big/small/unknown) + flip-tests" -``` - ---- - -### Task 2: `lib/model-gate.md` blocking include - -**Files:** -- Create: `lib/model-gate.md` - -**Interfaces:** -- Consumes: `lib/model-check.sh` exit codes (Task 1). -- Produces: the include that Tasks 3 and 5 reference verbatim as `` `$HOME/.claude/lib/model-gate.md` ``. - -- [ ] **Step 1: Create the include** - -Create `lib/model-gate.md` with exactly: - -```markdown -# Model gate — reflection requires a big model (BLOCKING) - -Shared include. Runs FIRST in any orchestrator whose reflection — -brainstorming, planning, contract, audit judgment, loop decisions — -executes inline or in inherit-model subagents. Sonnet-pinned executors are -not what this gate protects; it protects the thinking around them (BDR-066). - -## 1. Self-check - -Your system prompt names the model powering this session. Fable or Opus → -big. Sonnet, Haiku, anything else → small. - -## 2. Witness — deterministic check - - bash "$HOME/.claude/lib/model-check.sh" - -Output `:`; exit 0 = big, 2 = small, 3 = unknown. The witness -reads the PERSISTED model (settings.json — the file `/model` rewrites, -LRN-098). It can lag reality (session launched with `--model`, settings not -yet rewritten) — that is why the self-check exists alongside it. - -## 3. Verdict - -| self-check | witness | action | -|---|---|---| -| big | big (0) | proceed, SILENT — the nominal path prints nothing | -| small | any | **STOP** | -| big | small (2) | disagreement — **STOP**, surface BOTH values; the user confirms or relaunches | -| big | unknown (3) | fail-visible: print `model gate: witness unknown () — self-check says ` and ask the user to confirm before continuing (BDR-025: unknown never silently passes) | - -**STOP means**: print exactly - - ⛔ MODEL GATE — session on . Reflection steps of this skill - require Fable or Opus. Switch with /model, then relaunch the skill. - -then end the turn. No later step runs, no agent is dispatched, nothing is -edited. -``` - -- [ ] **Step 2: Commit** - -```bash -git add lib/model-gate.md -git commit -m "feat(model-routing): blocking model-gate include (self-check + witness)" -``` - ---- - -### Task 3: Wire the gate into the 12 reflection orchestrators - -**Files:** -- Modify: `skills/ship-feature/SKILL.md`, `skills/init-project/SKILL.md`, `skills/onboard/SKILL.md`, `skills/seo/SKILL.md`, `skills/geo/SKILL.md`, `skills/web-validate/SKILL.md`, `skills/harden/SKILL.md`, `skills/audit-delta/SKILL.md`, `skills/tour/SKILL.md` (orchestrator idiom), `skills/feat/SKILL.md`, `skills/bugfix/SKILL.md`, `skills/code-clean/SKILL.md` (thin-wrapper idiom) - -**Interfaces:** -- Consumes: `lib/model-gate.md` (Task 2). -- Produces: the string `lib/model-gate.md` present in each of the 12 files — Task 8's census greps exactly this. - -- [ ] **Step 1: Insert the orchestrator gate block (9 files)** - -For each of the 9 orchestrator skills, Edit with `old_string` = the file's unique H1 line (below), `new_string` = the same H1 line followed by a blank line and this exact block: - -```markdown -## MODEL GATE (blocking — run before any other step) - -Run `$HOME/.claude/lib/model-gate.md`. Reflection here (planning, audit -judgment, loop decisions) requires Fable/Opus. Verdict `small` → STOP: the -gate prints the remedy; end the turn — no later step, no dispatch. Nominal -(big) path is silent. -``` - -H1 anchors (verbatim, one per file): -- `skills/ship-feature/SKILL.md` → `# ORCHESTRATOR: SHIP FEATURE` -- `skills/init-project/SKILL.md` → `# ORCHESTRATOR: INIT PROJECT` -- `skills/onboard/SKILL.md` → `# ORCHESTRATOR: ONBOARD` -- `skills/seo/SKILL.md` → `# /seo — parallel SEO + GEO dispatcher` -- `skills/geo/SKILL.md` → `# /geo — GEO (AI-search) audit + fix dispatcher` -- `skills/web-validate/SKILL.md` → `# /web-validate — web standards audit (W3C + WCAG)` -- `skills/harden/SKILL.md` → `# /harden — web hardening audit` -- `skills/audit-delta/SKILL.md` → `# /audit-delta — Incremental multi-axis code audit` -- `skills/tour/SKILL.md` → `# /tour — grouped multi-axis sweep (clean + security + reconcile + doc)` - -- [ ] **Step 2: Insert the thin-wrapper gate paragraph (3 files)** - -For `skills/feat/SKILL.md`, `skills/bugfix/SKILL.md`, `skills/code-clean/SKILL.md`: Edit with `old_string` = `Load and follow strictly:` and `new_string` = - -```markdown -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: -``` - -(`Load and follow strictly:` occurs once per file — safe anchor.) - -- [ ] **Step 3: Verify the wiring by census** - -Run: `for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean; do grep -L 'lib/model-gate.md' "skills/$s/SKILL.md"; done` -Expected: no output (grep -L lists files MISSING the pattern — empty = all wired). - -Run: `for s in hotfix commit-change doc status release-candidate; do grep -l 'lib/model-gate.md' "skills/$s/SKILL.md"; done` -Expected: no output (excluded skills stay unwired). - -- [ ] **Step 4: Full suite + commit** - -Run: `make test` -Expected: green, exit 0. - -```bash -git add skills/ship-feature/SKILL.md skills/init-project/SKILL.md skills/onboard/SKILL.md skills/seo/SKILL.md skills/geo/SKILL.md skills/web-validate/SKILL.md skills/harden/SKILL.md skills/audit-delta/SKILL.md skills/tour/SKILL.md skills/feat/SKILL.md skills/bugfix/SKILL.md skills/code-clean/SKILL.md -git commit -m "feat(model-routing): wire blocking model gate into 12 reflection orchestrators" -``` - ---- - -### Task 4: Frontmatter pins — hotfixer sonnet, analyzer un-pinned - -**Files:** -- Modify: `agents/hotfixer.md:1-5` (frontmatter) -- Modify: `agents/analyzer.md:1-7` (frontmatter) - -**Interfaces:** -- Produces: `model: sonnet` line in hotfixer frontmatter (Task 7's applier dispatches and seo/geo L1 appliers ride on it); NO `model:` line in analyzer frontmatter (inherits session). Task 8's census greps both. - -- [ ] **Step 1: Pin hotfixer** - -Edit `agents/hotfixer.md`, `old_string`: - -``` -tools: Read, Edit, Write, Bash, Grep, Glob, Agent ---- -``` - -`new_string`: - -``` -tools: Read, Edit, Write, Bash, Grep, Glob, Agent -model: sonnet ---- -``` - -- [ ] **Step 2: Un-pin analyzer** - -Edit `agents/analyzer.md`, `old_string`: - -``` -tools: Read, Grep, Glob, Bash -model: haiku -memory: project -``` - -`new_string`: - -``` -tools: Read, Grep, Glob, Bash -memory: project -``` - -- [ ] **Step 3: Verify YAML stays parseable** - -Run: `python3 -c "import yaml,sys; [yaml.safe_load(open(f).read().split('---')[1]) for f in ['agents/hotfixer.md','agents/analyzer.md']]; print('YAML OK')"` -Expected: `YAML OK`. - -- [ ] **Step 4: Full suite + commit** - -Run: `make test` -Expected: green (includes the job9 review guards). - -```bash -git add agents/hotfixer.md agents/analyzer.md -git commit -m "feat(model-routing): pin hotfixer sonnet (executor), un-pin analyzer (inherits session)" -``` - ---- - -### Task 5: `/feat` re-architecture — reflection inline, execution dispatched - -**Files:** -- Modify (full rewrite): `skills/feat/SKILL.md` -- Modify (full rewrite): `agents/feater.md` -- Modify (3 surgical edits): `lib/verify-secure-loop.md` - -**Interfaces:** -- Consumes: `lib/model-gate.md` (Task 2), `lib/verify-secure-loop.md`, `lib/contract-interview.md`, `lib/gitflow-aiguillage.md`, `lib/analyze-before-plan.md`, `lib/design-gate.md` (all existing). -- Produces: `Agent(subagent_type="feater")` dispatch in feat/SKILL.md; feater `FEAT-EXEC REPORT` grammar `STATUS : DONE | NEED-DECISION | BLOCKED`; `model: sonnet` in feater frontmatter. Task 8's census greps `subagent_type="feater"`, `verify-secure-loop.md`, feater `model: sonnet`, feater has NO `AskUserQuestion`. - -- [ ] **Step 1: Rewrite `skills/feat/SKILL.md`** - -Replace the ENTIRE file content with: - -````markdown ---- -name: feat -description: | - Small feature implementation (1-5 files). Reflection inline (scope, - plan, contract — session model), execution dispatched to the - sonnet-pinned feater executor. For features that don't need the full - /ship-feature pipeline (no design brainstorm, no plugin check gate). - Trigger: "feat", "small feature", "add this", "petite feature", - "quick feature", "ajoute ca", "implement this small thing". - For multi-file features needing design → use /ship-feature. - For bug fixes → use /hotfix or /bugfix. -argument-hint: -allowed-tools: - - Read - - Edit - - Write - - Bash - - Grep - - Glob - - Agent ---- - -# /feat — small-feature orchestrator (reflection inline, execution dispatched) - -MODEL GATE (blocking): run `$HOME/.claude/lib/model-gate.md` BEFORE any -step below. Verdict `small` → STOP — print the gate's remedy, end the -turn, dispatch nothing. - -## REQUEST -$ARGUMENTS - ---- - -## STEP 0 — SCOPE CHECK - -Before starting, verify this is actually a small feature: - -```bash -git status -git log --oneline -3 -``` - -Read the relevant existing code to understand the context. - -### Decision rules (apply in order — first match wins) - -| Rule | Trigger | Action | -|---|---|---| -| 1 | Estimated diff < 2 files AND no logic (config value, copy fix, missing field) | DOWNGRADE → load `$HOME/.claude/agents/hotfixer.md` | -| 2 | New external dependency (`npm install `, `pip install`, `cargo add`) required | ESCALATE → `/ship-feature` (dep choices need design gate) | -| 3 | New route family / new top-level module / new DB migration | ESCALATE → `/ship-feature` | -| 4 | Estimated diff > 5 files | ESCALATE → `/ship-feature` | -| 5 | User wording is uncertain ("not sure how", "what do you think") | ESCALATE → `/ship-feature` (needs brainstorming) | -| 6 | UI feature on a stack with a design system AND the design toolchain incomplete | Proceed in `/feat`, but flag it in STEP 0.5 design gate | -| 7 | Otherwise | PROCEED in `/feat` | - -### Worked examples - -- "Add `/health` endpoint returning `{status:"ok",version}`" → 1-2 files, no new dep, route added to existing router → **PROCEED**. -- "Add a dark-mode toggle bound to `prefers-color-scheme`" → 2-3 files, design system exists → **PROCEED** (design gate triggers in STEP 0.5). -- "Add OAuth login (Google + GitHub providers)" → new deps, new routes, secrets handling → **ESCALATE** to `/ship-feature`. -- "Show a 'New' badge on items created this week" → 1-2 files, pure UI predicate → **PROCEED**. -- "Fix copy: 'Sign In' → 'Sign in'" in 1 file → **DOWNGRADE** to `/hotfix`. - -Print a one-line scope confirmation (use the rule that fired): -``` -FEAT: — rule , ~ files, -``` - -## STEP 0.5 — DESIGN GATE - -Follow `$HOME/.claude/lib/design-gate.md`: -- Scan $ARGUMENTS and target files for design/UI/style signals. -- If signals found → run `design-tool-gate.sh`; if it reports INCOMPLETE, - tell the user to run `/profile design` before proceeding. -- If no signals → skip (zero overhead). - -## STEP 0.6 — MEMORY READ-BEFORE (decisions-first) - -Run the scan per `$HOME/.claude/lib/analyze-before-plan.md`, decisions-weighted: a BDR may -already constrain or forbid the approach; an LRN may name a gotcha to apply. Emit RELATED -MEMORY; feed STEP 1 PLAN. Inline consumption — reader = planner, no injection. -`.claude/memory/` absent → guarded no-op (zero overhead on a memory-less repo). - -## STEP 0.7 — CONTRACT - -Run `$HOME/.claude/lib/contract-interview.md` (main loop — you are it). It -captures the request verbatim, asks 0-3 questions PROPORTIONAL to ambiguity -(a complete request → zero questions, silent), derives testable acceptance -criteria + file scope, and writes the contract to -`.claude/tasks/contracts/--.md`. Keep the path — the -executor reads it first and GATE 1 (STEP 4) hands it to a fresh verifier. - -## STEP 1 — PLAN (dispatch-ready) - -The executor follows this plan to the letter and CANNOT ask questions — -close every decision here: - -1. Files to create or modify (with line references). -2. Approach in 2-5 bullets — name every choice (naming, data shape, API - surface); an open choice left here comes back as a NEED-DECISION - round-trip. -3. Edge cases to handle. -4. Tests to add/update (exact files). -5. Disposition (from STEP 0.6): name each in-force BDR/LRN this plan honors - (`honors BDR-xxx by …`), or state `no in-force decision constrains this feature`. - A plan with neither = read-then-ignore; the disposition must surface as a trace. - -Print the plan as a compact checklist: -``` -PLAN: - [ ] — - [ ] — - [ ] — -``` - -If the approach is ambiguous: ask the user ONE focused question BEFORE -dispatching — never after (the executor cannot relay questions). - -## STEP 2 — BRANCH - -**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` -— your type = `feature`. On `main`/`develop` it branches first; on a working -branch it's a no-op (commit in place). Never `finish`. - -## STEP 3 — DISPATCH EXECUTOR - -Dispatch the executor — sonnet by frontmatter pin, do not override: - -``` -Agent(subagent_type="feater") -prompt: "CONTRACT: -PLAN: -BRANCH: -Implement the plan to the letter. Tests alongside code. No commit, no -branch ops, no new dependencies, no files outside the contract FILE SCOPE. -Finish with the FEAT-EXEC REPORT." -``` - -Parse the `FEAT-EXEC REPORT`: -- `STATUS : DONE` → STEP 4. -- `STATUS : NEED-DECISION` → make the decision HERE (that is reflection), - append it to the plan, re-dispatch a FRESH feater with plan + decision. - Max 2 decision round-trips → escalate to the user. -- `STATUS : BLOCKED` → surface the blocker to the user, stop. - -## STEP 4 — VERIFY + SECURE (fresh gates, bounded loops) - -Run the two fresh gates per `$HOME/.claude/lib/verify-secure-loop.md` with -`CONTRACT` = the STEP 0.7 path, `DIFF` = the working-tree diff the executor -produced, `TEST` = the suite named in its report: - -- GATE 1 — a FRESH verifier judges the diff against the contract (blind). - CONFORME on the first pass → straight to GATE 2, no loop. ECARTS → the - "dev" of the loop is the dispatched executor: re-dispatch a FRESH feater - with the CONTRACT path + the exact gap lines, nothing else. Max 3 → - escalate. -- GATE 2 — a FRESH security-auditor (`MODE: gate`) scans the diff. PASS → - STEP 5. BLOCK → re-dispatch a FRESH feater with the BLOCKING list + the - CONTRACT path; re-verify the request THEN re-scan, max 3 → escalate. - -Loop decisions stay HERE, in the main loop (LRN-083). Nominal (clear -request, conform first pass, clean diff) = one executor + one verifier + -one security dispatch. - -## STEP 5 — COMMIT - -Commit using conventional format: -``` -feat(): - - -``` - -If the feature touched multiple concerns (e.g., feature + config + -test), consider splitting into 2-3 atomic commits — load -`$HOME/.claude/agents/commit-changer.md` and follow its grouping logic. - -Print summary: -``` -FEAT COMPLETE -FEATURE : -FILE(S) : -TEST(S) : -VERIFIED : -``` - -## STEP 6 — DOC SYNC (automatic) - -Load `$HOME/.claude/agents/doc-syncer.md`. -Execute in automatic mode: -`auto-mode scope: ` - -**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits -ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never -`.claude/`/`CLAUDE.md` (rc 4 = a loud BDR-022 anomaly, not a silent skip), and no-ops when -nothing was patched — the common case for a trivial change. No FINISH in an inline flow, so -it just commits the docs on the current branch (no ordering concern). - -## STEP 7 — CAPITALIZE (memory registries) - -A small feature may or may not involve a design choice. Scan the work for: - -- **Non-trivial design choice** (even small: a library pick, a naming convention, a data-model tradeoff) → propose `BDR-XXX` in `.claude/memory/decisions.md` with alternatives considered. -- **Reusable pattern or gotcha encountered** → propose `LRN-XXX` in `.claude/memory/learnings.md`. - -Present the candidates grouped: -``` -CAPITALIZE — proposé - [decisions.md] BDR-XXX — (optionnel) - [learnings.md] LRN-XXX — (optionnel) -Valider ? (all / / edit / skip) -``` - -Always append a 1-line entry to today's heading in `.claude/memory/journal.md`. - -**Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The interactive gate may mirror the user's language; the appended entries must not. - -If no substantive capture candidate → skip with `CAPITALIZE: nothing to log`. - -**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it -surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` -only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit -hash, and no-ops if nothing was written. - ---- - -## RULES -- Max 5 files. If more needed → `/ship-feature`. -- Reflection (scope, plan, contract, loop decisions) NEVER leaves this main - loop; execution NEVER stays in it — the executor is the sonnet-pinned - feater subagent (BDR-066). -- The executor is dispatched FRESH on every round-trip — feedback travels - as contract path + named gaps/decisions, never as transcript. -- Design gate only (not full plugin check). See STEP 0.5. -- No brainstorm/design phase (if needed → `/ship-feature`). -- Keep scope tight. If scope creep happens mid-work, stop - and suggest splitting into `/feat` + follow-up task. -- Follow existing code patterns. Don't introduce new patterns - for a small feature. -```` - -(Note: this rewrite REPLACES the Task 3 thin-wrapper gate paragraph for feat — the gate line is now native under the H1. The census greps `lib/model-gate.md`, satisfied either way.) - -- [ ] **Step 2: Rewrite `agents/feater.md`** - -Replace the ENTIRE file content with: - -````markdown ---- -name: feater -description: Small-feature EXECUTOR — dispatched by /feat with a closed plan + contract. Implements to the letter, tests, reports. No planning, no questions, no commit. -tools: Read, Edit, Write, Bash, Grep, Glob -model: sonnet ---- - -# FEATER — plan executor - -You receive a CLOSED plan from the /feat orchestrator. Your job is faithful -execution, not design. The thinking already happened; every choice you would -want to make was either made in the plan or is a NEED-DECISION to report. - -## INPUT (in the dispatch prompt) - -- `CONTRACT`: path to the contract file — read it FIRST; its acceptance - criteria + FILE SCOPE bound everything you do. -- `PLAN`: files + approach + edge cases + tests. -- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS - BLOCKED — never create or switch branches. -- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY - those, touch nothing else. - -## EXECUTION RULES - -- Follow the plan to the letter. A plan hole or an open choice (naming, - data shape, API surface, dependency) → STOP, report `NEED-DECISION` with - the precise question. Never improvise a design decision. -- Stay inside the contract FILE SCOPE. A needed file outside it → - `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. -- Write tests alongside the code, as the plan names them. Run the relevant - suite incrementally; run it fully before reporting. -- Follow existing code patterns and CLAUDE.md limits (function size, - params, no global state). Match comment density and naming. -- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, - editing `.claude/**` or memory registries, user questions (you cannot - ask — report instead), attribution trailers of any kind. - -## OUTPUT — end with exactly this report (your final message) - -``` -FEAT-EXEC REPORT -STATUS : DONE | NEED-DECISION | BLOCKED -FILES : -TESTS : -NOTES : -``` -```` - -- [ ] **Step 3: Update `lib/verify-secure-loop.md` (3 surgical edits)** - -Edit 1 — header, `old_string`: - -``` -finished diff into a verified, security-cleared change through two fresh -gates and bounded loops. The dev stays inline (LRN-083: subagents = -execution + report; loop decisions live here, in the main loop). -``` - -`new_string`: - -``` -finished diff into a verified, security-cleared change through two fresh -gates and bounded loops. Loop decisions live here, in the main loop -(LRN-083: subagents = execution + report). The dev step is either inline -(bugfix) or a dispatched sonnet executor (/feat's feater): "hand the dev" -below means fix inline, or re-dispatch a FRESH executor with exactly those -inputs. -``` - -Edit 2 — GATE 1 ECARTS bullet, `old_string`: - -``` - lines (NOT-MET / out-of-scope), nothing else. Dev fixes inline, then - re-dispatch a FRESH verifier. -``` - -`new_string`: - -``` - lines (NOT-MET / out-of-scope), nothing else. Inline dev fixes in place; - a dispatched dev is re-dispatched FRESH with those inputs only. Then - re-dispatch a FRESH verifier. -``` - -Edit 3 — GATE 2 BLOCK bullet, `old_string`: - -``` -- `BLOCK(n)` → hand the dev the `BLOCKING` list + the CONTRACT path. Dev - fixes inline. Then **re-verify the REQUEST first** (GATE 1, fresh -``` - -`new_string`: - -``` -- `BLOCK(n)` → hand the dev the `BLOCKING` list + the CONTRACT path (inline - fix, or FRESH executor re-dispatch). Then **re-verify the REQUEST first** (GATE 1, fresh -``` - -- [ ] **Step 4: Structural verification** - -Run: `grep -c 'subagent_type="feater"' skills/feat/SKILL.md; grep -c 'verify-secure-loop.md' skills/feat/SKILL.md; grep -c 'model: sonnet' agents/feater.md; grep -c 'tools: Read, Edit, Write, Bash, Grep, Glob$' agents/feater.md; grep -c 'AskUserQuestion' agents/feater.md; true` -Expected: `1` / `1` (or more) / `1` / `1` (exact tools line — no Agent tool) / `0` (no AskUserQuestion anywhere). - -Run: `python3 -c "import yaml; yaml.safe_load(open('agents/feater.md').read().split('---')[1]); print('YAML OK')"` -Expected: `YAML OK`. - -- [ ] **Step 5: Full suite + commit** - -Run: `make test` -Expected: green. - -```bash -git add skills/feat/SKILL.md agents/feater.md lib/verify-secure-loop.md -git commit -m "feat(model-routing): /feat re-architecture — reflection inline, feater = sonnet executor (partial supersede BDR-050)" -``` - ---- - -### Task 6: Pin SDD implementation subagents to sonnet (ship-feature, init-project) - -**Files:** -- Modify: `skills/ship-feature/SKILL.md:144-148` -- Modify: `skills/init-project/SKILL.md:166-170` - -**Interfaces:** -- Produces: the literal `model: "sonnet"` in both files — Task 8's census greps it. - -- [ ] **Step 1: ship-feature STEP 4** - -Edit `skills/ship-feature/SKILL.md`, `old_string`: - -``` -`finishing-a-development-branch` step — this orchestrator owns integration via -`gitflow finish` (STEP 9). When SDD's flow reaches "Use -finishing-a-development-branch", stop and return. -``` - -`new_string`: - -``` -`finishing-a-development-branch` step — this orchestrator owns integration via -`gitflow finish` (STEP 9). When SDD's flow reaches "Use -finishing-a-development-branch", stop and return. - -**Model routing (BDR-066):** every subagent dispatched under SDD — per-task -implementers AND its reviewers — MUST carry `model: "sonnet"` in the Agent -call. The plan is closed; execution and plan-conformity review are sonnet -work. Reflection (task decomposition, review verdict arbitration) stays in -this loop. -``` - -- [ ] **Step 2: init-project STEP 8** - -Edit `skills/init-project/SKILL.md`, `old_string`: - -``` -`finishing-a-development-branch` step — this orchestrator owns integration via -`gitflow finish` (STEP 11). When SDD's flow reaches "Use -finishing-a-development-branch", stop and return. -``` - -`new_string`: - -``` -`finishing-a-development-branch` step — this orchestrator owns integration via -`gitflow finish` (STEP 11). When SDD's flow reaches "Use -finishing-a-development-branch", stop and return. - -**Model routing (BDR-066):** every subagent dispatched under SDD — per-task -implementers AND its reviewers — MUST carry `model: "sonnet"` in the Agent -call. The plan is closed; execution and plan-conformity review are sonnet -work. Reflection (task decomposition, review verdict arbitration) stays in -this loop. -``` - -- [ ] **Step 3: Verify + commit** - -Run: `grep -c 'model: "sonnet"' skills/ship-feature/SKILL.md skills/init-project/SKILL.md` -Expected: `1` for each file. - -Run: `make test` — Expected: green. - -```bash -git add skills/ship-feature/SKILL.md skills/init-project/SKILL.md -git commit -m "feat(model-routing): SDD implementation + review subagents dispatched model sonnet" -``` - ---- - -### Task 7: web-validate fixes via hotfixer L1 applier - -**Files:** -- Modify: `skills/web-validate/SKILL.md:274-277` (STEP 3, options A and B) - -**Interfaces:** -- Consumes: hotfixer sonnet pin (Task 4); mirrors the geo L1 applier idiom (`skills/geo/SKILL.md:72-77`). -- Produces: `subagent_type="hotfixer"` in web-validate — Task 8's census greps it. - -- [ ] **Step 1: Replace inline-Edit application with L1 dispatch** - -Edit `skills/web-validate/SKILL.md`, `old_string`: - -``` -4. On `A` : apply each bundle via `Edit` (targeted `old_string` / - `new_string`). Never use `Write` on shared templates (risk of - overwriting /seo or /geo content — meta tags, JSON-LD). -5. On `B` : for each diff, show and ask yes/no/skip. -``` - -`new_string`: - -```` -4. On `A` : dispatch each file-group's applier at L1 (execution = sonnet; - this loop only orchestrates), serially — one applier at a time, appliers - share files: - - ``` - Agent(subagent_type="hotfixer") - prompt: ". - Context: web-validate fix bundle, user-approved scope — no - confirmation needed. Apply via targeted Edit (old_string/new_string); - NEVER Write whole files (shared templates carry /seo and /geo - content — meta tags, JSON-LD). Do NOT commit — apply and self-verify - only." - ``` - -5. On `B` : for each diff, show and ask yes/no/skip; apply approved diffs - as in `A` (hotfixer dispatch). -```` - -- [ ] **Step 2: Verify + commit** - -Run: `grep -c 'subagent_type="hotfixer"' skills/web-validate/SKILL.md` -Expected: `1`. - -Run: `make test` — Expected: green. - -```bash -git add skills/web-validate/SKILL.md -git commit -m "feat(model-routing): web-validate fix bundle applied via hotfixer at L1 (BDR-061 alignment)" -``` - ---- - -### Task 8: Census guard `lib/tests/model-routing.test.sh` + flip-test - -**Files:** -- Test: `lib/tests/model-routing.test.sh` (guarded path — sentinel required) - -**Interfaces:** -- Consumes: every string produced by Tasks 3-7 (see greps below). Auto-discovered by the Makefile `test` glob `lib/tests/*.test.sh` — no runner edit needed. - -- [ ] **Step 1: Write the census test** - -```bash -printf 'model-routing plan: add census guard test' > .claude/.config-edit-ok -``` - -Then create `lib/tests/model-routing.test.sh` with exactly: - -```bash -#!/usr/bin/env bash -# lib/tests/model-routing.test.sh — census: gate wiring + pins + executor shape (BDR-066) -set -u -R="$(cd "$(dirname "$0")/../.." && pwd)" -pass=0; fail=0 -ok() { pass=$((pass+1)); } -ko() { fail=$((fail+1)); printf 'FAIL %s\n' "$1"; } -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 12 reflection orchestrators -for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean; do - has "skills/$s/SKILL.md" 'lib/model-gate.md' -done -# 2) gate NOT wired in the excluded skills (encodes the spec exclusion list) -for s in hotfix commit-change doc status release-candidate; do - lacks "skills/$s/SKILL.md" 'lib/model-gate.md' -done -# 3) executor + gate pins -has "agents/feater.md" 'model: sonnet' -has "agents/hotfixer.md" 'model: sonnet' -has "agents/verifier.md" 'model: sonnet' -has "agents/security-auditor.md" 'model: sonnet' -fm_lacks "agents/analyzer.md" 'model:' -# 4) /feat executor shape -has "skills/feat/SKILL.md" 'subagent_type="feater"' -has "skills/feat/SKILL.md" 'verify-secure-loop.md' -lacks "agents/feater.md" 'AskUserQuestion' -# 5) SDD execution pinned -has "skills/ship-feature/SKILL.md" 'model: "sonnet"' -has "skills/init-project/SKILL.md" 'model: "sonnet"' -# 6) web-validate applies via L1 applier -has "skills/web-validate/SKILL.md" 'subagent_type="hotfixer"' - -printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail" -[ "$fail" -eq 0 ] -``` - -- [ ] **Step 2: Run — expect green (everything already wired by Tasks 3-7)** - -Run: `bash lib/tests/model-routing.test.sh` -Expected: `model-routing census: 28 pass, 0 fail`, exit 0. (Count: 12 wired + 5 excluded + 5 pins + 3 feat-shape + 2 SDD + 1 web-validate.) - -- [ ] **Step 3: Flip-test the guard (LRN-096 — prove it CAN fail)** - -```bash -sed -i 's|lib/model-gate.md|lib/model-gate-REMOVED.md|' skills/tour/SKILL.md -bash lib/tests/model-routing.test.sh; echo "exit=$?" -git checkout -- skills/tour/SKILL.md -bash lib/tests/model-routing.test.sh; echo "exit=$?" -``` - -Expected: first run prints `FAIL skills/tour/SKILL.md missing: lib/model-gate.md` and `exit=1`; second run prints `28 pass, 0 fail` and `exit=0`. - -- [ ] **Step 4: Lint + full suite + commit** - -Run: `shellcheck lib/tests/model-routing.test.sh && make test` -Expected: clean + green. - -```bash -git add lib/tests/model-routing.test.sh -git commit -m "test(model-routing): census guard — gate wiring, pins, executor shape (flip-tested)" -``` - ---- - -### Task 9: README + CHANGELOG - -**Files:** -- Modify: `README.md` (agent/model documentation) -- Modify: `CHANGELOG.md` (Unreleased section) - -- [ ] **Step 1: Locate the README insertion point** - -Run: `grep -niE 'agents?/|sonnet|haiku|model' README.md | head -20` - -If README has a table listing agents (a row per agent), refresh/add its model info from the table below. If not, insert a new subsection `### Agent model routing (BDR-066)` immediately after the section that documents `agents/` (fallback: before the "Skills" section), with exactly: - -```markdown -### Agent model routing (BDR-066) - -Reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs -INLINE on the session model — assumed Fable/Opus, enforced by a blocking -gate (`lib/model-gate.md` + `lib/model-check.sh`) at the entry of the 12 -reflection orchestrators. Execution runs on pinned subagents: - -| Agent | Model | Tier | -|---|---|---| -| feater, hotfixer | sonnet (pinned) | executors — code from a closed plan, fix-bundle appliers | -| verifier, security-auditor | sonnet (pinned) | fresh gates (≤3×/loop) | -| 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, code-cleaner, bugfixer, commit-changer | inherit session (Fable/Opus) | reflection / audit / inline playbooks | -``` - -- [ ] **Step 2: CHANGELOG** - -Run: `grep -n 'Unreleased' CHANGELOG.md` - -Under the `## [Unreleased]` heading (create `### Added` / `### Changed` subsections if absent), add: - -```markdown -### Added -- Model routing (BDR-066): blocking model gate (`lib/model-gate.md` + - `lib/model-check.sh`, flip-tested) wired into 12 reflection orchestrators; - census guard `lib/tests/model-routing.test.sh`. -- `/feat` re-architected: reflection inline (scope/plan/contract), execution - dispatched to the sonnet-pinned `feater` executor; verify+secure loop - decided in the main loop with fresh executor re-dispatches. - -### Changed -- `hotfixer` pinned `model: sonnet` (seo/geo/web-validate L1 applier); - `analyzer` haiku pin removed (inherits the session model). -- ship-feature / init-project: SDD implementation + review subagents - dispatched with `model: "sonnet"`. -- web-validate `--fix`: bundle applied via `hotfixer` at L1 instead of - inline Edit (BDR-061 alignment). -``` - -- [ ] **Step 3: Commit** - -Run: `make test` — Expected: green. - -```bash -git add README.md CHANGELOG.md -git commit -m "docs(model-routing): README agent-model table + CHANGELOG entry" -``` - ---- - -### Task 10: Capitalize memory + TODO follow-up - -**Files:** -- Modify: `.claude/memory/decisions.md` (append BDR-066 + Index row) -- Modify: `.claude/memory/journal.md` (1 line under a `## 2026-07-15` heading) -- Modify: `.claude/tasks/TODO.md` (chantier section + plan-2 backlog) - -- [ ] **Step 1: Append BDR-066 to `.claude/memory/decisions.md`** - -Add to the Index table (after the BDR-065 row): - -```markdown -| BDR-066 | 2026-07-15 | Model routing: reflection inline (session big model) + sonnet-pinned executors + blocking gate | accepted | -``` - -Append at end of file: - -```markdown -## BDR-066 — Model routing: reflection inline (session big model), executors pinned sonnet, blocking gate - -- **Date**: 2026-07-15 -- **Status**: accepted (partial supersede of BDR-050: /feat dev no longer inline; bugfix/hotfix dev-inline CONSERVED) -- **Decision**: reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs on session model (Fable; Opus fallback) — inline or inherit subagents, never pinned down. Execution (code from closed plan, fix-bundle application) runs sonnet-pinned subagents: feater + hotfixer pinned sonnet; SDD implementation+review subagents dispatched `model: "sonnet"` (ship-feature/init-project); web-validate fixes via hotfixer L1 (was inline Edit). analyzer haiku pin REMOVED (digest feeds plan = reflection tier). verifier + security-auditor STAY sonnet (job9 confirmed — procedural gates, ≤3×/loop). Blocking gate `lib/model-gate.md` (self-check + witness `lib/model-check.sh`) wired in 12 reflection orchestrators; small → STOP, unknown → fail-visible; census guard `lib/tests/model-routing.test.sh` flip-tested. -- **Why**: big-model quota burned on mechanical execution (Fable exhausted mid-job8); plan closed at dispatch → executor needs obedience not judgment; fresh sonnet gates catch executor drift. -- **Alternatives rejected**: opus pins on audit agents (session-independent) — rejected: session assumed big + blocking gate as backstop, one tier fewer; advisory gate — rejected by user, blocking; split bugfix/hotfix too — rejected: bugfix investigation interleaved w/ fix, hotfix gain marginal vs dispatch overhead. -- **Caveats**: client-handover-writer conversion (inline-load → sonnet dispatch, 11 human-gate sites to relocate) DEFERRED to own plan — its opus pin stays inert meanwhile; feater cannot ask → NEED-DECISION report = escalation valve, plan must close decisions; witness reads settings.json — lags `--model`-launched sessions (self-check compensates). -- **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`. -``` - -- [ ] **Step 2: Journal line** - -Append under a `## 2026-07-15` heading (create it if absent) in `.claude/memory/journal.md`: - -```markdown -- 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. -``` - -- [ ] **Step 3: TODO follow-up entry** - -Add at the top of `.claude/tasks/TODO.md` (above the 2026-07-08 section): - -```markdown -## 2026-07-15 — model routing (feature/model-routing) -Spec + plan in docs/superpowers/ (transient, BDR-065). BDR-066. Branch -unmerged — human gate. -- [x] gate lib/model-check.sh + lib/model-gate.md (flip-tested) wired ×12 -- [x] pins: hotfixer/feater sonnet, analyzer un-pinned; SDD model:"sonnet"; - web-validate → hotfixer L1; census guard model-routing.test.sh -- [x] /feat re-arch: reflection inline → feater sonnet executor (partial - supersede BDR-050) -- [ ] DOGFOOD (manual, next sessions): /feat live run — plan closes - decisions, dispatch carries sonnet, verify loop in main loop; gate - STOP on a sonnet session (LRN-079 class, not automatable here) -- [ ] PLAN 2 — client-handover conversion (spec §5): inline-load → sonnet - dispatch, relocate 11 human-gate sites to dispatcher (inventory in - plan-1 session), or lighter variant: dispatch only the redaction - phase. Decide shape at plan time. -``` - -- [ ] **Step 4: Commit memory scoped** - -```bash -git add .claude/memory/decisions.md .claude/memory/journal.md .claude/tasks/TODO.md -git commit -m "chore(memory): BDR-066 model routing + journal + TODO follow-ups" -``` - -- [ ] **Step 5: Final gate** - -Run: `make test` -Expected: green, exit 0. Then report the full commit list (`git log --oneline develop..HEAD`) for the human merge gate. Do NOT run `gitflow finish`. - ---- - -# WAVE 2 — pure-execution + reflection-split skills (user directive 2026-07-15) - -The wave-1 exclusion list left `hotfix, commit-change, doc, status, release-candidate` -inheriting the session model — i.e. running EXECUTION on the big model, the -waste the split exists to kill. User verdicts (2026-07-15): -- **doc / status** = pure non-interactive execution → convert inline-load to a - dispatched subagent so its pin takes effect. doc-syncer stays sonnet; - status-reporter stays **haiku** (right tier for a read-only collector; the - win is getting it off the big model, not the tier). -- **hotfix** = reflection (locate root cause + propose fix) + execution → split - like /feat: reflection inline (+ MODEL GATE), execution dispatched to the - sonnet hotfixer executor. hotfix JOINS the gated group (12→13). -- **commit-change** = grouping (judgment) + committing (execution), interactive - → dispatch EVERYTHING (grouping included) to a sonnet commit-changer, relocate - the two approval gates to the dispatcher (propose→confirm→execute, seo-applier - shape). No MODEL GATE (no inline reflection — grouping runs on sonnet). -- **release-candidate** = create a sonnet `release-executor` agent for the - mechanical spans (version.txt, CHANGELOG rewrite, gitflow start/finish, tag), - relocate the two human gates (when-to-release, push) to the dispatcher. No - MODEL GATE (user's explicit choice — force dispatch, not gate). - -Post-wave-2 gate exclusion list = `commit-change, doc, status, release-candidate` -(hotfix removed — now wired). - -## Global Constraints (wave 2) - -Same as wave 1: branch `feature/model-routing`, no merge, no attribution -trailers, `make test` green per commit, shellcheck clean, config-protection -sentinel before each `lib/tests/*` write, YAML `safe_load`-parseable frontmatter. - ---- - -### Task 11: doc + status → dispatched execution - -**Files:** -- Modify: `skills/doc/SKILL.md` (add `Agent` to allowed-tools; body → dispatch) -- Modify: `skills/status/SKILL.md` (add `Agent` to allowed-tools; body → dispatch) - -**Interfaces:** doc-syncer.md is already `model: sonnet`; status-reporter.md is -already `model: haiku` — no agent edits. Only the skills change from inline-load -to `Agent(subagent_type=…)` so the pins take effect. - -- [ ] **Step 1: doc → dispatch.** In `skills/doc/SKILL.md`, add ` - Agent` to the - `allowed-tools` list, and replace the body block - ``` - Load and follow strictly: - - $HOME/.claude/agents/doc-syncer.md - - Execute the DOC SYNCER on this project. - - Context from the user (if any): - $ARGUMENTS - ``` - with: - ``` - Dispatch the doc-syncer as a subagent so its `model: sonnet` pin takes - effect (doc-sync = execution, not the session's big model): - - Agent(subagent_type="doc-syncer") - prompt: "Audit + sync public docs for this project. Context from the user: - $ARGUMENTS. Report PATCHED_FILES and a summary — do NOT commit." - - Then commit the patched docs from THIS loop per `$HOME/.claude/lib/doc-commit.md` - (surgical: only doc-syncer's PATCHED_FILES, never `.claude/`/`CLAUDE.md`, - no-op if nothing patched). - ``` - -- [ ] **Step 2: status → dispatch.** In `skills/status/SKILL.md`, add `Agent` to - `allowed-tools` (`Read, Bash, Glob, Grep, Agent`), and replace the body - `Load and follow strictly:\n- $HOME/.claude/agents/status-reporter.md\n\nProduce the full PROJECT STATUS report for the current working directory.` - with a dispatch: - ``` - Dispatch the status-reporter as a subagent so its `model: haiku` pin takes - effect (read-only collection = cheapest tier, off the big session model): - - Agent(subagent_type="status-reporter") - prompt: "Produce the full PROJECT STATUS report for the current working - directory. $ARGUMENTS" - ``` - Keep the existing "Fallback when agent file missing" section intact (it still - applies — if the dispatch target is unreachable, emit the missing-agent line - and STOP). - -- [ ] **Step 3: Verify + commit.** `grep -c 'subagent_type="doc-syncer"' skills/doc/SKILL.md` - → 1; `grep -c 'subagent_type="status-reporter"' skills/status/SKILL.md` → 1. - `make test` green. - ```bash - git add skills/doc/SKILL.md skills/status/SKILL.md - git commit -m "feat(model-routing): doc/status dispatch their agent (sonnet/haiku pins take effect)" - ``` - ---- - -### Task 12: hotfix — reflection inline + dispatched sonnet executor (/feat pattern) - -**Files:** -- Modify (rewrite): `skills/hotfix/SKILL.md` — becomes the reflection orchestrator -- Modify (rewrite): `agents/hotfixer.md` — becomes pure executor -- Modify: `lib/tests/loops-light.test.sh` — repoint hotfix structure locks (guarded) - -**Pattern:** mirror the shipped `/feat` split (skills/feat/SKILL.md + agents/feater.md). - -- [ ] **Step 1: Rewrite `skills/hotfix/SKILL.md` as the orchestrator.** Keep `Agent` - in allowed-tools. Structure: - - `# /hotfix — quick-fix orchestrator (reflection inline, execution dispatched)` - - `MODEL GATE (blocking): run $HOME/.claude/lib/model-gate.md BEFORE any step. small → STOP.` - (hotfix now has a reflection phase → it joins the gated group.) - - STEP 1 LOCATE (reflection, inline): find the bug from the description, read - the file(s), CONFIRM the root cause is obvious/superficial, escalate to - `/bugfix` if deeper. Optional blockers-only memory glance (as today). - - STEP 1.5 DESIGN GATE (`lib/design-gate.md`, as today). - - STEP 1.7 CONTRACT (silent autofill, `lib/contract-interview.md`, zero - questions, as today). - - STEP 2 PRE-FLIGHT (inline): gitflow aiguillage (type `hotfix`); snapshot - `git rev-parse HEAD` (the revert SHA) + dirty-tree check (as today's STEP 2 - pre-flight). - - STEP 3 DISPATCH EXECUTOR: `Agent(subagent_type="hotfixer")` with the - contract path, the located file(s), the proposed minimal fix, and the branch. - Parse a `HOTFIX-EXEC REPORT` with `STATUS : DONE | BLOCKED`. - - STEP 4 VERIFY + SECURE + COMMIT (main loop, LRN-083): on executor DONE, the - smoke result is in its report; then the security gate — dispatch a FRESH - security-auditor (`MODE: gate`, SCOPE = diff vs the pre-flight SHA). **hotfix - keeps revert-not-loop**: smoke FAIL or security BLOCK → `git restore .` to the - pre-flight SHA + STOP + "escalate to /bugfix" (verbatim from today's STEP 3). - No verifier at hotfix weight. Commit only after smoke + security pass. - - STEP 5 DOC SYNC + STEP 6 CAPITALIZE: identical to today's STEP 4/5 (doc-sync - auto-mode + `doc-commit.md`; lightweight capitalize + always-on journal + - `capitalize-commit.md`). - - RULES: max 2 files; execution never stays inline, reflection never leaves it - (BDR-066); executor dispatched fresh; revert-not-loop preserved. - -- [ ] **Step 2: Rewrite `agents/hotfixer.md` as the executor.** Frontmatter: - `tools: Read, Edit, Write, Bash, Grep, Glob` (DROP `Agent` — no nested dispatch; - security moved to the orchestrator), `model: sonnet`. Body: receive - CONTRACT + located file(s) + proposed fix + BRANCH (verify with - `git branch --show-current`, never switch). Apply the minimal edit (no - refactoring), run the stack smoke/test cascade (keep today's detection cascade), - report. FORBIDDEN: git commit, branch ops, security dispatch, user questions, - attribution trailers. End with: - ``` - HOTFIX-EXEC REPORT - STATUS : DONE | BLOCKED - FILE(S) : - FIX : - SMOKE : - NOTES : - ``` - -- [ ] **Step 3: Repoint `lib/tests/loops-light.test.sh` hotfix locks** (guarded — - sentinel first). The hotfix block currently checks `agents/hotfixer.md` for - orchestration clauses now moved to the skill. Introduce `HSKL="$REPO/skills/hotfix/SKILL.md"` - and repoint: contract/silent → HSKL `STEP 1.7 — CONTRACT`; security gate + - `failure REVERTS, never loops` + `No verifier is dispatched at hotfix weight` - → HSKL; `hotfix skill has Agent` (HSK ` - Agent`) unchanged. The - `hotfix has Agent tool` lock on hotfixer INVERTS (hotfixer no longer has Agent) - → change to assert hotfixer LACKS Agent and carries `model: sonnet` + the - `HOTFIX-EXEC REPORT` grammar. Add a `hotfix dispatches hotfixer` lock - (`subagent_type="hotfixer"` in HSKL). Keep include/feat/bugfix blocks untouched. - Add a negative-match helper `tn()` (mirror `tf`, invert the grep) if asserting - Agent-absence. - -- [ ] **Step 4: Wire hotfix into the census + gate lists.** In - `lib/tests/model-routing.test.sh` (guarded — sentinel first): MOVE `hotfix` - from the excluded loop to the wired loop (`has "skills/hotfix/SKILL.md" 'lib/model-gate.md'`). - Update the expected count in the run message accordingly. - -- [ ] **Step 5: Verify + commit.** `bash lib/tests/loops-light.test.sh` green; - `bash lib/tests/model-routing.test.sh` green; YAML check both rewritten files; - `make test` green. - ```bash - git add skills/hotfix/SKILL.md agents/hotfixer.md lib/tests/loops-light.test.sh lib/tests/model-routing.test.sh - git commit -m "feat(model-routing): /hotfix split — reflection inline + gate, hotfixer = sonnet executor" - ``` - ---- - -### Task 13: commit-change — dispatch grouping+commit to sonnet, relocate approval gates - -**Files:** -- Modify (rewrite): `skills/commit-change/SKILL.md` — dispatcher owns the two gates -- Modify (rewrite): `agents/commit-changer.md` — sonnet, propose/execute phases, no AskUserQuestion - -**Pattern:** seo-applier shape (subagent proposes → dispatcher confirms → subagent executes). - -- [ ] **Step 1: Rewrite `agents/commit-changer.md`.** Frontmatter: - `tools: Bash, Read, Grep, Glob` (DROP `AskUserQuestion` — gates move to the - dispatcher), `model: sonnet`. Body: two modes driven by the dispatch prompt. - - `MODE: propose` → Phase 0 (gitflow aiguillage, type chore — bash), Phase 1 - (gather), Phase 2 (reconstruct steps), Phase 2.5 → EMIT the `COMMIT PLAN` - block + any edge-case flags (sensitive files, staged-only, conflicts) + - Phase-4 capitalize candidates, then STOP with - `READY TO APPLY — awaiting dispatcher confirmation`. Writes NOTHING. - - `MODE: apply` → receive the APPROVED plan (steps + messages) + approved - capitalize entries; execute Phase 3 (stage-per-step + commit) and write the - approved memory via `capitalize-commit.md`; report the commit hashes. - -- [ ] **Step 2: Rewrite `skills/commit-change/SKILL.md` as dispatcher.** Keep - `Agent` + `AskUserQuestion` in allowed-tools. Flow: pre-flight (detached HEAD / - conflicts / identity — STOP as today) → `Agent(subagent_type="commit-changer")` - with `MODE: propose` → show the returned COMMIT PLAN, `AskUserQuestion` - (all / numbers / edit / skip) → show capitalize candidates, `AskUserQuestion` - (all / IDs / skip) → `Agent(subagent_type="commit-changer")` with `MODE: apply` - + the approved plan + approved entries → report hashes. NO MODEL GATE (grouping - runs on the sonnet subagent — no inline reflection to protect). - -- [ ] **Step 3: Verify + commit.** `grep -c 'subagent_type="commit-changer"' skills/commit-change/SKILL.md` - ≥ 1; `grep -c 'model: sonnet' agents/commit-changer.md` → 1; - `grep -c 'AskUserQuestion' agents/commit-changer.md` → 0; YAML check; `make test` green. - ```bash - git add skills/commit-change/SKILL.md agents/commit-changer.md - git commit -m "feat(model-routing): /commit-change dispatch to sonnet commit-changer, gates relocated to dispatcher" - ``` - ---- - -### Task 14: release-candidate — sonnet release-executor, human gates relocated - -**Files:** -- Create: `agents/release-executor.md` — sonnet, mechanical release spans -- Modify (rewrite): `skills/release-candidate/SKILL.md` — dispatcher owns the two human gates - -- [ ] **Step 1: Create `agents/release-executor.md`.** Frontmatter: - `tools: Read, Edit, Write, Bash, Grep, Glob`, `model: sonnet`. Two-span - executor driven by the dispatch prompt (a human gate sits BETWEEN the spans, so - it cannot be one dispatch): - - `SPAN: prep ` → `gitflow start release `, set `version.txt`, - rewrite CHANGELOG (`## [Unreleased]` → `## [] — `, re-open empty - Unreleased; a MAJOR must spell out breaking), run the test suite (RC gate — - never release red), commit the prep on the release branch. Report the branch - + test result. No merge, no tag, no push. - - `SPAN: finish ` → `gitflow finish` (fan-out), `git tag -a v main - -m "release "` AFTER finish. Report. NEVER push (dispatcher's gate). - - FORBIDDEN: deciding the version number (dispatcher/user owns it), the - when-to-release decision, `git push`, attribution trailers. - -- [ ] **Step 2: Rewrite `skills/release-candidate/SKILL.md` as dispatcher.** Add - `allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, AskUserQuestion` to - the frontmatter (it currently has none). Keep all the Overview/Versioning/Common- - mistakes doctrine. Flow: preconditions (clean tree, identity, develop ahead of - main) → the version-number decision stays HERE (judgment: derives from change - nature; decide before running) → `Agent(subagent_type="release-executor")` - `SPAN: prep ` → **HUMAN GATE — when to release** (`AskUserQuestion`, - explicit go, never on "tests pass") → `Agent(subagent_type="release-executor")` - `SPAN: finish ` → **push GATE (ASK)** (`AskUserQuestion`; on go only, - LRN-069): `git push origin main develop && git push origin v` from THIS - loop. No MODEL GATE. - -- [ ] **Step 3: Verify + commit.** `RC_WORK=$(mktemp -d) RC_TAG=1 bash lib/tests/run-release-candidate.sh` - → 5/5 (the release mechanics test is unchanged — the lib still fans out + the - dispatcher still tags); `grep -c 'subagent_type="release-executor"' skills/release-candidate/SKILL.md` - ≥ 1; YAML check the new agent; `make test` green. - ```bash - git add agents/release-executor.md skills/release-candidate/SKILL.md - git commit -m "feat(model-routing): /release-candidate dispatches sonnet release-executor, human gates in dispatcher" - ``` - ---- - -### Task 15: census + docs + memory for wave 2 - -**Files:** -- Modify: `lib/tests/model-routing.test.sh` (guarded) — wave-2 assertions -- Modify: `README.md`, `CHANGELOG.md`, `.claude/memory/decisions.md`, `.claude/tasks/TODO.md` - -- [ ] **Step 1: Extend the census** (`lib/tests/model-routing.test.sh`, guarded — - sentinel first). The excluded loop drops `hotfix` (moved to wired by Task 12 Step 4) - and now reads `for s in commit-change doc status release-candidate`. Add - execution-dispatch asserts: `has skills/doc/SKILL.md 'subagent_type="doc-syncer"'`; - `has skills/status/SKILL.md 'subagent_type="status-reporter"'`; - `has skills/commit-change/SKILL.md 'subagent_type="commit-changer"'`; - `has skills/release-candidate/SKILL.md 'subagent_type="release-executor"'`; - pins `has agents/commit-changer.md 'model: sonnet'`, - `has agents/release-executor.md 'model: sonnet'`; and executor-shape - `lacks agents/commit-changer.md 'AskUserQuestion'`. Update the printed expected - count. Flip-test one new assertion (LRN-096). - -- [ ] **Step 2: README + CHANGELOG.** Update the BDR-066 agent-model table: - hotfixer stays sonnet (now an effective executor), commit-changer → sonnet, - release-executor (new) → sonnet, status-reporter → haiku (now effective via - dispatch). Move doc/status/commit-change/release-candidate out of the "inherit" - row into a new "execution — dispatched" line. CHANGELOG Unreleased: add the - wave-2 bullets (doc/status/hotfix/commit-change/release-candidate routing). - -- [ ] **Step 3: Capitalize.** Append to the BDR-066 entry a `**Wave 2**` bullet: - doc/status dispatched (sonnet/haiku pins effective); hotfix split like /feat - (joins gated group); commit-change dispatched sonnet with relocated gates; - release-candidate sonnet release-executor with relocated human gates; exclusion - list now commit-change/doc/status/release-candidate. Journal line + - TODO tick under the 2026-07-15 section. - ```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-2 census + docs + BDR-066 update" - ``` - -- [ ] **Step 4: Final wave-2 review** — dispatch a whole-branch reviewer (opus) over - the wave-2 range; confirm both consumers of verify-secure-loop still coherent, - hotfix revert-not-loop preserved, no execution left on the big model in the - five converted skills. Report the full `git log --oneline develop..HEAD`. Do NOT - merge. - ---- - -# WAVE 3 — reflection-split the last two inline execution-carrying agents (user directive 2026-07-15) - -`/bugfix` and `/code-clean` are still thin wrappers that inline-load an agent -doing BOTH reflection and execution on the big session model — the exact -pre-split state `/feat` (Task 5) and `/hotfix` (Task 12) were in. Split each -like the shipped pattern: reflection inline (session model, behind the MODEL -GATE both skills already carry), execution dispatched to a sonnet executor. - -**Honest tradeoff (recorded in the wave-3 BDR bullet):** bugfix's investigation -and fix are tightly coupled; handing a context-free sonnet executor a closed -FIX PLAN is the same bet `/feat` makes — mitigated by the structured DIAGNOSIS -+ the verify loop catching drift. Further supersedes the BDR-050 "bugfix stays -inline" carve-out (hotfix already reversed in wave 2). code-clean's win is -larger than it looks: today it INLINE-LOADS the refactorer (so the refactor -runs on the big model, sonnet pin inert) — after the split the refactor runs -inside the sonnet executor for the first time. - -Gate membership is UNCHANGED: both skills keep reflection (investigation / -audit), so both STAY in the wired gate list — this wave only adds -executor-shape asserts, it does not move either skill between the wired and -excluded lists. - -## Global Constraints (wave 3) - -Same as waves 1–2: branch `feature/model-routing`, no merge, no attribution -trailers, `make test` green per commit, shellcheck clean, config-protection -sentinel before each `lib/tests/*` write (controller applies guarded test -edits — subagents cannot create the sentinel), YAML `safe_load`-parseable -frontmatter. - ---- - -### Task 16: `/bugfix` split — reflection inline + dispatched sonnet executor - -**Files:** -- Modify (rewrite): `skills/bugfix/SKILL.md` — thin wrapper → reflection orchestrator -- Modify (rewrite): `agents/bugfixer.md` — full agent → pure sonnet executor -- Modify (surgical): `lib/verify-secure-loop.md` — bugfix's dev is now dispatched too -- Modify: `lib/tests/loops-light.test.sh` — repoint bugfix locks (guarded — CONTROLLER applies) - -**Pattern:** mirror the shipped `/hotfix` split (skills/hotfix/SKILL.md — it is -the closest template: reflection orchestrator + a security gate whose decisions -live in the main loop) and `/feat` (agents/feater.md — the pure-executor shape). -The difference from hotfix: bugfix keeps the FULL verify+secure loop (fresh -verifier + fresh security, bounded 3×, per `lib/verify-secure-loop.md`) and the -interactive pre-commit + capitalize gates — hotfix has none of those. - -- [ ] **Step 1: Rewrite `skills/bugfix/SKILL.md` as the reflection orchestrator.** - Keep `Agent` in allowed-tools; the frontmatter description block is unchanged. - Keep the existing `MODEL GATE (blocking)` line verbatim (bugfix stays gated). - Absorb, INLINE (session model), what were bugfixer STEPs 1–3.5 — reflection: - - STEP 1 GATHER CONTEXT (git status/log; what/where/when). - - STEP 1.5 DESIGN GATE (`$HOME/.claude/lib/design-gate.md`, unchanged). - - STEP 2 INVESTIGATE (trace symptom → root cause, blast radius). - - STEP 2.5 MEMORY READ-BEFORE (`$HOME/.claude/lib/analyze-before-plan.md`, - blockers-weighted; keep the TEETH clause — DIAGNOSIS must name any binding - prior or state none bears). - - STEP 3 DIAGNOSE + PLAN — emit the `BUGFIX — DIAGNOSIS` block (BUG / ROOT - CAUSE / EVIDENCE / BLAST RADIUS / FIX PLAN / RISK) verbatim from today's - bugfixer STEP 3. Keep the significance gate: trivial → proceed; significant - (>10 lines / multi-file / behavior change) → wait for user approval; - root-cause unclear → list ranked hypotheses, ask before proceeding. - - STEP 3.5 CONTRACT (`$HOME/.claude/lib/contract-interview.md`, main loop; - DIAGNOSIS feeds it — REQUEST verbatim = the bug report, ACCEPTANCE = - symptom reproduced-then-gone + regression test present+passing, FILE SCOPE - = the FIX PLAN files; keep the contract path for STEP 5). - - STEP 4 BRANCH: gitflow aiguillage (`$HOME/.claude/lib/gitflow-aiguillage.md`, - type `bugfix`; never finish). - - STEP 5 DISPATCH EXECUTOR: - ``` - Agent(subagent_type="bugfixer") - prompt: "CONTRACT: - DIAGNOSIS: - FIX PLAN: - BRANCH: - Apply the fix to the letter + the regression test. No commit, no branch - ops, no security dispatch. Finish with the BUGFIX-EXEC REPORT." - ``` - Parse `BUGFIX-EXEC REPORT`: `STATUS : DONE` → STEP 6; `NEED-DECISION` → - decide HERE (reflection), append to the plan, re-dispatch a FRESH bugfixer, - max 2 round-trips → escalate; `BLOCKED` → surface + stop. - - STEP 6 VERIFY + SECURE + PRE-COMMIT GATE + COMMIT (main loop, LRN-083): - run the two fresh gates per `$HOME/.claude/lib/verify-secure-loop.md` with - `CONTRACT` = STEP 3.5 path, `DIFF` = the executor's working-tree diff, - `TEST` = the suite from its report (the loop's "dev" is the dispatched - bugfixer — re-dispatched FRESH on ECARTS/BLOCK). After both gates pass, - keep today's interactive `BUGFIX — READY TO COMMIT` pre-commit gate - (diff-stat + message → yes / edit message / skip / amend last), then commit - with the conventional `fix():` message, then print `BUGFIX COMPLETE`. - - STEP 7 DOC SYNC (doc-syncer auto-mode + `$HOME/.claude/lib/doc-commit.md`, - verbatim from today's bugfixer STEP 6). - - STEP 8 CAPITALIZE (BLK-XXX pre-filled from DIAGNOSIS + optional LRN; - interactive gate; `$HOME/.claude/lib/capitalize-commit.md`; verbatim from - today's bugfixer STEP 7). - - RULES: no fix without root cause first; execution never stays inline, - reflection never leaves it (BDR-066); executor dispatched fresh; keep - regression-test + scoped-fix + escalate-to-/ship-feature-if->5-files rules. - -- [ ] **Step 2: Rewrite `agents/bugfixer.md` as the pure executor.** Replace the - ENTIRE file with exactly: - -````markdown ---- -name: bugfixer -description: Bug-fix EXECUTOR — dispatched by /bugfix with a closed DIAGNOSIS + FIX PLAN + contract. Applies the fix and a regression test, runs the suite, reports. No investigation, no questions, no commit. -tools: Read, Edit, Write, Bash, Grep, Glob -model: sonnet ---- - -# BUGFIXER — fix executor - -You receive a CLOSED diagnosis + fix plan from the /bugfix orchestrator. The -investigation already happened; your job is faithful execution, not analysis. -Every choice was made in the plan or is a NEED-DECISION to report. - -## INPUT (in the dispatch prompt) - -- `CONTRACT`: path to the contract file — read it FIRST; its acceptance - criteria (symptom reproduced-then-gone + a regression test present) + FILE - SCOPE bound everything you do. -- `DIAGNOSIS`: root cause + evidence, from the orchestrator's investigation. -- `FIX PLAN`: the exact edits (file:line → change) + the regression test to add. -- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS - BLOCKED — never create or switch branches. -- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY - those, touch nothing else. - -## EXECUTION RULES - -- Apply the FIX PLAN to the letter — fix the ROOT CAUSE named in DIAGNOSIS, - not the symptom. A plan hole or an open choice (naming, data shape, API - surface, dependency) → STOP, report `NEED-DECISION` with the precise - question. Never re-investigate or improvise a different fix. -- Stay inside the contract FILE SCOPE. A needed file outside it → - `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. -- Add or update the regression test the plan names — it must fail before the - fix and pass after. Run the relevant suite incrementally; run it fully - before reporting. -- Follow existing code patterns and CLAUDE.md limits (function size, params, - no global state). Keep the fix minimal — no "while we're here" cleanups. -- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, - security/verifier dispatch, editing `.claude/**` or memory registries, user - questions (you cannot ask — report instead), attribution trailers of any kind. - -## OUTPUT — end with exactly this report (your final message) - -``` -BUGFIX-EXEC REPORT -STATUS : DONE | NEED-DECISION | BLOCKED -FILE(S) : -TEST(S) : -SMOKE : -NOTES : -``` -```` - -- [ ] **Step 3: Update `lib/verify-secure-loop.md` (both consumers now dispatched).** - The header line `(feat, bugfix)` stays. In the intro, the sentence that says - the dev step is "either inline (bugfix) or a dispatched sonnet executor - (/feat's feater)" is now stale — BOTH are dispatched. Edit it to: the dev - step is a dispatched sonnet executor (feat's `feater`, bugfix's `bugfixer`); - "hand the dev" below means re-dispatch a FRESH executor with exactly those - inputs. Keep GATE 1 / GATE 2 / order-invariant bodies unchanged (they already - read "inline dev fixes in place; a dispatched dev is re-dispatched FRESH" — - the inline branch simply no longer has a consumer, harmless). - -- [ ] **Step 4 (CONTROLLER — guarded): repoint `lib/tests/loops-light.test.sh` - bugfix locks.** Sentinel first: - `printf 'model-routing plan: repoint bugfix structure locks to the skill orchestrator' > .claude/.config-edit-ok` - Introduce `BSK="$REPO/skills/bugfix/SKILL.md"`. The `bugfixer.md (bugfix wiring)` - block currently greps `$BUG` for orchestration clauses now moved to the skill — - repoint them to `$BSK`: `STEP 3.5 — CONTRACT`, `feeds it: REQUEST verbatim`, - `Fresh gates (verify + secure)` (or the skill's actual STEP-6 wording — match - it), `lib/verify-secure-loop.md`. Add a new `bugfixer.md (executor — sonnet, - no Agent)` block mirroring the hotfixer one: `tn` bugfixer LACKS `Agent`, - `tf` `model: sonnet`, `tf` `BUGFIX-EXEC REPORT`. Add `tf "bugfix dispatches - bugfixer" "$BSK" 'subagent_type="bugfixer"'`. Keep include/feat/hotfix blocks - untouched. - -- [ ] **Step 5: Verify + commit.** `bash lib/tests/loops-light.test.sh` green; - YAML check both rewritten files - (`python3 -c "import yaml; [yaml.safe_load(open(f).read().split('---')[1]) for f in ['agents/bugfixer.md','skills/bugfix/SKILL.md']]; print('YAML OK')"`); - `make test` green. - ```bash - git add skills/bugfix/SKILL.md agents/bugfixer.md lib/verify-secure-loop.md lib/tests/loops-light.test.sh - git commit -m "feat(model-routing): /bugfix split — reflection inline, bugfixer = sonnet executor (supersedes BDR-050 bugfix carve-out)" - ``` - ---- - -### Task 17: `/code-clean` split — audit + gate inline + dispatched sonnet executor - -**Files:** -- Modify (rewrite): `skills/code-clean/SKILL.md` — thin wrapper → audit orchestrator -- Modify (rewrite): `agents/code-cleaner.md` — full agent → pure PHASE-2 sonnet executor - -**Pattern:** mirror `/feat` (skill = orchestrator holding reflection + interactive -gate; agent = pure executor). The interactive VALIDATION GATE must stay in the -orchestrator (a dispatched subagent cannot ask). code-cleaner gains `model: sonnet`. - -- [ ] **Step 1: Rewrite `skills/code-clean/SKILL.md` as the audit orchestrator.** - Add `Agent` to allowed-tools (keep `AskUserQuestion`, `Read/Edit/Write/Bash/ - Grep/Glob`). Keep the existing `MODEL GATE (blocking)` line verbatim (audit = - reflection, stays gated). Absorb code-cleaner's PHASE 1 INLINE (session model): - - `# /code-clean — cleanup orchestrator (audit inline, execution dispatched)` - - STEP 1 LOAD PROJECT NORMS (CLAUDE.md > lang configs > community defaults). - - STEP 2 SCAN (A dead code / B style / C structural — verbatim from today's - code-cleaner PHASE 1 STEP 2, keep the TODO-age bash). - - STEP 3 BUILD REPORT (the `CODE-CLEAN AUDIT` block, severity levels). - - STEP 4 VALIDATION GATE (interactive, `AskUserQuestion`): present the report; - approve all / cherry-pick / clarify. Do NOT proceed until explicit approval. - Exported/public-API symbols flagged in the audit are resolved HERE, per-item - (this is where the today's guard-rail consent lives — the executor never asks). - - STEP 5 PERSIST SCOPE + DISPATCH: write the approved items to - `.claude/audits/CODE-CLEAN-SCOPE.md` (`mkdir -p .claude/audits` first), one - per line `file:line — item — severity — proposed fix`, then: - ``` - Agent(subagent_type="code-cleaner") - prompt: "SCOPE: .claude/audits/CODE-CLEAN-SCOPE.md - APPROVED: - BRANCH: - Execute PHASE 2 on the approved scope only. Zero behavior change. No commit. - Finish with the CODE-CLEAN-EXEC REPORT." - ``` - Parse `CODE-CLEAN-EXEC REPORT`: `DONE` → STEP 6; `BLOCKED` → surface + stop. - - STEP 6 SUMMARY: present the `CODE-CLEAN COMPLETE` block (removed / refactored - / skipped / bugs-found / tests) from the executor's report. No commit here - (code-clean has never auto-committed — leave the working tree for the user - or a follow-up `/commit-change`; keep today's behavior). - - RULES: zero behavior change; no scope creep; exported symbols need explicit - per-item consent AT THE GATE; bugs → BUGS-FOUND.md not fixed; no plugin - check (lightweight); systemic issues → suggest `/ship-feature`. - -- [ ] **Step 2: Rewrite `agents/code-cleaner.md` as the PHASE-2 executor.** Replace - the ENTIRE file with exactly: - -````markdown ---- -name: code-cleaner -description: Cleanup EXECUTOR (PHASE 2) — dispatched by /code-clean with an APPROVED scope. Deletes approved dead code, hands style/structural items to the refactorer, re-audits. Zero behavior change. No audit, no questions, no commit. -tools: Read, Edit, Write, Bash, Grep, Glob -model: sonnet ---- - -# CODE-CLEANER — cleanup executor (PHASE 2) - -You receive an APPROVED cleanup scope from the /code-clean orchestrator. The -audit and the user approval already happened; your job is faithful execution. -The iron law is unchanged: ZERO behavior change — identical observable output -before and after. - -## INPUT (in the dispatch prompt) - -- `SCOPE`: path to `.claude/audits/CODE-CLEAN-SCOPE.md` — the approved items - (`file:line — item — severity — proposed fix`), the on-disk contract. -- `APPROVED`: the item list the user confirmed (may be a subset of the audit), - including any exported/public-API symbols the gate explicitly cleared. -- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS - BLOCKED — never create or switch branches. - -## EXECUTION — in order - -### 1. Delete approved dead code (safest first) - -Remove approved unused imports / variables / functions, commented-out blocks, -stale TODO/FIXME. **Guard rail**: an exported / public-API symbol the -`APPROVED` list did NOT explicitly clear → do NOT delete; SKIP it and record -it under NOTES. The per-item exported-symbol consent lives in the -orchestrator's gate — you never ask. - -### 2. Style + structural fixes → INLINE-LOAD the refactorer - -Load `$HOME/.claude/agents/refactorer.md` and continue AS the refactorer in -THIS SAME context — you *become* it. This is an inline load, NOT a subagent -dispatch: the `Agent` tool is not involved and no new context is spawned. Its -scope = the style / structural items in `SCOPE`. Its own safety process runs -(pre-report, function-by-function, test after each) — zero behavior change. -Running inside this sonnet executor, the refactor finally runs on sonnet (the -refactorer pin was inert under the old inline-load on the session model). - -### 3. Log discovered bugs (do NOT fix) - -Real defects found during cleanup (not style issues) → append each to -`.claude/audits/BUGS-FOUND.md` (`mkdir -p .claude/audits` first): file:line, -description, severity, discovered-while. Cleanup and bugfixing are separate -concerns — never fix a bug here. - -### 4. Re-audit - -Re-scan only the modified files; verify no new issues were introduced; run the -project test suite + linter/formatter if available. - -## RULES - -- Zero behavior change. Unsure a deletion is safe → leave it, record under NOTES. -- No "while we're here" scope creep — only the APPROVED items. -- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, user - questions (report instead), editing `.claude/**` or memory registries, - attribution trailers of any kind. - -## OUTPUT — end with exactly this report (your final message) - -``` -CODE-CLEAN-EXEC REPORT -STATUS : DONE | BLOCKED -REMOVED : -REFACTORED: -SKIPPED : -BUGS : -TESTS : -NOTES : -``` -```` - -- [ ] **Step 3: Verify + commit.** - `grep -c 'subagent_type="code-cleaner"' skills/code-clean/SKILL.md` → 1; - `grep -c 'model: sonnet' agents/code-cleaner.md` → 1; - `grep -c 'AskUserQuestion' agents/code-cleaner.md` → 0; - YAML check both files; `make test` green. - ```bash - git add skills/code-clean/SKILL.md agents/code-cleaner.md - git commit -m "feat(model-routing): /code-clean split — audit+gate inline, code-cleaner = sonnet PHASE-2 executor" - ``` - ---- - -### Task 18: wave-3 census + docs + memory - -**Files:** -- Modify: `lib/tests/model-routing.test.sh` (guarded — CONTROLLER applies) — wave-3 asserts -- Modify: `README.md`, `CHANGELOG.md`, `.claude/memory/decisions.md`, - `.claude/memory/journal.md`, `.claude/tasks/TODO.md` - -- [ ] **Step 1 (CONTROLLER — guarded): extend the census.** Sentinel first: - `printf 'model-routing plan: wave-3 executor-shape asserts (bugfix, code-clean)' > .claude/.config-edit-ok` - In `lib/tests/model-routing.test.sh`, add a `# 8) wave-3 — bugfix/code-clean - reflection-split executors` section: - `has skills/bugfix/SKILL.md 'subagent_type="bugfixer"'`; - `has agents/bugfixer.md 'model: sonnet'`; - `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'`. - (bugfix + code-clean stay in the existing `# 1)` wired-gate loop — do NOT move - them.) Update the printed expected count. Flip-test one new assertion (LRN-096: - e.g. temporarily break the bugfixer dispatch string, confirm red, restore). - -- [ ] **Step 2: README + CHANGELOG.** In the BDR-066 agent-model table, MOVE - `bugfixer` and `code-cleaner` out of the "inherit session" row into the - executor/dispatched rows (bugfixer → sonnet executor; code-cleaner → sonnet - PHASE-2 executor). The "inherit session" row keeps analyzer + seo/geo/validator - analyzers (+ commit-changer stays wherever wave-2 placed it). CHANGELOG - Unreleased `### Changed`: add the wave-3 bullet (bugfix/code-clean split — - reflection inline, executors sonnet; refactor now runs on sonnet inside the - code-clean executor). - -- [ ] **Step 3: Capitalize.** Append a `**Wave 3**` bullet to the BDR-066 entry - in `.claude/memory/decisions.md`: bugfix + code-clean reflection-split - (executors sonnet); supersedes the BDR-050 "bugfix inline" carve-out (hotfix - went in wave 2, bugfix now); code-clean refactor finally on sonnet (inline-load - pin was inert). Note the accepted tradeoff (bugfix investigation↔fix coupling, - mitigated by DIAGNOSIS + verify loop). Journal line under 2026-07-15 + 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-3 census + docs + BDR-066 update (bugfix/code-clean split)" - ``` - -- [ ] **Step 4: Final wave-3 review** — dispatch a whole-branch reviewer (opus) - over the wave-3 range; confirm: bugfix keeps root-cause-first + the pre-commit - gate + verify+secure loop with the executor as the loop's dev; code-clean keeps - the interactive validation gate + exported-symbol per-item consent at the gate - (not in the executor); zero execution left on the big model in either skill; - both executors have no `AskUserQuestion` and are `model: sonnet`. Report the - full `git log --oneline develop..HEAD`. Do NOT merge. - ---- - -# WAVE 4 — client-handover: dispatch the doc-generation to sonnet (redaction-only, spec §5, user directive 2026-07-16) - -**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. - -## Architecture - -- **`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 | 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\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. diff --git a/docs/superpowers/specs/2026-07-15-model-routing-design.md b/docs/superpowers/specs/2026-07-15-model-routing-design.md deleted file mode 100644 index e1b1419..0000000 --- a/docs/superpowers/specs/2026-07-15-model-routing-design.md +++ /dev/null @@ -1,143 +0,0 @@ -# Model routing — reflection inline (big model) / execution pinned (Sonnet) — design - -**Date**: 2026-07-15 · **Status**: approved (user, 2026-07-15) · **Branch**: `feature/model-routing` -**Lifecycle**: transient planning artifact (BDR-065) — committed during the run, deleted post-merge. - -## Principle - -The session model is assumed to be a big reasoning model (Fable 5, or Opus when -Fable is unavailable). Everything that **thinks** — brainstorming, planning, -technical decisions, audits, loop decisions — runs INLINE in the main -conversation, or in subagents that inherit the session model. Everything that -**executes** a ready-made plan — writing code, applying fix bundles, commits, -deliverable rendering — runs on Sonnet-pinned subagents. A blocking gate -enforces the "session = big model" assumption at the entry of every reflection -orchestrator. - -User verdicts baked in (2026-07-14/15): -- Scope = hybrid: ship-feature/init-project execution → sonnet; `/feat` - re-architected (plan inline → dispatch executor); bugfix/hotfix stay fully - inline (BDR-050 conserved for them). -- Gate = BLOCKING, not advisory. -- Audit agents inherit the session model (no opus pin); the gate extends to - audit orchestrators. -- verifier + security-auditor KEEP `model: sonnet` (job9 decision confirmed). -- client-handover-writer → sonnet (requires converting its inline-load to a - true dispatch; human gates relocate to the main loop). - -## 1. Blocking model gate - -New `lib/model-check.sh`: resolves the current session model from -`settings.json` (physical path resolution — LRN-023 class), normalizes -(`claude-fable-5[1m]` → fable, `claude-opus-*` → opus, sonnet, haiku), prints -`big|small|unknown`. Exit 0 = big, 2 = small, 3 = unknown. - -New `lib/model-gate.md` snippet (same include pattern as `lib/design-gate.md`): -run the check; `small` → STOP the skill: "session model is — reflection -requires Fable/Opus. Switch with /model, then relaunch." `unknown` → -fail-visible: show the raw value, ask the user to confirm or abort (BDR-025 -doctrine — unknown never silently passes). - -Wired as a STEP 0 line in the reflection orchestrators: -`ship-feature, init-project, feat, bugfix, onboard, seo, geo, web-validate, -harden, audit-delta, tour, code-clean`. -NOT wired in: `hotfix` (trivial by definition), `commit-change`, `doc`, -`status`, `release-candidate`. - -Caveats to prove at implementation time: -- `/model` mid-session rewrites settings.json (LRN-098 observed it once — - re-prove with a live flip-test before trusting the source). -- The helper itself must be flip-tested (LRN-096: an unproven guard is a - vacuous guard). - -## 2. Frontmatter pins (`agents/*.md`) - -| Agent | Before | After | Rationale | -|---|---|---|---| -| feater | (inherit) | **sonnet** | executor as subagent: seo/geo L1 applier + new /feat dispatch | -| hotfixer | (inherit) | **sonnet** | L1 applier (seo/geo/web-validate); /hotfix inline unaffected (pin inert on inline load) | -| client-handover-writer | opus | **sonnet** | deliverable executor; pin becomes EFFECTIVE only with §5 dispatch conversion (today's opus pin is inert — the agent is inline-loaded) | -| analyzer | haiku | **(none — inherit)** | analysis feeds the plan = reflection; runs big via the session model | -| verifier | sonnet | keep | F1 confirmed (job9) | -| security-auditor | sonnet | keep | F1 confirmed (job9) | -| seo-analyzer, geo-analyzer, validator-analyzer | (inherit) | keep (inherit) | audit = reflection = session model; covered by the gate | -| code-cleaner | (inherit) | keep (inherit) | audit phase = reflection; fixes hand off to refactorer (sonnet) via CODE-CLEAN-SCOPE.md (job9 H1) | -| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet | keep | workers/executors | -| status-reporter | haiku | keep | mechanical collector | -| bugfixer, commit-changer | (inherit) | keep | inline-only playbooks — a pin would be inert | - -## 3. `/feat` re-architecture (partial supersede of BDR-050 — feat only) - -`skills/feat/SKILL.md` absorbs the reflection: analyze-before-plan, design -gate, MINI-PLAN, contract (`lib/contract-interview.md`) — all inline. Then -dispatches `Agent(subagent_type="feater")` (sonnet via pin) with: the -contract, the plan, the branch name, repo conventions. - -`agents/feater.md` is rewritten as a pure executor: implement the plan to the -letter, run project checks, commit (no attribution trailers), return a -structured summary. No user interaction inside feater (subagents cannot ask) — -every decision must be closed pre-dispatch. - -The verify-secure loop moves out of feater.md into the /feat main loop -(LRN-083 invariant: loop decisions live in the main loop): fresh verifier → -ECARTS → re-dispatch feater with the verdict deltas, bounded 3×; then the -security gate. Escalation paths unchanged. - -## 4. SDD execution pinned (ship-feature STEP 4, init-project STEP 8) - -One instruction line in each SKILL.md: every implementation subagent -dispatched under `superpowers:subagent-driven-development` MUST carry -`model: "sonnet"` in the Agent call. No fork of the superpowers skill — the -main loop emits the Agent calls and controls the params. - -## 5. client-handover conversion (inline-load → true dispatch) - -`skills/client-handover/SKILL.md`: collect params inline (URL, logo, options), -then `Agent(subagent_type="client-handover-writer")` — the sonnet pin becomes -effective. Human gates (per-axis threshold escalation, overrides) RELOCATE to -the main loop: the writer returns a structured `GATE NEEDED` status instead of -asking; the dispatcher asks the user and re-dispatches (or continues via -SendMessage) with the decision. `AskUserQuestion` is removed from the writer's -tools. - -OPEN VERIFY POINT: the writer's own nested dispatches (seo/harden re-runs as -general-purpose subagents) — verify at implementation what nested children -inherit (session model vs parent model). If they inherit the sonnet parent, -the re-run audits violate the principle → force the model explicitly in those -nested dispatches or lift them to the main loop. - -## 6. web-validate fixes → L1 applier - -STEP 3 stops applying fixes via inline Edit; dispatches `hotfixer` (sonnet) -with the fix bundle — same pattern as seo/geo (BDR-061 alignment). - -## 7. Memory / doc / tests - -- New BDR: model-routing principle (reflection inline big / executors sonnet / - blocking gate); partial supersede of BDR-050 (feat only); records F1 - (verifier/security stay sonnet) and the analyzer haiku→inherit change. -- README: agent-model table refresh. CHANGELOG Unreleased entry. -- Tests: flip-tests for `model-check.sh` (fable[1m] / opus / sonnet / garbage - fixtures); gate STOP proven on a small-model fixture (LRN-096); /feat smoke - on a throwaway repo (LRN-079): plan inline → dispatch carries sonnet → - verify loop decided in main loop; grep census: no executor dispatch without - an effective pin. - -## Out of scope / accepted deviations - -- `/doc` and `/commit-change` stay inline on the session model (judgment and - execution interleaved; converting them buys little). Revisit under quota - pressure. -- bugfix/hotfix fully inline (BDR-050 conserved). -- No per-agent "fable-else-opus" fallback exists in the harness — the session - model IS the fallback mechanism; the gate is its backstop. - -## Risks - -- Model strings in settings.json may change shape with CC updates → - model-check must return `unknown` (fail-visible), never guess. -- feater as a subagent loses main-conversation context → the plan becomes the - contract; weak plans cost verify-loop iterations. Mitigation: - contract-interview stays mandatory in /feat. -- Nested model inheritance under client-handover-writer unknown → §5 verify - point.