feat(model-routing): /hotfix split — reflection inline + gate, hotfixer = sonnet executor (dual-use applier preserved)

This commit is contained in:
Bastien Chanot
2026-07-15 19:28:58 +02:00
parent f36aec370b
commit 45cd86810a
4 changed files with 255 additions and 169 deletions
+52 -156
View File
@@ -1,92 +1,48 @@
--- ---
name: hotfixer 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). 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 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. You apply a fix that was ALREADY decided upstream and prove it doesn't break
The fix is inline (no dev subagents); a fresh security gate runs before the build — you never investigate or design the fix. Two dispatch sources,
commit, and any gate failure reverts — never loops. Get in, fix, gate, same job:
get out.
## REQUEST - **/hotfix orchestrator** — root-cause analysis happened in its LOCATE step;
$ARGUMENTS 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 Applier path (/seo, /geo, /web-validate): no CONTRACT/LOCATED/FIX keys — the
straight to the source: 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 ## EXECUTION RULES
git status
git log --oneline -3
```
- Read the relevant file(s). Confirm the root cause is obvious - Apply the minimal change that fixes the bug. Edit only what is necessary
and superficial (typo, wrong value, missing import, etc.). — no refactoring, no cleanup, no "while we're here" improvements.
- If the bug turns out to be deeper than expected (unclear cause, - Stay inside the scope you were given. On the /hotfix path that is the
multiple files involved, logic error): STOP and say: contract FILE SCOPE (max 2 files) — a fix that needs more → `STATUS
"This looks deeper than a hotfix. Load `$HOME/.claude/agents/bugfixer.md` BLOCKED`, report why (the orchestrator escalates to `/bugfix`), never
and run the BUGFIXER agent on this target." expand scope yourself. On the applier path it is the files named in the
bundle item — apply only those.
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/<date>-<slug>-<HHMM>.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.
- If tests exist for the affected code, run them. Detection cascade: - If tests exist for the affected code, run them. Detection cascade:
```bash ```bash
# JS/TS # JS/TS
@@ -102,85 +58,25 @@ Apply the minimal change that fixes the bug:
test -f Makefile && grep -qE '^test:' Makefile && echo "make test" test -f Makefile && grep -qE '^test:' Makefile && echo "make test"
``` ```
Run whichever one resolves; if none → continue to smoke check below. Run whichever one resolves; if none → continue to smoke check below.
- Smoke check (always, even when no tests): try the build/typecheck command for - Smoke check (always, even when no tests ran): try the build/typecheck
the stack — `npm run build`, `tsc --noEmit`, `cargo build`, `go build ./...`, command for the stack — `npm run build`, `tsc --noEmit`, `cargo build`,
`python -c "import <pkg>"` — to confirm the fix did not break compilation. `go build ./...`, `python -c "import <pkg>"` — 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. HOTFIX-EXEC REPORT
- If no tests: smoke check from STEP 2 must have passed. STATUS : DONE | BLOCKED
2. **Failure branch** — if tests fail OR smoke check fails after the fix: FILE(S) : <changed files>
- Print the failure output verbatim (under 30 lines). FIX : <one-line description>
- Run `git restore .` to revert the working-tree edits to the pre-flight SHA. SMOKE : <test/build result, verbatim line>
(Files were not yet staged — restore is safe.) NOTES : <BLOCKED: the blocker; DONE: none>
- 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(<scope>): <what was wrong>
```
5. Print summary:
```
HOTFIX APPLIED
FILE(S) : <changed files>
FIX : <one-line description>
VERIFIED: <test name or smoke check that passed>
SECURITY: <PASS | DEGRADED (checklist only)>
```
## STEP 4 — 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 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.
+20 -7
View File
@@ -13,6 +13,7 @@ FSK="$REPO/skills/feat/SKILL.md"
BUG="$REPO/agents/bugfixer.md" BUG="$REPO/agents/bugfixer.md"
HOT="$REPO/agents/hotfixer.md" HOT="$REPO/agents/hotfixer.md"
HSK="$REPO/skills/hotfix/SKILL.md" HSK="$REPO/skills/hotfix/SKILL.md"
HSKL="$REPO/skills/hotfix/SKILL.md"
PASS=0; FAIL=0 PASS=0; FAIL=0
tf() { # tf <label> <file> <fixed-string> tf() { # tf <label> <file> <fixed-string>
@@ -29,6 +30,13 @@ tr_() { # tr_ <label> <file> <ERE>
echo " FAIL $1 — no match: $3"; FAIL=$((FAIL+1)) echo " FAIL $1 — no match: $3"; FAIL=$((FAIL+1))
fi fi
} }
tn() { # tn <label> <file> <fixed-string> — PASS when ABSENT (mirror of tf, inverted)
if grep -qF -- "$3" "$2" 2>/dev/null; then
echo " FAIL $1 — present (should be absent): $3"; FAIL=$((FAIL+1))
else
echo " PASS $1"; PASS=$((PASS+1))
fi
}
echo "── verify-secure-loop.md (shared include) ──" echo "── verify-secure-loop.md (shared include) ──"
if [ -f "$INC" ]; then echo " PASS include exists"; PASS=$((PASS+1)); else echo " FAIL include missing"; FAIL=$((FAIL+1)); fi if [ -f "$INC" ]; then echo " PASS include exists"; PASS=$((PASS+1)); else echo " FAIL include missing"; FAIL=$((FAIL+1)); fi
@@ -57,14 +65,19 @@ tf "bug diagnosis feeds it" "$BUG" "feeds it: REQUEST verbatim"
tf "bug fresh gates" "$BUG" "Fresh gates (verify + secure)" tf "bug fresh gates" "$BUG" "Fresh gates (verify + secure)"
tf "bug uses shared include" "$BUG" "lib/verify-secure-loop.md" tf "bug uses shared include" "$BUG" "lib/verify-secure-loop.md"
echo "── hotfixer.md (hotfix wiring — revert, not loop) ──" echo "── hotfixer.md (hotfix executor — sonnet, no Agent) ──"
tr_ "hotfix has Agent tool" "$HOT" "^tools:.*Agent" tn "hotfixer lacks Agent tool" "$HOT" "Agent"
tf "hotfix silent contract" "$HOT" "STEP 1.7 — CONTRACT (silent autofill)" tf "hotfixer model sonnet" "$HOT" "model: sonnet"
tf "hotfix zero questions" "$HOT" "questions ever" tf "hotfixer report grammar" "$HOT" "HOTFIX-EXEC REPORT"
tf "hotfix security gate" "$HOT" "Security gate (fresh auditor)"
tf "hotfix block reverts" "$HOT" "failure REVERTS, never loops" echo "── skills/hotfix/SKILL.md (hotfix wiring — revert, not loop) ──"
tf "hotfix no verifier" "$HOT" "No verifier is dispatched at hotfix weight" tf "hotfix silent contract" "$HSKL" "STEP 1.7 — CONTRACT (silent autofill)"
tf "hotfix zero questions" "$HSKL" "questions ever"
tf "hotfix security gate" "$HSKL" "Security gate (fresh auditor)"
tf "hotfix block reverts" "$HSKL" "failure REVERTS, never loops"
tf "hotfix no verifier" "$HSKL" "No verifier is dispatched at hotfix weight"
tf "hotfix skill has Agent" "$HSK" " - Agent" tf "hotfix skill has Agent" "$HSK" " - Agent"
tf "hotfix dispatches hotfixer" "$HSKL" 'subagent_type="hotfixer"'
echo "" echo ""
echo "loops-light structure locks: $PASS pass, $FAIL fail" echo "loops-light structure locks: $PASS pass, $FAIL fail"
+3 -3
View File
@@ -9,12 +9,12 @@ 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; } 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; } 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 # 1) gate wired in the 13 reflection orchestrators
for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean; do for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean hotfix; do
has "skills/$s/SKILL.md" 'lib/model-gate.md' has "skills/$s/SKILL.md" 'lib/model-gate.md'
done done
# 2) gate NOT wired in the excluded skills (encodes the spec exclusion list) # 2) gate NOT wired in the excluded skills (encodes the spec exclusion list)
for s in hotfix commit-change doc status release-candidate; do for s in commit-change doc status release-candidate; do
lacks "skills/$s/SKILL.md" 'lib/model-gate.md' lacks "skills/$s/SKILL.md" 'lib/model-gate.md'
done done
# 3) executor + gate pins # 3) executor + gate pins
+180 -3
View File
@@ -18,9 +18,186 @@ allowed-tools:
- Agent - Agent
--- ---
Load and follow strictly: # /hotfix — quick-fix orchestrator (reflection inline, execution dispatched)
- $HOME/.claude/agents/hotfixer.md
Execute the HOTFIXER agent on the following target: 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 $ARGUMENTS
---
## STEP 1 — LOCATE (reflection)
Find the bug. Use the description and any error message to go
straight to the source:
```bash
git status
git log --oneline -3
```
- 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."
- Settle the proposed fix HERE — the executor cannot ask questions, so the
exact edit (what changes, in which file(s)) must be closed before dispatch.
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.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 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 from STEP 1. It writes `.claude/tasks/contracts/<date>-<slug>-<HHMM>.md`.
This is the reference the executor reads first, and the scope for STEP 4's
security gate and the escalation report if a gate fails. No verifier is
dispatched at hotfix weight — STEP 4's smoke result already verifies these
trivial criteria; the gate hotfix adds is security (STEP 4).
## STEP 2 — PRE-FLIGHT
**Gitflow aiguillage (before dispatch):** 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`.
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?"`.
## STEP 3 — DISPATCH EXECUTOR
Dispatch the executor — sonnet by frontmatter pin, do not override:
```
Agent(subagent_type="hotfixer")
prompt: "CONTRACT: <path from STEP 1.7>
LOCATED: <file(s) found in STEP 1 + the confirmed root cause>
FIX: <the proposed minimal fix, closed in STEP 1>
BRANCH: <current branch — verify with git branch --show-current, never switch>
Apply the minimal fix. No refactoring, no commit, no branch ops, no
security dispatch, no revert. Finish with the HOTFIX-EXEC REPORT."
```
Parse the `HOTFIX-EXEC REPORT`:
- `STATUS : DONE` → STEP 4 (the SMOKE line in the report decides pass/fail
there; DONE here means execution completed, not that it verified clean).
- `STATUS : BLOCKED` → if any edits were made, `git restore .` to the
pre-flight SHA (STEP 2); surface the blocker to the user; STOP. One
attempt only — hotfix never re-dispatches (escalate to `/bugfix` for
deeper work).
## STEP 4 — VERIFY + SECURE + COMMIT (main loop, LRN-083)
1. Read the SMOKE line from the executor's report. **Failure branch** — if
it reports a failing test/build result:
- Print the failure output verbatim (under 30 lines).
- Run `git restore .` to revert the working-tree edits to the pre-flight
SHA (STEP 2). (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.
2. **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.
3. Commit using conventional format (only after smoke AND security pass):
```
fix(<scope>): <what was wrong>
```
4. Print summary:
```
HOTFIX APPLIED
FILE(S) : <changed files>
FIX : <one-line description>
VERIFIED: <test name or smoke check that passed>
SECURITY: <PASS | DEGRADED (checklist only)>
```
## STEP 5 — 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 hotfix. No FINISH in an inline flow, so
it just commits the docs on the current branch (no ordering concern).
## STEP 6 — 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`.
- Reflection (LOCATE, contract, gate decisions) NEVER leaves this main
loop; execution NEVER stays in it — the executor is the sonnet-pinned
hotfixer subagent (BDR-066).
- The executor is dispatched FRESH, once — hotfix never re-dispatches (no
decision round-trips; a blocked or failed attempt reverts and escalates
to `/bugfix`, it does not retry).
- Design gate only if CSS/style signals detected. See STEP 1.5.
- **Revert-not-loop preserved**: smoke FAIL or security BLOCK → `git
restore .` to the pre-flight SHA + STOP + escalate to `/bugfix`; hotfix
never loops. No verifier is dispatched at hotfix weight.
- If root cause is unclear → escalate to `/bugfix` (STEP 1).
- If fix touches >5 lines of logic → reconsider if this is
truly a hotfix.