Tweak
Fast path for small web-stack changes: a bugfix, copy/styling adjustment, config change, or small
refactor that fits 1-3 files. Everything heavier belongs to /dev-ship — the gate that decides is
shared/TWEAK-DISCIPLINE.md (size gate, backlog guard, registration
policy, never-do list). No TaskCreate phase tracking — a tweak run is minutes of work with no
compaction risk; ceremony is what this skill exists to avoid (deliberate, not a gap:
check-task-markers.py expects 0 units here). Safe to run several /dev-tweak
invocations concurrently against the same repo/branch — PHASE 4's commit lands atomically per
shared/SCOPED-COMMIT.md § 5. Skill file stays English; user-facing
output follows CLAUDE.md § User Preferences → Language:.
Tweak configuration (per shared/TWEAK-DISCIPLINE.md):
- verify: scoped tests + lint per PHASE 3 below
- escalation ship target:
/dev-ship - escalation debug target:
/dev-ship {feature}debug round, or the inline DEBUG-LADDER.md tier-3 discipline outside a feature context
PHASE 0 — Pre-flight, size gate & backlog guard
Todo: session already in plan mode at invocation (harness-level, not this skill's own) → still run steps 1-3 and 5-6 now — they're read-only and plan-mode-safe. Defer only step 4 (a write) to the first action after the session's next
ExitPlanModeresolves, before PHASE 1 starts. A fired gate/guard still routes toreferences/escalate.mdregardless of plan mode.
Repo: resolve
$REPOpershared/SYNC.md§ Worktree-aware Path Resolution —git worktree list --porcelain | head -1for{main_worktree}vsgit rev-parse --show-toplevelfor{current}; different → use{main_worktree}/.project/..project/absent → degrade gracefully: skip the card lookup, guard, and learnings silently, keep the rest (the code change is the value; do not scaffold).Mode + description:
.project/present → resolve the card with the narrowest load that can answer the question, per shared/TWEAK-DISCIPLINE.md § Card pickup path 1 (exact name, or an unambiguous ≥2-shared-token match against liveTWEAKcards):- Invocation argument is a bare kebab-case token (a plausible card name) → try the
single-card load FIRST:
node ~/.claude/scripts/backlog-load.js "$REPO" read-feature "<arg>".present: true+type: "TWEAK"→ card mode, and this payload already carriesdependencies[]— no second read, noguard-itemsload at all (card mode skips step 5's guard anyway, so the full-backlog payload would be loaded for nothing). present: false, a non-TWEAK type, or free-text prose → THEN loadnode ~/.claude/scripts/backlog-load.js "$REPO" guard-itemsfor the ≥2-shared-token match and step 5's guard (one load, not two).- Match → card mode. Description = the card's
description. Dependency check againstdependencies[]from whichever load ran (guard-itemsomits the field — on that path read the matched card'sdependenciesfrombacklog.jsondirectly): oneAskUserQuestiononly when a dependency is present and not yetshipped/DONE(per TWEAK-DISCIPLINE § Card pickup); no dependencies field → skip silently. A dependencyread-featurereports aspresent: falseis usually already resolved and archived, not missing — look it up in.project/archive/backlog-archive.json#archived[]and checkshipped: true(the criterion per TWEAK-DISCIPLINE § Card pickup). An archivedfeature.jsoncarriesstatus, nevershipped, sostatus: "DONE"there is a weaker fallback signal, not the check. - No match, or
.project/absent → free-text mode. Description from the invocation argument; if empty, ask one short question.
- Invocation argument is a bare kebab-case token (a plausible card name) → try the
single-card load FIRST:
Branch guard.
Todo: run shared/TWEAK-DISCIPLINE.md § Branch guard's actual check now —
git symbolic-ref --short refs/remotes/origin/HEAD(or themain/masterfallback) vsgit branch --show-current. Run both commands; never infer the default branch from the session's environment block or from memory. On the default branch → continue silently. Any other branch or detached HEAD → warn + ask before proceeding.Baseline — mandatory precondition for PHASE 4 and for a later escalate.md "override" choice, not optional ceremony.
Todo: run now, before step 5's gate check: `mkdir -p .project/session && git status
--porcelain | sort > .project/session/pre-tweak-status.txt` per
shared/SCOPED-COMMIT.md § 1 (skip only when
.project/is absent). Runs even when the gate is about to escalate — the file is cheap and unblocks a later "Continue as tweak" override without re-deriving state.
Gate (intake pre-check) + guard.
Apply shared/TWEAK-DISCIPLINE.md § Size gate criteria 1, 5 and 6 to the projected scope now — never from memory or from this file's own intro framing (criteria 2, 3 and 4 need the real file set and are decided in PHASE 1 step 2 instead). Use the shared table's own numbers — do not renumber locally:
- 1 — Net-new surface — adds capability instead of adjusting existing behavior
- 5 — Guard hit with in-pipeline status — see § Backlog guard resolution
- 6 — Debug tier-3 signals — intermittent failure, cause spans multiple modules, or a prior fix attempt already failed (DEBUG-LADDER.md tier 3)
Any of these fires → Read
references/escalate.mdnow, before locating.§ Backlog guard: card mode → skip (the card already names the scope — a fresh dedup would just rediscover itself). Free-text mode → run § Backlog guard as before, then § Card pickup path 2 (the TWEAK-only mini-guard) against the same
guard-itemsload from step 2.Todo: if any gate criterion fires or a guard demands escalation → Read
.claude/skills/dev-tweak/references/escalate.mdand follow it — never continue silently.Slug: card mode → the card's own kebab
name(no re-derivation). Free-text mode → derive a kebab-case slug from the description (commit scope + learnings feature key).Todo: print the intake status now, at this phase boundary — not deferred to the final report:
Guard: ✓ no card overlap(or the warn/advisory lines). Card mode printsCard: {name}instead — the card already names the scope (step 5 skipped the guard), so there is no guard result to report. Runs even when step 5's gate is about to escalate (same mirrored rule as step 4's baseline) —references/escalate.md § 3 (a)reads this printed name when it promotes the card out of the tweak lane. TheGate:verdict itself prints in PHASE 1 step 2, once the file set is known — do not print it here.
PHASE 1 — Locate & context
Locate the change with minimal reads (Grep → targeted Read). The files found here feed the size-gate re-check and the learnings load below.
Pre-seeded from a ship de-escalation handoff (invocation carries a
files[]+acceptance[]pair, per shared/TWEAK-DISCIPLINE.md § De-escalation gate (a)) → skip the Grep/Read locate itself; use the passedfiles[]as the located set directly. Everything downstream is unchanged: step 2's size-gate re-check still runs against that set — the handoff is not an exemption from it, and a criterion firing here still escalates exactly as a freshly-located set would. Hold the passedacceptance[]in memory and use it as PHASE 3's verify checklist (a test/check that exercises one of its scenarios counts toward Tier 1's auto-pass condition) instead of relying on whatever coverage happens to already exist.Todo: an intake step here — a clarifying
AskUserQuestion, or what the located code reveals — can surface that the real scope exceeds the size gate (the described 1-file tweak is actually a schema/sequencer/multi-file change). The moment it does, Readreferences/escalate.mdand escalate before any design work — do not run an Explore/plan/EnterPlanModecycle on the out-of-scope shape first (that is the intake-side twin of PHASE 2's "do not finish the edit first"). Holds even when the session is already in harness plan mode. This gates every step below: only once it clears do steps 2-5 run.Todo (card mode): locate shows the described defect already resolved on
main(a later commit fixed it, or it never applied — stale), or the card's whole reason to exist is superseded by a wider card (nothing fixed it, another card absorbed it — confirm with oneAskUserQuestionnaming that card first) → skip PHASE 2, PHASE 3, and PHASE 4 step 1 entirely (including step 3's learnings load); go straight to the matching PHASE 4 write per shared/TWEAK-DISCIPLINE.md § Card pickup → Stale card / Obsolete-superseded card. Both cases: commit nothing, report carries noVerdict:/commit-sha line. Superseded decline → continue the tweak as originally scoped.Close the size gate — with the file set now known, apply shared/TWEAK-DISCIPLINE.md § Size gate criteria 2, 3 and 4 (file span, new test file, architecture) to the actual files. Criterion 3 fires on a new test file or harness only — new cases in an existing test file are tweak-compatible. A criterion fires → Read
references/escalate.mdbefore any design work.Todo: print
Gate: ✓ tweak-sized ({n} file(s))now. Not printed → this step did not run; do not proceed to step 3. One exception to "now": an intakeAskUserQuestionin step 1 whose answer itself decides the file set (a scope choice between a 1-file and a 2-file fix) — print theGate:line after that answer lands, since{n}does not exist before it. Never skip the print, only defer it past that one question.Learnings — mandatory, not gated on tweak size. Run exactly this, after locate so
--pathscarries the real file anchors (see shared/LEARNINGS-LOAD.md for the full parameter/relevance model):node ~/.claude/scripts/learnings-search.js "$REPO" load \ --feature "{slug}" --scopes component --pitfall-prefix true \ --paths "{located files, comma-separated, repo-relative}"Todo: any non-zero exit (including exit 2, usage error) is a failed step, not a zero-match result — fix the invocation and re-run before proceeding. Only exit 0 with empty stdout is a genuine zero. The count feeds step 5's
Lane:line below; no separate print here.Durable-decisions check — dev-tweak's only route back to a feature's already-settled design questions (
durableDecisions[]has no other reader on the modify path — seeshared/FEATURE-LOAD.md)..project/absent (already degraded at PHASE 0 step 1) → skip silently, same as the rest of this skill's graceful degradation..project/present → grep.project/features/*/feature.jsonand.project/features/archive/*/feature.jsonforfiles[].pathentries matching any located file (repo-relative path match). No match on any feature → skip silently, no cost — most tweaks touch files no pipeline feature ever built.Todo: a feature matched → project its decisions first (cheap, no Read):
node -e 'const f=require(process.argv[1]); console.log(JSON.stringify((f.durableDecisions||[]).map( x=>({decision:x.decision,constraint:x.constraint,chosen:x.chosen}))))' \ <path-to-feature.json>Every projected entry has a null/absent
constraintandchosen→ no recorded constraint can bind this tweak: say so in one clause and continue, no Read. Otherwise → Read.claude/skills/dev-tweak/references/durable-decisions.mdand follow it (multi-match tiebreak, how the constraints bind PHASE 2).Lane routing.
Todo: judge this table fresh against this run's actual locate/learnings results, never from memory. Evaluate rows in order; the first match picks the lane. Source of truth: shared/TWEAK-DISCIPLINE.md § Lane routing — do not renumber locally, same policy as PHASE 0 step 5's inlined size-gate criteria.
# Condition Lane 1 Stale or obsolete/superseded card, or a docs-only / .project-only change (docs-only = no tracked source file is edited; a docstring or comment edit inside a source file is a code change and does not qualify)A 2 A verify round in this run failed, or a size-gate escalation was consciously overridden (§ Escalation gate c) C 3 PHASE 1 locate left ≥2 candidate sites open, or landed on none B 4 A learning printed with type pitfallcarries the⟨path⟩marker (its ownpaths[]overlap a located file) — read the marker, never re-classifyB 5 Otherwise A A lane only ever moves up during a run, and never overrules the size gate. Row 2 fired → Read TWEAK-DISCIPLINE § Lane routing for its hard rules (the second failed round ends the tweak) before designing.
Then print one line, always — Lane A included:
Lane: {A|B|C} · Learnings: {n} ({matched pitfall, or "no pitfall on located paths"}).{n}= total lines the load printed across all blocks — a raw count, not a deduped one; nothing downstream depends on the exact number.
PHASE 2 — Implement
STOP — gate before the first
Edit: scroll up and confirm four artifacts exist above this point — a printedGate:line (PHASE 1 step 2), alearnings-search.jstool result (step 3), afeature.jsongrep result or its "no match" (step 4), and a printedLane:line (step 5). Judge what the transcript shows, not what you remember doing. Any one absent → go back to that step now; do not edit first and reconcile after. All four present → say so in one line (Pre-edit gate: ✓ 4/4) before the firstEdit— a gate that leaves no trace cannot be distinguished from a gate that was skipped. An escalation firing in PHASE 1 is the one exception: the run ends atreferences/escalate.mdinstead, which prints its own two-line report.Lane execution — run the lane PHASE 1 step 5 picked:
- A — direct. No
EnterPlanMode. Edit straight away. - B — designed.
EnterPlanMode(skip if already active) → design → write the decision to the plan file →ExitPlanMode→ implement. - C — B plus a second opinion. A
Planagent (model: "opus") writes the design, then a Fable consult on the plan file per shared/SECOND-OPINION.md, both beforeExitPlanMode.
Semantics and the hard rules stay in shared/TWEAK-DISCIPLINE.md § Lane routing. Four dev-side deltas:
- Row 4 (pitfall) triggered the lane → the plan file's design names the concrete mitigation in one line — part of the design, not a separate print.
- Lane C → the Fable digest must be visible before
ExitPlanMode, when the gate is presented. - Opus/Fable involvement is not a size-gate exemption — a wider file span or net-new surface
found during design still routes to
references/escalate.md. - The harness may open its own plan-mode workflow prescribing Explore/
Planagent fan-out onEnterPlanMode. Ignore it: the file set is already located, a tweak designs inline.
- A — direct. No
Edit discipline per shared/TWEAK-DISCIPLINE.md § Edit discipline — read-before-write, bounded read size, deliberate (not random) test-file pick. A located file has a frontend extension (
.tsx/.jsx/.vue/.svelte/.cssor equivalent) → load the theme digest (same extraction as/dev-inspectPHASE 0 step 4 — color tokens, motion,cssVars; session-memoized) and Read shared/EDIT-DISCIPLINE.md, hold the diff against it. No frontend file located → skip both, no cost.Bugfix-shaped tweaks follow shared/DEBUG-LADDER.md tier 1/2: hypothesis before edit, evidence before a second attempt — never guess-and-check.
Mid-flight re-check.
Todo: the moment actual scope exceeds the size gate (a 4th source file touched, a discovered new surface) → stop now and Read
references/escalate.md— do not finish the edit first and reconcile after.
PHASE 3 — Verify light
A tweak that edits no git-tracked file at all — only gitignored .project/ state (e.g.
recording a known issue as a learning) — or a stale or obsolete/superseded card with nothing to
edit (see PHASE 1) — has nothing to verify and nothing to commit: skip PHASE 3 and PHASE 4 step 1,
say so in the report (no Verdict:/commit sha lines), and go straight to the card-completion (or
cancellation) + learning writes. A docstring/comment-only edit inside a tracked source file is
still a code change — it runs the normal verify + commit flow below, just with no behavior for a
test to exercise (routes to PHASE 3's Tier 2 modal, not the auto-pass tier). Everything below
assumes a code change.
Scoped to the touched modules — never the full suite unless it is genuinely fast:
- Tests: run existing tests covering the touched files. Take the test and lint commands from the
project's own docs first —
CLAUDE.md § Commands,.project/, or the test harness's own config — and only fall back to the web defaults below when the project names none. A non-JS project (Python/Go/Rust/C++) will not have the commands in the next two bullets. - The documented command is suite-wide (the common case outside JS:
pytest <dir>,go test ./...,cargo test) → do not run it as written; the project naming it does not make it scoped. Derive the scoped form — append the touched test file(s), or a-k/pattern filter — and run any build/compile step those same docs mandate as its own separate command. Run the unscoped command only when a measured run comes back under ~60s; over that, name in the report which scoped subset ran instead. - The project's docs mandate a post-build step (deploy, sync an artifact to a runtime data
directory, restart a service) → it belongs to verify, not to "later": a green test run on a build
the user's runtime never received is a false pass. Run it. Could not run it → it becomes a PHASE 4
step 4
Next steps:item, phrased as the command the user runs — never a line inside the report fence: an unrun step is the user's action, and label-value lines read as archive data they scroll past. - Web defaults:
npx vitest related <files>, or the project's test command with a path/pattern filter. - Harness failure (collection/import error, missing interpreter or deps, stale virtualenv) is
not a baseline regression — repair it when the broken piece is gitignored local state (e.g. a
stale
.venv), say so in the report, then re-run. Never edit source to make a broken harness pass. - Lint: on changed files only — Biome (
npx biome check) when@biomejs/biomeis in package.json; ESLint when configured; skip with one line otherwise.tsc --noEmitonly when configured and cheap. - Visual/copy tweaks: re-check live in the running app (DEBUG-LADDER tier 1) instead of tests.
Drive the app via the
/runskill — it owns the per-project launch path (browser dev-server, Tauri/Electron desktop shell) so this stays project-agnostic. Capture concrete evidence before judging pass: a screenshot, a computed-style/DOM assertion, the changed pixels — never an eyeballed "looks right". Can't reach/drive the running app (wrong worktree, no dev server, headless environment) → say so explicitly and ask the user to verify visually; never report the live check as passed when it wasn't run.
New failures vs the baseline → fix within the current tier's discipline; unfixable within tweak
scope → Read references/escalate.md. Not a failed round: a test or assertion this same PHASE 2
pass authored failing on its own defect (an over-broad matcher, a wrong fixture), corrected without
touching the code under change — that is the test loop working. It becomes a failed round the moment
the correction reaches the source under change. A failed round also feeds
shared/TWEAK-DISCIPLINE.md § Lane routing row 2: the first
failed round in this run lifts to Lane C for the next PHASE 2 pass (re-score, don't re-derive from
scratch — the lane only ever moves up); a second failed round on the same issue routes to
references/escalate.md instead of a fourth lane.
Live verdict.
Todo: check the auto-pass condition below FIRST, before considering the modal — the modal is the fallback, not the default.
Tier 1 — auto-pass (no modal). Skip straight to PHASE 4 when all of these hold — machine proof only, never a self-assessment of "this is trivial":
- the checks above actually ran and came back clean, AND
- at least one test exercises the changed behavior (lint/typecheck alone doesn't count; a change with no covering test doesn't count), AND
- this is not a visual/copy tweak (the "visual/copy tweaks" bullet above still applies — a live re-check there is human judgment, not machine proof), AND no reachability caveat fired. That caveat is not visual/copy-only: it fires for any change whose user-visible effect can only be confirmed in a running app or runtime this session cannot drive (game engine, trading terminal, daemon). Source-level proof that the call site is correct is real evidence, but it is not that confirmation — route to Tier 2 and name what the user should look at.
Only the covering-test bullet failed, and coverage is one mechanical assertion away — an
existing test file already covers the touched module AND the assertion is mechanical (a value, a
source-level invariant, a rendered string) → add that one case, re-run the checks, and re-evaluate
Tier 1. Size-gate criterion 3 fires on a new test file only, so this stays tweak-sized, and PHASE
4's commit-type list already carries test for exactly this. No such file, or the assertion needs a
new harness or fixture (criterion 3 fires) → Tier 2. Bounded on purpose: never invent a test whose
only purpose is to dodge the modal.
Any other one of these failing → Tier 2.
Tier 2 — ask. Correctness rests on human judgment → one AskUserQuestion before wrap-up, four
options. Use these four verbatim — do not improvise replacements even when a live check was
blocked; a blocked live check maps to I'll test it myself. For a visual/copy tweak the live
re-check above runs FIRST and the modal presents its evidence (screenshot / verified value) — so
Pass there is an informed confirm-and-commit, never a decision made before the result exists. A
fifth path, Re-score — design this properly, is deliberately NOT a modal option (AskUserQuestion
caps at 4) — reached only via the built-in Other answer; treat that answer exactly as its
bullet below describes:
Pass (Recommended)→ the shown result is correct → continue to PHASE 4 and commit.I'll test it myself→ state plainly what to test and what "pass" looks like, then wait — do not proceed to PHASE 4 until the user replies. "Works" → PHASE 4. "Doesn't hold up" → counts as a failed round (§ Lane routing row 2, same first/second-round rule as above) → back to PHASE 2 on the same file scope, then re-run PHASE 3.One more small tweak→ back to PHASE 2 for one more iteration on the same file scope, then re-run PHASE 3. This doesn't reset the size gate — a new file surfacing on this pass still firesreferences/escalate.mdexactly like any other mid-flight re-check (PHASE 2 step 5). Not itself a failed round (the prior pass may have verified clean) — only an actual PHASE 3 failure counts toward § Lane routing row 2.Re-score — design this properly(Other) → counts as a failed round (§ Lane routing row 2) → re-enter PHASE 2 step 2; the lane lifts per that row (first re-score → Lane C, second →references/escalate.md).Revert — restore to baseline, don't commit(per shared/TWEAK-DISCIPLINE.md § Edit discipline) → restore the working tree topre-tweak-status.txt(PHASE 0 step 4), commit nothing, skip PHASE 4 step 1 entirely. Card mode → the card is not touched (noshipped/CANCELLEDwrite — the defect is still open, this run just didn't fix it). Report closes withVerdict: reverted, not committedinstead of a commit sha.
PHASE 4 — Wrap-up
Scoped commit per shared/SCOPED-COMMIT.md — never a bare
git add && git commit. Write the commit message to a scratch file under.project/session/first, then land with exactly this call — the script accepts no other arguments, and in particular there is no baseline flag:pre-tweak-status.txtis your own reference for categorizing files, never something you pass in.bash ~/.claude/scripts/scoped-commit.sh \ --message <path-to-message-file> \ --files <comma-separated-paths>Deltas vs § 5, one rule per line:
- Baseline is
pre-tweak-status.txt; OVERLAP policy is auto-include (the fix is the point); fallback: ask which files belong to the tweak. --fileslists the files THIS run edited — never the whole baseline diff. A concurrent/dev-tweakon the same tree makes its own files look NEW against your baseline too (§ 2 buckets every changed file as NEW / OVERLAP / PRE-EXISTING; NEW cannot tell your file from theirs).- Message type is never
feat— a tweak adds no net-new capability (size-gate criterion 1). Use{fix|refactor|perf|style|test|docs|chore}({slug}): {summary};testwhen the only change is added or expanded test coverage,docswhen it is a docstring/comment/markdown-only edit (PHASE 3's comment-only branch). - Cleanup: remove the baseline file and the commit-message scratch file.
- Baseline is
Card-mode completion (skip entirely in free-text mode): move the card from
.project/backlog.json#features[]to.project/archive/backlog-archive.json#archived[], setting exactlyshipped: true,shippedAt(YYYY-MM-DD),shippedSha(step 1's commit), andsummary(the tweak's one-line outcome). Those four and no others — astatusflip or atransitiondelete is not part of this write. Semantics, the archiving contract, and the dashboard rationale live in shared/TWEAK-DISCIPLINE.md § Card pickup → completion write; read it only if the move itself is unclear.Then run shared/BACKLOG.md § Archive-move invariant: re-read both files and confirm the card is absent from
features[]and present inarchived[]with all four fields. A running board app (serve-backlog.js) can silently revert an external write from its in-memory store — re-apply on a revert. Only once this holds does the report carryCard: {name} → shipped.Obsolete/superseded card instead (PHASE 1's confirmed obsolete branch): run that same file's § Card pickup cancellation write instead — the card stays in
features[], no archive move.Optional learning (0-1): only for a bugfix whose root cause has value beyond this spot (filter per shared/LEARNING-WRITE.md § Writer Append Protocol). The payload goes in on stdin — there are no
--feature/--summaryflags:node ~/.claude/scripts/learnings-write.js append "$REPO" <<'JSON' {"entries":[{"feature":"{slug}","type":"pitfall","source":"extracted", "summary":"...","tags":["..."],"paths":["{located file}"]}]} JSONpathscarries the located files — PHASE 1 step 3 loads with--paths, so a learning written without them is invisible to this skill's own next relevance load. 0-3 tags perLEARNING-WRITE.md § Tag Vocabulary. A non-zero exit is a failed step, not a zero result — fix the payload and re-run (same rule as PHASE 1 step 3). Then run the Consolidation Gate once (LEARNING-WRITE.md § Consolidation Gate). Skip both silently otherwise. No state auto-push (TWEAK-DISCIPLINE § Registration policy).Stale-learning correction — separate from the 0-1 budget above, and not gated on the bugfix filter: PHASE 1 step 3's load surfaced a learning this tweak just made wrong (a convention it renamed, a limit it lifted, a path it moved) or superseded (the workaround it prescribes is no longer the best route) → correct that entry in place. Same stdin shape as
append, with the patch fields flat alongsidematch— a nested{"match":…,"patch":{…}}is silently ignored:node ~/.claude/scripts/learnings-write.js enrich "$REPO" <<'JSON' {"patches":[{"match":{"feature":"...","type":"pitfall", "summaryEquals":"<exact current summary>"}, "summary":"<corrected summary>"}]} JSONThis call fails silently. Exit 0 with
{"patched":0,"alreadyApplied":1}on a first correction means the payload was not understood, not that the work was already done — re-read the entry and confirm the summary actually changed before reporting it. Onlypatched: 1is success. This repairs existing memory rather than adding to it, so it neither counts against the 0-1 budget nor triggers the Consolidation Gate, and it is not a new backlog write. Leaving a contradicted learning in place is the drift trap this closes — the next run reads it as current and undoes the tweak.Report — one fenced block per
shared/OUTPUT.md§ Report Block (≤72 chars, Label-value grammar), with any "what changed" prose detail outside the fence.Todo: Read
.claude/skills/shared/OUTPUT.md§ Report Block now, before composing the block — 75 lines. Reconstructing the grammar from memory drops the====underline and lets explanatory sentences into the fence, the two rules that decide whether the user can scan the result at all.Repeat the
Card:/Guard:,Gate:andLane:lines here even though they printed mid-run — this block is the durable record. Fields:what changed, with
file:linerefs; checks run; commit shaa
Guard:line reflecting PHASE 0's actual result — never assert "no card overlap" if the guard didn't run (say so instead); card mode prints this exact form instead of aGuard:label:Card: {name} → shipped, orCard: {name} → cancelled (superseded by {card})for the obsolete/superseded outcomea
Verdict:line —auto-passed on green checks ({n} tests + lint)for a Tier 1 auto-pass, oruser-confirmed/self-testedfor whichever Tier 2 path was taken. Auto-pass is never silent — the report always states why the modal didn't fire.a
Lane:line always, Lane A included —Lane: {A|B|C} · Learnings: {n}(carry PHASE 1 step 5's line forward verbatim; B/C append the matching row in one line). This field is the proof PHASE 1 step 3's learnings load actually ran — its absence means that step was skipped.a
Consult:line only when Lane C actually spawned a consult — values per shared/SECOND-OPINION.md § Logging (consulted ({trigger})/consulted ({trigger}) → revised/consulted ({trigger}) → confirmed/unavailable). Omit entirely on Lane A/B — there is nothing to log.a
Learning:line when one was written;Escalation overridden: {criterion}when applicablea post-fence
Next steps:numbered block (shared/SKILL-PATTERNS.md § Next Steps) when either trigger fires; neither fires → a tweak is terminal, no next-step offer:- PHASE 3 could not run a project-mandated post-build step → the command the user must run, first in the list. Fires in card mode too, where the tweak is otherwise terminal.
- the guard flagged a TODO card (free-text mode only) →
/dev-ship {card}
An escalation park (
references/escalate.md § 3 (a)) prints its ownPick it up with /dev-ship {name}.line instead of this block.
Todo: raised a skill-feedback point alongside this report (friction observed during the run, per
~/.claude/CLAUDE.md § Skill Feedback) → store it now, in one call:node ~/.claude/scripts/skill-feedback.js add --skill dev-tweak --note "<point>"(repeat--noteper point;--source userfor a point the user raised). The report is not the store — an unstored point is lost, so/core-auditnever sees its recurrence count. Nothing observed during the run → no call, no ritual closer.