T-DYZJ-planning-exemption-splits-open-from-closed
Status: planning/proposed · Impact: medium · Complexity: small
AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-07-20 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.
Path-reference sweeps that repoint citations after a move exempt
docs/planning/ wholesale, treating every planning entity as a frozen
historical record. That reasoning holds for closed entities and fails for
open ones: an open backlog item citing a pre-move path is naming a
forward-looking work target, not recording history, so exempting it
strands whoever picks it up at a dead path. Split the exemption by entity
status so closed records stay frozen while open work items get swept.
Reported from T-C9RD-consolidate-augmented-into-solutions in
https://github.com/sksizer/dev:
Reference sweeps that repoint paths after a move exempt docs/planning/ wholesale, on the reasoning that planning entities are historical records whose citations should stay frozen. That is right for closed entities and wrong for open ones. During T-C9RD, B-6V5U and B-UEE4 — both status: open/active backlog items citing pre-move paths as forward-looking WORK TARGETS — were exempted and will now send whoever picks them up at dead paths. Split the exemption by entity status: closed/* entities stay frozen as historical record; open/active entities are in scope for the sweep (or at minimum are reported as stale-citation warnings). Touchpoints: the paths claim resolver at apps/sdlc/lib/model/entities/task/claims/ and the reference-sweep guidance in apps/sdlc/conventions/.
| Location | Role today |
|---|---|
apps/sdlc/conventions/ | Home of the canonical shared conventions each SKILL.md references instead of inlining. There is no reference-sweep doc here, so the post-move sweep rule — including the docs/planning/ exemption — exists only as ad-hoc prose re-invented in each task’s ACs. |
docs/planning/tasks/T-C9RD-consolidate-augmented-into-solutions.md | AC-7 carries the exemption in its wholesale form (“historical planning records exempt”), which is what stranded the two open backlog items. |
apps/sdlc/lib/model/entities/task/claims/paths.ts | Flags a back-ticked, path-shaped citation whose path no longer exists but whose basename uniquely matches one file elsewhere. Runs per-task inside the readiness gate only; its detection core is module-private and it ignores the entity’s status. |
apps/sdlc/lib/model/corpus/loader.ts#loadCorpus | Walks docs/planning/ into a basename → {type, status} index — the existing seam that already knows every planning entity’s status. |
apps/sdlc/lib/model/read.ts#scanEntities | Bulk frontmatter scan across the planning dirs; the read layer any corpus-wide walk must go through. |
apps/sdlc/lib/model/ops/index.ts | Explicit barrel for the generic cross-entity ops (audit, validate, migrate, check-identifiers, get-schema). model/ops/ is not a discovery-walk root, so an op registers by being re-exported here. |
apps/sdlc/skills/task-work/SKILL.md | Step 1’s relevance check verifies paths cited by the task being picked up. Nothing covers the reciprocal direction — repointing citations held by other entities after this task moves a file. |
apps/sdlc/lib/model/entities/task/implementation-ready.md | Requires a delete row to enumerate every referencing file as its own modify row, but says nothing about how docs/planning/ participates in that enumeration. |
Proposed
Section titled “Proposed”Codify the sweep rule once, split by entity status, and make the split checkable instead of prose-only:
closed/*planning entities are frozen historical records — out of scope for a post-move citation sweep.- Every other planning entity is a live work item whose citations name forward-looking targets, so it is in scope and its stale citations are reported.
The reporting half rides on the detection core already written for the
paths claim resolver, lifted to a corpus-wide, advisory op.
Approach
Section titled “Approach”- Write the convention. Add
apps/sdlc/conventions/reference-sweep.mdas the single home for post-move sweep guidance: what a sweep covers (doc citations, hooks, CI/lefthook gates, eval harnesses, non-.mdstring fields), and the status split above stated as the rule, with the T-C9RD/B-6V5U/B-UEE4 incident as its one-paragraph rationale. - Expose the detection core. In
apps/sdlc/lib/model/entities/task/claims/paths.ts, exportcollectCitations,indexBasenames, andstripLocationSuffix. The resolver’s ownresolve()and its findings are unchanged; only the module’s export surface widens so a second caller can reuse the walk. - Add the corpus op. Add
apps/sdlc/lib/model/ops/stale-citations.ts, adefineOp({ noun: "entities", verb: "stale-citations" })descriptor modelled on the siblingcheck-identifiers.ts. It resolves the planning root fromctx.projectRoot(overridable via an optionalplanningRootinput), enumerates entities throughscanEntities, drops any whosestatusstarts withclosed/, and runs the Step-2 helpers over each survivor’s body. Output:{ findings: [{ file, path, line, relocated }] }whererelocatedis the unique same-basename match ornull. Severity is advisory — the op always exits 0 and reports; it never blocks. - Register it. Re-export the descriptor from
apps/sdlc/lib/model/ops/index.tsalongside the other generic ops. - Test the split. Add
apps/sdlc/lib/model/ops/tests/stale-citations.test.tswith a fixture planning dir holding two entities that carry the identical stale citation — oneclosed/done, oneopen/active— and assert only theopen/activeone appears infindings. - Point the two consumers at the convention. Add a one-line pointer in
apps/sdlc/skills/task-work/SKILL.md’s Notes and in the delete-row paragraph ofapps/sdlc/lib/model/entities/task/implementation-ready.md. One-line references only — no duplicated prose, per the progressive-disclosure rule inapps/sdlc/skills/CLAUDE.md.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
apps/sdlc/conventions/reference-sweep.md | new | Canonical post-move sweep guidance carrying the closed/*-frozen / non-closed-in-scope split. |
apps/sdlc/lib/model/entities/task/claims/paths.ts | modify | Export collectCitations, indexBasenames, stripLocationSuffix; resolver behaviour untouched. |
apps/sdlc/lib/model/ops/stale-citations.ts | new | entities stale-citations op — status-filtered corpus walk reporting stale citations held by non-closed entities. |
apps/sdlc/lib/model/ops/index.ts | modify | Re-export the new op descriptor so importing the barrel registers it. |
apps/sdlc/lib/model/ops/tests/stale-citations.test.ts | new | Fixture test pinning the status split (closed skipped, open reported). |
apps/sdlc/skills/task-work/SKILL.md | modify | One-line Notes pointer to the convention doc. |
apps/sdlc/lib/model/entities/task/implementation-ready.md | modify | One-line pointer from the delete-row enumeration paragraph to the convention doc. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
apps/sdlc/conventions/reference-sweep.mdexists and states the split in both directions — aclosed/*planning entity is exempt from a post-move citation sweep, a non-closed one is in scope. - AC-2:
apps/sdlc/cli/sdlc entities stale-citations --output jsonexits 0 and emits afindingsarray whose entries each carryfile,path,line, andrelocated. - AC-3: the op drops any entity whose
statusstarts withclosed/— pinned by the fixture inapps/sdlc/lib/model/ops/tests/stale-citations.test.ts, where two entities carry the identical stale citation and only theopen/activeone is reported. - AC-4:
apps/sdlc/lib/model/ops/index.tsre-exports the new descriptor, andapps/sdlc/cli/sdlc entities stale-citations --helpprints the op’s summary. - AC-5:
apps/sdlc/skills/task-work/SKILL.mdandapps/sdlc/lib/model/entities/task/implementation-ready.mdeach carry a one-line pointer toapps/sdlc/conventions/reference-sweep.md, with the sweep prose itself living only in that doc. - AC-6: the
pathsresolver’s behaviour is unchanged —bun test apps/sdlc/lib/model/entities/task/claims/tests/passes with no edits to its existing expectations.
Out of scope
Section titled “Out of scope”- Repointing the concrete citations in
docs/planning/backlog/B-6V5U-retire-augmented-logging-and-augmented-utils-for-native.mdanddocs/planning/backlog/B-UEE4-adopt-sksizer-panes-determined-ui-across-migrated-vue-apps.md. T-C9RD-consolidate-augmented-into-solutions is stillin-progressand the cited paths still exist, so there is nothing stale to repoint yet. - Promoting the op to a blocking gate (lefthook / CI). It is advisory in this task; a gate is a separate decision once the finding volume is known.
- Auto-rewriting stale citations. The op reports; repointing stays an implementer action.
- Splitting on any frontmatter field other than
status(e.g. staleness bylast_reviewed).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-07-20 UTC from T-C9RD-consolidate-augmented-into-solutions in https://github.com/sksizer/dev.