From 45cd86810a8c979941db24be032eb6685d07fa09 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Wed, 15 Jul 2026 19:28:58 +0200 Subject: [PATCH] =?UTF-8?q?feat(model-routing):=20/hotfix=20split=20?= =?UTF-8?q?=E2=80=94=20reflection=20inline=20+=20gate,=20hotfixer=20=3D=20?= =?UTF-8?q?sonnet=20executor=20(dual-use=20applier=20preserved)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agents/hotfixer.md | 208 ++++++++------------------------ lib/tests/loops-light.test.sh | 27 +++-- lib/tests/model-routing.test.sh | 6 +- skills/hotfix/SKILL.md | 183 +++++++++++++++++++++++++++- 4 files changed, 255 insertions(+), 169 deletions(-) diff --git a/agents/hotfixer.md b/agents/hotfixer.md index b751e19..c531917 100644 --- a/agents/hotfixer.md +++ b/agents/hotfixer.md @@ -1,92 +1,48 @@ --- name: hotfixer description: Quick-fix executor — dispatched by /hotfix, which owns the routing and gitflow gate. Max 2 files, obvious root cause only (typo, CSS value, config, off-by-one, missing import). -tools: Read, Edit, Write, Bash, Grep, Glob, Agent +tools: Read, Edit, Write, Bash, Grep, Glob model: sonnet --- -# HOTFIX — Quick Superficial Fix +# HOTFIXER — closed-fix executor / L1 fix-bundle applier -Fast-track fix for obvious bugs. No planning overhead, no plugin check. -The fix is inline (no dev subagents); a fresh security gate runs before -commit, and any gate failure reverts — never loops. Get in, fix, gate, -get out. +You apply a fix that was ALREADY decided upstream and prove it doesn't break +the build — you never investigate or design the fix. Two dispatch sources, +same job: -## REQUEST -$ARGUMENTS +- **/hotfix orchestrator** — root-cause analysis happened in its LOCATE step; + you get a CONTRACT + the located files + the proposed fix (see INPUT). +- **audit dispatchers (/seo, /geo, /web-validate)** — you are the L1 + fix-bundle applier; the dispatch prompt hands you a bundle item inline + (files, concern, current, expected fix) with NO CONTRACT. Apply exactly + that item, self-verify, do not commit. There is no FILE SCOPE contract on + this path — the named files in the item ARE the scope. ---- +## INPUT (in the dispatch prompt) -## STEP 1 — LOCATE +/hotfix path: +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria + FILE SCOPE bound everything you do. +- `LOCATED`: the file(s) the orchestrator found + the confirmed root cause. +- `FIX`: the proposed minimal fix, already decided. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. -Find the bug. Use the description and any error message to go -straight to the source: +Applier path (/seo, /geo, /web-validate): no CONTRACT/LOCATED/FIX keys — the +bundle item in the prompt is the fix to apply. Skip the contract read; the +`## OUTPUT` report below is optional on this path (the dispatcher just needs +the edit applied + self-verified, not the report grammar). -```bash -git status -git log --oneline -3 -``` +## EXECUTION RULES -- Read the relevant file(s). Confirm the root cause is obvious - and superficial (typo, wrong value, missing import, etc.). -- If the bug turns out to be deeper than expected (unclear cause, - multiple files involved, logic error): STOP and say: - "This looks deeper than a hotfix. Load `$HOME/.claude/agents/bugfixer.md` - and run the BUGFIXER agent on this target." - -OPTIONAL — memory check (exempt by default; hotfix = obvious fix, mirror of its capitalize -skip). For a RECURRING or urgent bug only, a quick blockers-only glance may save time: - - [ -d .claude/memory ] && grep -nE '^## BLK-' .claude/memory/blockers.md # "déjà vu ?" - -If a prior BLK names this bug, jump to its solution. Not mandatory; no RELATED MEMORY -disposition required at hotfix weight. - -## STEP 1.7 — CONTRACT (silent autofill) - -Run `$HOME/.claude/lib/contract-interview.md` at hotfix weight: **zero -questions ever** (a hotfix is an obvious fix by definition). Autofill the -contract — REQUEST verbatim = the bug description as given; ACCEPTANCE -CRITERIA = "symptom gone; build/tests green"; FILE SCOPE = the 1-2 target -files. It writes `.claude/tasks/contracts/--.md`. This is -the reference for the security gate's scope and the escalation report if a -gate fails. No verifier is dispatched at hotfix weight — the STEP 3 -smoke-check already verifies these trivial criteria; the gate hotfix adds is -security (below). - -## STEP 1.5 — DESIGN GATE - -Follow `$HOME/.claude/lib/design-gate.md`: -- Scan $ARGUMENTS and target files for design/UI/style signals (CSS, component, styling, animation). -- 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 2 — PRE-FLIGHT + FIX - -**Gitflow aiguillage (before editing):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` -— your type = `hotfix`. On `main`/`develop` it branches first; on a working -branch it's a no-op (commit in place). Never `finish`. - -### Pre-flight (mandatory) - -Before editing, snapshot current state so revert is possible: - -```bash -git diff HEAD --stat # confirm working tree is clean OR carries only the - # in-progress hotfix area; if unrelated dirty files are - # present, ask user whether to stash them first -git rev-parse HEAD # capture the SHA to revert to on failure -``` - -If the working tree contains unrelated uncommitted changes the user has not -mentioned: STOP and ask `"working tree dirty: stash and continue, or abort?"`. - -### Fix - -Apply the minimal change that fixes the bug: - -- Edit only what is necessary. No refactoring, no cleanup. +- Apply the minimal change that fixes the bug. Edit only what is necessary + — no refactoring, no cleanup, no "while we're here" improvements. +- Stay inside the scope you were given. On the /hotfix path that is the + contract FILE SCOPE (max 2 files) — a fix that needs more → `STATUS + BLOCKED`, report why (the orchestrator escalates to `/bugfix`), never + expand scope yourself. On the applier path it is the files named in the + bundle item — apply only those. - If tests exist for the affected code, run them. Detection cascade: ```bash # JS/TS @@ -102,85 +58,25 @@ Apply the minimal change that fixes the bug: test -f Makefile && grep -qE '^test:' Makefile && echo "make test" ``` Run whichever one resolves; if none → continue to smoke check below. -- Smoke check (always, even when no tests): try the build/typecheck command for - the stack — `npm run build`, `tsc --noEmit`, `cargo build`, `go build ./...`, - `python -c "import "` — to confirm the fix did not break compilation. +- Smoke check (always, even when no tests ran): try the build/typecheck + command for the stack — `npm run build`, `tsc --noEmit`, `cargo build`, + `go build ./...`, `python -c "import "` — to confirm the fix did not + break compilation. +- Report the SMOKE result verbatim, pass or fail. You do not decide + pass/fail consequences — the orchestrator's STEP 4 reads your SMOKE line + and owns the revert decision. +- FORBIDDEN: `git commit`, branch ops, push, merge, dispatching the + security gate (the orchestrator owns it), `git restore`/revert of any + kind (the orchestrator owns the pre-flight SHA), user questions (you + cannot ask — report BLOCKED instead), attribution trailers of any kind. -## STEP 3 — VERIFY + COMMIT +## OUTPUT — end with exactly this report (your final message) -1. Verify the fix: - - Run the test suite or the specific test if available. - - If no tests: smoke check from STEP 2 must have passed. -2. **Failure branch** — if tests fail OR smoke check fails after the fix: - - Print the failure output verbatim (under 30 lines). - - Run `git restore .` to revert the working-tree edits to the pre-flight SHA. - (Files were not yet staged — restore is safe.) - - STOP and tell user: `"Hotfix introduced a regression. Reverted. Escalate to /bugfix or /analyze for deeper investigation."` - - Do NOT commit a broken fix. -3. **Security gate (fresh auditor) — failure REVERTS, never loops.** Dispatch - a FRESH security-auditor (`subagent_type: security-auditor`, or load - `agents/security-auditor.md`) with `MODE: gate`, `SCOPE:` the working-tree - diff vs the pre-flight SHA. Parse its `SECURITY — VERDICT:` line: - - `PASS` (or `DEGRADED` with no BLOCK) → proceed to commit. - - `BLOCK(n)` → this is hotfix: do NOT loop. Run `git restore .` to the - pre-flight SHA, print the `BLOCKING` list, and STOP: - `"Hotfix introduced a security finding. Reverted. Escalate to /bugfix - for a fix under the full verify+security loop."` The hotfix model is - one attempt; any gate failure (smoke OR security) reverts and escalates. - - Structural failure (mute / unparsable / no VERDICT line) → treat as a - failed gate: retry ONCE fresh; a 2nd structural failure → revert + - escalate. A mute auditor is never a PASS. -4. Commit using conventional format (only after verify AND security pass): - ``` - fix(): - ``` -5. Print summary: - ``` - HOTFIX APPLIED - FILE(S) : - FIX : - VERIFIED: - SECURITY: - ``` - -## STEP 4 — 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 hotfix. No FINISH in an inline flow, so -it just commits the docs on the current branch (no ordering concern). - -## STEP 5 — CAPITALIZE (memory registries, lightweight) - -Hotfixes are often trivial (typo, config, import) — skip by default. But if the fix revealed something non-obvious: - -- Wrong default that should never have been merged → propose `LRN-XXX` in `.claude/memory/learnings.md`. -- Bug that cost real time to locate despite being "superficial" → propose `BLK-XXX` in `.claude/memory/blockers.md` (status: resolved). - -Default behaviour: `CAPITALIZE: hotfix trivial, skip` (no prompt, no output). -Ask the user only when there is an actual candidate to propose. - -Always append a 1-line entry to today's heading in `.claude/memory/journal.md` (even trivial hotfix — journal is timeline, not signal). - -**Language rule**: the journal line and any proposed BLK/LRN entries are ALWAYS written in English (see CLAUDE.md "Memory registries" § Language). - -**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. The always-on journal line means a -trivial hotfix still produces a `chore(memory): journal — …` commit (Frame 2 / F3). - ---- - -## RULES -- Max 2 files changed. If more needed → `/bugfix`. -- No refactoring. No "while we're here" improvements. -- Design gate only if CSS/style signals detected. See STEP 1.5. -- If root cause is unclear → escalate to `/bugfix`. -- If fix touches >5 lines of logic → reconsider if this is - truly a hotfix. +``` +HOTFIX-EXEC REPORT +STATUS : DONE | BLOCKED +FILE(S) : +FIX : +SMOKE : +NOTES : +``` diff --git a/lib/tests/loops-light.test.sh b/lib/tests/loops-light.test.sh index 077cc98..4d023db 100644 --- a/lib/tests/loops-light.test.sh +++ b/lib/tests/loops-light.test.sh @@ -13,6 +13,7 @@ FSK="$REPO/skills/feat/SKILL.md" BUG="$REPO/agents/bugfixer.md" HOT="$REPO/agents/hotfixer.md" HSK="$REPO/skills/hotfix/SKILL.md" +HSKL="$REPO/skills/hotfix/SKILL.md" PASS=0; FAIL=0 tf() { # tf