/drift — Which One Is Lying, the Spec or the Code?
Specs rot silently. Code drifts silently. Everything built on the wrong one
inherits the lie. This skill is a focused comparison, not a rewrite session —
cheap models do this well precisely because the procedure tells them exactly
what to compare.
Invocation
/drift {spec_dir}/AUTH_SPEC.md src/auth/ # spec vs implementation
/drift pagination # find the governing doc, then compare
Procedure
Fix the two sides. Side A = the declared truth (spec, README, API doc,
schema doc, config comment). Side B = the built truth (code, migrations, live
behavior). If multiple docs claim the same territory, note the conflict — that
is already a finding.
Extract testable claims from Side A. Go claim by claim, not vibe by vibe.
A claim is testable if a grep, a file read, or a command can confirm it:
endpoints listed, fields and types, defaults, error codes, invariants
("one row per event"), sequences ("X runs before Y").
Verify each claim against Side B. Actual grep/read/run per claim. Three
outcomes only:
MATCH — spec and code agree
DRIFT — they disagree (quote both sides: spec line + code file:line)
UNVERIFIABLE — claim too vague to test (that's a spec defect; report it)
For every DRIFT, name the liar. One of:
- Spec is stale — code moved on legitimately → fix: update the spec
- Code is wrong — spec is the intent, code violates it → fix: file a bug
- Ambiguous — can't tell which is authoritative → fix: escalate; someone
must own the call. Never pick silently.
Report. A table: claim | verdict | evidence | liar | fix. End with the one
number that matters: N claims, M drifted. If M/N > ~20%, say plainly that the
spec can't currently be trusted as a foundation.
Rules
- Read the spec FIRST, code second. Reading code first contaminates you with
code-as-intent, and you'll rationalize the drift away.
- Do not fix drift inline while sweeping — sweeping and fixing are different
altitudes; log fixes, finish the sweep, then fix.
- "The spec doesn't mention it" is a finding (coverage gap), not a MATCH.
Worked example (real ruling, 2026-07-09 — reproduced as a static transcript)
Sides: Side A = the repo's catalog doc (declared skill roster). Side B = the skills/ tree.
- Extracted claims: each catalog row asserts "a skill of this name exists here".
- Verified row by row against the tree: several rows had no matching
directory — deleted skills and overlay-only skills still listed as present.
- Verdict per row: DRIFT (doc names it, tree lacks it).
- Named the liar: the doc — the tree had legitimately moved on; the
catalog never followed.
- Fix landed at the doc layer, plus a mechanical check so the CLASS can't
recur: dropped the dead rows, marked overlay-only rows as such, and added
a CI rows-exist check (overlay rows exempt).
DRIFT: catalog vs skills/ | liar: spec (stale) | fix: doc + CI gate
Composes with
/refute — each spec claim is a claim to refute against the code.
spec-citation hook — forces reading the spec before editing protected paths,
which is drift prevention at write time; /drift is drift detection after the fact.
/altitude — a DRIFT whose fix keeps recurring is usually a wrong-layer problem.
/verdict — DRIFT/MATCH findings worth remembering are logged there.
/escalate — spec-vs-code conflicts you can't adjudicate queue there.
/sweep — a sweep's spec-drift dimension is /drift fanned out across the repo.
1---2name: drift3description: Spec vs code-as-built diff. Compares what a spec/doc/contract declares against what the code and live system actually do, and reports which one is lying. Use when behavior surprises you, before building on a spec, or as a periodic honesty sweep.4---56# /drift — Which One Is Lying, the Spec or the Code?78Specs rot silently. Code drifts silently. Everything built on the wrong one9inherits the lie. This skill is a focused comparison, not a rewrite session —10cheap models do this well precisely because the procedure tells them exactly11what to compare.1213## Invocation1415```16/drift {spec_dir}/AUTH_SPEC.md src/auth/ # spec vs implementation17/drift pagination # find the governing doc, then compare18```1920## Procedure21221. **Fix the two sides.** Side A = the declared truth (spec, README, API doc,23 schema doc, config comment). Side B = the built truth (code, migrations, live24 behavior). If multiple docs claim the same territory, note the conflict — that25 is already a finding.26272. **Extract testable claims from Side A.** Go claim by claim, not vibe by vibe.28 A claim is testable if a grep, a file read, or a command can confirm it:29 endpoints listed, fields and types, defaults, error codes, invariants30 ("one row per event"), sequences ("X runs before Y").31323. **Verify each claim against Side B.** Actual grep/read/run per claim. Three33 outcomes only:34 - `MATCH` — spec and code agree35 - `DRIFT` — they disagree (quote both sides: spec line + code file:line)36 - `UNVERIFIABLE` — claim too vague to test (that's a spec defect; report it)37384. **For every DRIFT, name the liar.** One of:39 - **Spec is stale** — code moved on legitimately → fix: update the spec40 - **Code is wrong** — spec is the intent, code violates it → fix: file a bug41 - **Ambiguous** — can't tell which is authoritative → fix: escalate; someone42 must own the call. Never pick silently.43445. **Report.** A table: claim | verdict | evidence | liar | fix. End with the one45 number that matters: N claims, M drifted. If M/N > ~20%, say plainly that the46 spec can't currently be trusted as a foundation.4748## Rules4950- Read the spec FIRST, code second. Reading code first contaminates you with51 code-as-intent, and you'll rationalize the drift away.52- Do not fix drift inline while sweeping — sweeping and fixing are different53 altitudes; log fixes, finish the sweep, then fix.54- "The spec doesn't mention it" is a finding (coverage gap), not a MATCH.5556### Worked example (real ruling, 2026-07-09 — reproduced as a static transcript)5758**Sides:** Side A = the repo's catalog doc (declared skill roster). Side B = the `skills/` tree.59601. Extracted claims: each catalog row asserts "a skill of this name exists here".612. Verified row by row against the tree: several rows had no matching62 directory — deleted skills and overlay-only skills still listed as present.633. Verdict per row: DRIFT (doc names it, tree lacks it).644. Named the liar: **the doc** — the tree had legitimately moved on; the65 catalog never followed.665. Fix landed at the doc layer, plus a mechanical check so the CLASS can't67 recur: dropped the dead rows, marked overlay-only rows as such, and added68 a CI rows-exist check (overlay rows exempt).6970`DRIFT: catalog vs skills/ | liar: spec (stale) | fix: doc + CI gate`7172## Composes with7374- `/refute` — each spec claim is a claim to refute against the code.75- `spec-citation` hook — forces reading the spec before editing protected paths,76 which is drift prevention at write time; /drift is drift detection after the fact.77- `/altitude` — a DRIFT whose fix keeps recurring is usually a wrong-layer problem.78- `/verdict` — DRIFT/MATCH findings worth remembering are logged there.79- `/escalate` — spec-vs-code conflicts you can't adjudicate queue there.80- `/sweep` — a sweep's spec-drift dimension is /drift fanned out across the repo.