workflow_lint: flag stale gotchas.md pointers after an entry relocates (live instance in research-project-structure.md)
Highlight text on any card (body, plan, or an event) to anchor a comment, or leave a whole-task comment here. Mention @claude to summon a reply.
No comments yet.
Mechanize the stale-relocation-pointer class: a lint flagging text that names
gotchas.md alongside a #<N> citation where #<N> no longer occurs in
.claude/rules/gotchas.md.
Why now
#2189 relocated 27 entries verbatim out of .claude/rules/gotchas.md into six
topic-owning rule files (a 24.4 KB reduction), and its ## Out of scope
section names generalized residual-relocation as a successor lever — so
more entries will move. Every relocation risks leaving behind a pointer that
still sends the reader to gotchas.md for a rule that now lives elsewhere.
Two live instances were found by hand during #2189's round-1 code review:
.claude/rules/upload-policy.md:247— pointed at "gotchas.md, #923" for the conditional-.enventry relocated to.claude/rules/pod-side-reporting.md. FIXED in #2189 commit2ddec80aad(it was in the round's own diff scope)..claude/rules/research-project-structure.md:73— the same class (`.claude/rules/gotchas.md`; incident #923), left UNFIXED because it was outside #2189's criterion-8 diff scope. This is a live stale pointer onmainright now and is the natural first regression fixture.
Both were caught by a reviewer reading prose. Nothing mechanical detects them.
A distinct, related instance worth handling in the same pass
.claude/rules/LESSONS.md's gotchas.md row — the ALWAYS-ON index — still
advertises the topic "chained smoke-then-full leg out-root residue" among
gotchas.md's contents, though #2189 relocated that rule to
.claude/rules/crash-fix-rounds.md. #2189 could not fix it: editing
LESSONS.md was a hard prohibition in that task (43 B of headroom against
_LESSONS_MAX_BYTES = 9600, and further trimming of that row was ruled out at
#1269).
This is the same failure mode one level up — the index misdirects rather than a
sibling rule file — and it argues the check should cover LESSONS.md trigger
rows too, not just #N co-references. Note the LESSONS.md form has no #N to
key on, so it needs a different detector (topic-phrase presence), and fixing
any LESSONS.md row still runs into that file's byte budget. Consider whether
this half belongs here or with the LESSONS.md budget decision.
Proposed shape (for the implementer to settle)
- Primary detector: for each
#<N>that co-occurs with agotchas.mdmention in a tracked.claude/**/*.mdfile, FAIL (or WARN) when#<N>does not appear in.claude/rules/gotchas.md. - Expect false positives: a pointer may legitimately cite
gotchas.mdfor CONTEXT while the#<N>belongs to a different claim in the same sentence. Calibrate against the live tree before choosing FAIL vs WARN — a WARN that actually fires beats a FAIL that gets suppressed. - Baseline is NOT clean:
research-project-structure.md:73must either be fixed in the same change or explicitly grandfathered.
Provenance
Filed by the #2189 orchestrator from the round-1 code-reviewer's prose
follow-up (lower-confidence, uncapped per
.claude/rules/workflow-fix-on-bug.md). Sibling of #2192 (conflict-marker
residue lint), filed from the same review.