T-AVDD-ac-grep-allow-legacy-ref-marker
Status: closed/superseded · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
Tasks whose ACs are shaped as “grep returns zero hits for the old
path/symbol” (a common shape for migrations) routinely match
legitimate prose: comments documenting the migration as an
anti-pattern, test constants intentionally encoding the forbidden
string for regression coverage, changelog references. The
implementer of T-G834-move-plugin-runtime-state-to-sdlc-dir
had to rephrase comments and assemble a test constant from string
fragments (".claude" + "/" + "worktrees/") just to satisfy the
grep gate. An opt-in # allow-legacy-ref: <token> marker on a
single line would let prose document migration history without
weakening the AC’s coverage of real regressions.
| Location | Role today |
|---|---|
The setup_planning.pyandrun_evals.py comments documenting | <migrated from v2 — no role recorded> |
A test constant FORBIDDEN_CLAUDE_WORKTREES_LINE in | <migrated from v2 — no role recorded> |
Proposed
Section titled “Proposed”Path-grep ACs that need to forbid a token but tolerate a finite number of deliberate references support a single-line opt-in marker:
# allow-legacy-ref: .claude/worktrees/ (documents the pre-migration layout)Lines carrying this marker are excluded from the grep’s match set. The marker names the exact token being excused (so reviewers can audit every excused line), and a free-form trailing comment captures the reason.
The reference implementation is a small wrapper script (e.g.
plugin/scripts/grep_with_allow.py) that runs the underlying
grep, post-filters out lines bearing a matching
# allow-legacy-ref: <prefix> annotation, and exits zero/nonzero
on the filtered count. ACs that adopt it cite the wrapper instead
of bare grep.
Approach
Section titled “Approach”- Decide the marker syntax. Default proposal: a per-line trailing
comment of the form
# allow-legacy-ref: <token>, where<token>must appear on the same line for the suppression to apply. Strict per-line scoping avoids “this whole file is excluded” ambiguity. - Implement
plugin/scripts/grep_with_allow.py(new). Wrapsgrep -rn -E <pattern> <paths>, post-filters lines carrying# allow-legacy-ref: <substring-of-match>, prints surviving matches to stdout, exits zero iff zero matches survive. - Add a small test fixture (e.g.
plugin/scripts/test_grep_with_allow.py) covering: match with no marker (fail), match with matching marker (suppress), match with non-matching marker (fail), nested directory traversal. - Document the marker in
plugin/conventions/(likely a short new doc, or appended to an existing AC-pattern doc if one exists). - Optionally retrofit
setup_planning.py’s test constant assembly andrun_evals.pycomments to use the marker — the originating task already shipped without the marker, so this is cleanup not a blocker.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/scripts/grep_with_allow.py | new | wrapper that |
plugin/scripts/test_grep_with_allow.py | new | fixture |
plugin/conventions/<new-or-appended>.md | modify | document the marker |
plugin/skills/setup/setup_planning.py | modify | adopt the |
plugin/skills/setup/tests/run_evals.py | modify | restore |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
plugin/scripts/grep_with_allow.py -E '\.claude/worktrees/' plugin/exits zero on a tree where every literal occurrence of the forbidden token sits on a line bearing# allow-legacy-ref: .claude/worktrees/and exits nonzero on a tree that contains an un-annotated occurrence. - AC-2: A new fixture in
plugin/scripts/test_grep_with_allow.pypins the suppress / non-suppress / mismatched-token semantics. - AC-3: At least one existing path-grep AC in the plugin (the originating task’s AC-1 is the canonical case) is rewritable against the wrapper without weakening the regression it protects.
Out of scope
Section titled “Out of scope”- Generalizing the marker beyond grep (e.g. teaching the audit runner or the SKILL.md linter about it). Path-grep ACs are the observed pain point; expanding scope is a follow-up.
- Migrating every existing grep AC in the plugin to use the wrapper. This task ships the mechanism; adoption is per-task.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-G834-move-plugin-runtime-state-to-sdlc-dir on 2026-05-22.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: AC-1 grep matched legitimate comments documenting the migration as an anti-pattern (in setup_planning.py, run_evals.py) and one test constant (FORBIDDEN_CLAUDE_WORKTREES_LINE) - required rephrasing comments and assembling the test constant from string fragments. Awkward; suggests path-grep ACs ought to allow an opt-in # allow-legacy-ref: marker for prose that documents migration history without weakening the AC. Keywords searched: forbidden_claude_worktrees_line, allow-legacy-ref, setup_planning, anti-pattern, documenting, legitimate, rephrasing, assembling Excluded: 2026-05-22-move-plugin-runtime-state-to-sdlc-dir Top candidates (score / status / headline):
- 16 / closed/done / 2026-05-19-co-locate-skill-specific-scripts — Co-locate skill-specific scripts under their skill dir; promote when shared
- 15 / closed/done / 2026-05-20-pluralize-recognizes-backlog-as-plural — pluralize() should treat ‘backlog’ as already-plural
- 10 / planning/draft / 2026-05-21-promote-pluralize-to-shared-helper — Promote pluralize() + IRREGULAR_PLURALS to a shared helper
- 9 / closed/done / 2026-05-20-regen-walks-skill-co-located-scripts — regen.mjs walks
plugin/skills/
/*.py for script reference pages - 7 / closed/done / 2026-05-19-sdlc-setup-seeds-hooks-gitignore-unignore — Have /sdlc:setup seed the .claude/hooks/ un-ignore lines in .gitignore Decision: SPAWNED