Context
The "no decay-prone ticket/Epic/Discussion/ADR refs in durable SHIPPED artifacts (.mjs JSDoc/comments, learn/ docs, Dockerfile/config)" discipline has recurred as a repeat violation despite being captured in agent memory (empirical: #11940 / #12113 / #12151, and again across this session in #12290 spec comments + #12209 base/view comments). The discriminator is sound — durable-shipped prose vs tracking-coordination (PR bodies, commit subjects (#TICKET), ticket/A2A/Discussion bodies, test.describe(...) anchors are load-bearing and stay) — but enforcement is discipline-only, and discipline loses to the authoring reflex of "cite the motivating ticket as the reason" at every comment.
Per AGENTS.md §self_evolving_systems ("mechanical guard > discipline-only") + §friction_to_gold, a recurring discipline-slip is a substrate signal for a mechanical guard, not another memory reminder.
The Problem
When tickets close / rename / get superseded, ticket refs embedded in durable code comments rot into dangling archaeology that poisons KB ingestion and misleads future readers. A passive memory entry cannot prevent this — it requires the author to remember + judge at every comment.
The Fix
Add buildScripts/util/check-ticket-archaeology.mjs (mirroring check-shorthand.mjs): a check script that, given staged [files...] (or a default-dir scan), flags ticket-ref patterns (#\d{4,}, Epic #N, Discussion #N, ADR-?\d{3,4}) appearing in comment context within .mjs source, and exits non-zero.
- Comment-context detection: line/block comments (
//, /* */, JSDoc * ) — NOT string literals, so test.describe('... (#11645)') and other load-bearing string anchors stay exempt.
- Escape hatch: an inline
ticket-ref-ok marker exempts a genuinely load-bearing line (judgment-call relief valve, not a blanket bypass).
- Wiring: add to
lint-staged "*.mjs" (alongside check-shorthand) — staged-files scan → incremental adoption (only flags a file when it is touched; no big-bang repo cleanup required).
- Self-test: a unit spec proving it flags a JSDoc/
// ticket ref, exempts a test.describe string ref, and honors the escape marker.
Substrate-Accretion Defense
Adds the guard script + lint-staged entry, but enables compressing/retiring the passive MEMORY.md jsdoc_archaeology_self_audit entry — the discipline moves from fragile-memory to reliable-mechanism. Decay-mitigation: prevents the recurring rot directly.
Acceptance Criteria
Out of Scope (follow-up)
.md / learn/ + Dockerfile/compose scanning (more legit-ref edge cases; stage after the .mjs guard proves out).
- Repo-wide CI gate (needs a full pre-existing-violation sweep first).
- Retiring the MEMORY.md entry (do once the guard is merged + proven).
Context
The "no decay-prone ticket/Epic/Discussion/ADR refs in durable SHIPPED artifacts (.mjs JSDoc/comments, learn/ docs, Dockerfile/config)" discipline has recurred as a repeat violation despite being captured in agent memory (empirical: #11940 / #12113 / #12151, and again across this session in #12290 spec comments + #12209 base/view comments). The discriminator is sound — durable-shipped prose vs tracking-coordination (PR bodies, commit subjects
(#TICKET), ticket/A2A/Discussion bodies,test.describe(...)anchors are load-bearing and stay) — but enforcement is discipline-only, and discipline loses to the authoring reflex of "cite the motivating ticket as the reason" at every comment.Per
AGENTS.md §self_evolving_systems("mechanical guard > discipline-only") + §friction_to_gold, a recurring discipline-slip is a substrate signal for a mechanical guard, not another memory reminder.The Problem
When tickets close / rename / get superseded, ticket refs embedded in durable code comments rot into dangling archaeology that poisons KB ingestion and misleads future readers. A passive memory entry cannot prevent this — it requires the author to remember + judge at every comment.
The Fix
Add
buildScripts/util/check-ticket-archaeology.mjs(mirroringcheck-shorthand.mjs): a check script that, given staged[files...](or a default-dir scan), flags ticket-ref patterns (#\d{4,},Epic #N,Discussion #N,ADR-?\d{3,4}) appearing in comment context within.mjssource, and exits non-zero.//,/* */, JSDoc*) — NOT string literals, sotest.describe('... (#11645)')and other load-bearing string anchors stay exempt.ticket-ref-okmarker exempts a genuinely load-bearing line (judgment-call relief valve, not a blanket bypass).lint-staged"*.mjs"(alongsidecheck-shorthand) — staged-files scan → incremental adoption (only flags a file when it is touched; no big-bang repo cleanup required).//ticket ref, exempts atest.describestring ref, and honors the escape marker.Substrate-Accretion Defense
Adds the guard script + lint-staged entry, but enables compressing/retiring the passive MEMORY.md
jsdoc_archaeology_self_auditentry — the discipline moves from fragile-memory to reliable-mechanism. Decay-mitigation: prevents the recurring rot directly.Acceptance Criteria
check-ticket-archaeology.mjsflags#\d{4,}/ Epic / Discussion / ADR refs in.mjscomment context.test.describe('...(#11645)')) are NOT flagged.ticket-ref-okinline marker exempts a line.lint-staged*.mjs(staged-files, incremental).Out of Scope (follow-up)
.md/learn/+ Dockerfile/compose scanning (more legit-ref edge cases; stage after the .mjs guard proves out).