T-V8K4-task-ensure-ready-fuzzy-locates-cited-paths
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.
/sdlc:task-ensure-ready validates referenced file paths only when
they appear in the ## Files to touch section. Paths cited elsewhere
in the body (Goal / Today / Acceptance criteria) slip through even
when the basename matches an existing script but the parent dir is
wrong — e.g. plugin/validators/lint_skill_prose.py vs the real
plugin/scripts/lint_skill_prose.py. The drift surfaces only at
relevance-check time during /sdlc:task-work, well after the
readiness gate has stamped readiness_verified_at:. Catching it at
ensure-ready time keeps stale paths out of open/ready tasks. Cited
by the post-mortem of T-TJB3-orchestrate-enforces-one-line-verdict.
plugin/skills/task-ensure-ready/SKILL.md Step 3 (“Evaluate the
contract”) extracts paths via a body-wide regex but only verifies
existence for paths listed under ## Files to touch. The
implementation-ready.md contract’s “File-path disqualifiers” entry
is similarly scoped to that section. A path like
plugin/validators/lint_skill_prose.py in ## Acceptance criteria
(when the real script lives at plugin/scripts/lint_skill_prose.py)
never trips the disqualifier — the basename exists, but at a
different parent.
Quote from the originating post-mortem: “The task body cited
plugin/validators/lint_skill_prose.pybut the script actually lives atplugin/scripts/lint_skill_prose.py. The relevance check caught it, but the task spec slipped through /sdlc:task-ensure-ready because path-resolution against a tight glob only checks paths under ‘Files to touch’.”
Proposed
Section titled “Proposed”Extend the readiness check to also fuzzy-locate every plugin/...
(or other project-root-rooted) path mentioned anywhere in the body.
When a cited path doesn’t exist but a file with the same basename
exists elsewhere, flag it as a definition_gap with a suggested
correction. Existing path-exists checks under ## Files to touch
remain authoritative for new-file declarations.
Approach
Section titled “Approach”- Audit
plugin/skills/task-ensure-ready/SKILL.mdStep 3 andplugin/entities/task/implementation-ready.mdfor the current path-check scope; identify the regex used and where the check gate is applied. - Add a “cited-path drift” sub-check that runs the same path regex over the WHOLE body (excluding fenced code blocks), and for each non-existent path searches for files matching the basename anywhere under the project root.
- On a basename match with parent-dir drift, record a
definition_gapthat names both the cited path and the most-likely real path so the operator can fix the body in one edit. - Add a new run_evals.py case covering the drift scenario.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/skills/task-ensure-ready/SKILL.md | modify | Extend Step 3’s path-resolution sub-check to scan the whole body (excluding fenced code blocks) for project-rooted paths and fuzzy-locate basenames when the cited path doesn’t exist. |
plugin/entities/task/implementation-ready.md | modify | Document the new “cited-path drift” disqualifier alongside the existing file-path disqualifier; tighten the contract so basename-elsewhere mismatches are surfaced at ensure-ready time. |
plugin/skills/task-ensure-ready/tests/run_evals.py | modify | Add fixture cases for both AC-1 (basename exists at different parent) and AC-2 (basename absent entirely). |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A task whose body cites
plugin/validators/lint_skill_prose.py(a basename that exists, but at a different parent) fails ensure-ready with adefinition_gapthat names the cited path and the actual location. - AC-2: A task whose body cites a non-existent path with no
matching basename anywhere in the repo fails ensure-ready with a
definition_gapnaming the missing path. - AC-3:
plugin/skills/task-ensure-ready/tests/run_evals.pycovers both cases and passes.
Out of scope
Section titled “Out of scope”- Fuzzy-matching arbitrary code symbols (the original disqualifier
for symbol drift remains as-is — that’s a
command grepcheck, not a fuzzy locator). - Auto-correcting the cited path in the task body (only flagging).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-TJB3-orchestrate-enforces-one-line-verdict on 2026-05-21.
Review feedback (from PR #87, closed for refactor)
Section titled “Review feedback (from PR #87, closed for refactor)”PR #87 implemented this task end-to-end (added
plugin/skills/task-ensure-ready/scan_cited_paths.py, extended Step 3
of the skill, widened the file-path disqualifier in
implementation-ready.md, and added seven new eval cases — 23/23
passing). The PR is being closed without merge because broader
refactoring is planned in this area; re-pick this task post-refactor.
Reviewer (sksizer) feedback during the PR:
- The only review comments were on the spawned sibling task
docs/planning/tasks/2026-05-21-run-quality-checks-continue-on-fail.md(added by this PR as a post-mortem follow-up), not on the scan_cited_paths.py implementation itself. Specifically: shouldrun_quality_checks.py --continue-on-failemit a structured data payload of all errors (not just--lineoutput)? — answered yes, the sibling task spec was updated in commit 0472966 to add AC-4 covering a--jsonmode that emits a structured array (verb name, exit code, status, captured output) so consumers (e.g./sdlc:task-workStep 7) can diff pre-existing vs branch-introduced failures programmatically. - No reviewer feedback was filed against the cited-path-scanner design,
the eval coverage, the scope of body-wide scanning, or the
fenced-code / inline-code / optional-section exemption inheritance
from
scan_placeholders.py. On re-pickup, treat the PR #87 implementation as a working reference but expect the surrounding refactor to change the integration surface (Step 3 hook point, the shell-out vs in-process boundary, and the disqualifier vocabulary).