1061 lines
43 KiB
Markdown
1061 lines
43 KiB
Markdown
# 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 <file>` clean and `bash -n <file>` 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: <what you are writing>' > .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=<path>` for fixtures.
|
||
- Produces: stdout `<class>:<raw>` 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 : <class>:<raw> (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 `<class>:<raw>`; 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 (<raw>) — self-check says <model>` and ask the user to confirm before continuing (BDR-025: unknown never silently passes) |
|
||
|
||
**STOP means**: print exactly
|
||
|
||
⛔ MODEL GATE — session on <model>. 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: <feature description>
|
||
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 <x>`, `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: <feature name> — rule <N>, ~<N> files, <brief approach>
|
||
```
|
||
|
||
## 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/<date>-<slug>-<HHMM>.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:
|
||
[ ] <file> — <what to do>
|
||
[ ] <file> — <what to do>
|
||
[ ] <test file> — <test to add>
|
||
```
|
||
|
||
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: <path from STEP 0.7>
|
||
PLAN: <the STEP 1 checklist + approach bullets + edge cases, verbatim>
|
||
BRANCH: <current branch — verify with git branch --show-current, never switch>
|
||
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(<scope>): <what was added>
|
||
|
||
<brief description of the feature>
|
||
```
|
||
|
||
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 : <name>
|
||
FILE(S) : <created/modified files>
|
||
TEST(S) : <added tests>
|
||
VERIFIED : <what was checked>
|
||
```
|
||
|
||
## STEP 6 — DOC SYNC (automatic)
|
||
|
||
Load `$HOME/.claude/agents/doc-syncer.md`.
|
||
Execute in automatic mode:
|
||
`auto-mode scope: <list of files modified during this session>`
|
||
|
||
**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 — <titre> (optionnel)
|
||
[learnings.md] LRN-XXX — <pattern> (optionnel)
|
||
Valider ? (all / <IDs> / 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 : <created/modified paths>
|
||
TESTS : <added/updated + final suite run result, verbatim line>
|
||
NOTES : <DONE: deviations (must be none) | NEED-DECISION: the exact
|
||
question + the options you see | BLOCKED: the blocker verbatim>
|
||
```
|
||
````
|
||
|
||
- [ ] **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: "<paste the file-group's bundle items: file, issue, current,
|
||
expected fix>.
|
||
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`.
|