T-XSI8-task-define-flags-spec-shell-drift
Status: closed/superseded · Impact: low · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
A task spec frequently cites shell invocations of a target skill
(“/sdlc:pr-check calls gh pr view and gh api .../comments”)
as evidence of “Today” behaviour, but the cited SKILL.md may have
moved on between when the spec was authored and when an implementer
picks it up. Surfaced during T-BM56-pr-check-mock-state-flag:
the spec described /sdlc:pr-check as making two gh calls when
the live SKILL.md had already collapsed comments and reviews into a
single gh pr view --json …,comments,reviews fetch. The drift was
benign here (the underlying intent — “swap the live gh payload
for a JSON blob” — still applied), but a tighter check at pickup
would catch the larger class of “spec describes a code shape that no
longer exists” before implementation effort is sunk.
From the originating post-mortem’s Friction list:
The task spec mentions
gh api .../commentsas a separate call the skill makes, but the live SKILL.md already collapses comments and reviews into the singlegh pr view --json …,comments,reviewsfetch. Spec was authored against a prior shape of the skill — a task-spec “still accurate?” check at pickup that diffs cited shell invocations against current SKILL.md would catch this class of drift before implementation starts.
/sdlc:task-ensure-ready today validates referenced file paths
(see T-V8K4-task-ensure-ready-fuzzy-locates-cited-paths) but
does not extract or verify shell invocation patterns the spec
attributes to other skills. A task that says “pr-check calls
gh foo bar” passes the readiness gate even when the referenced
skill never makes that call.
Proposed
Section titled “Proposed”Per the PR #88 review feedback (captured at the bottom of this file), the right shape is a resolver interface rather than a hardcoded SKILL.md grep:
/sdlc:task-ensure-readyextracts cited shell command patterns from the task body (regex-driven; covers<skill> calls \` ,``.*against the real `, and similar shapes surfaced by a quick survey of recent task specs). - For each extracted pattern, the check delegates to a resolver
that knows how to verify the cited invocation against the cited
target. Resolvers ship as small adapters: a default
SkillMarkdownResolvergreps the cited SKILL.md; consumer projects can register their own resolvers (kubectl apply→ deploy script,pnpm run X→package.json, etc.) viasdlc.yaml. - For the upstream SDLC plugin specifically, the SKILL.md-grep
resolver lives behind the project-local skill extension convention
(
plugin/conventions/project-local-skill-extension.md) so the hard-coded coupling never enters the upstream skill. The skill loads.sdlc/skill-ext/task-ensure-ready/cited-invocations.sh(or.py) as the extension point; the SDLC repo ships aSkillMarkdownResolveradapter at that path; consumer repos can ship their own. - Mismatches surface as an advisory note on the readiness verdict rather than a hard fail — the drift is often benign, but the human should know.
Approach
Section titled “Approach”- Survey: read 3-5 recent task specs and identify the actual syntactic patterns authors use to cite shell invocations of other skills. The extractor’s regex is only useful if it covers the common case.
- Define the resolver contract — input shape (cited command + cited
target file), output shape (
OK/MISMATCH: <reason>/SKIP: <reason>for unknown target types), and howsdlc.yamlregisters additional resolvers. - Ship the
SkillMarkdownResolverdefault in this repo via the project-local skill extension convention: under.sdlc/skill-ext/task-ensure-ready/(consultplugin/conventions/project-local-skill-extension.mdfor the exact event/script-name shape). - Wire the extractor + resolver invocation into
/sdlc:task-ensure-readyas a non-blocking advisory. Print anote:line under the readiness verdict pointing at the mismatched invocation and the resolver’s diagnostic. Do not downshift status. - Document the resolver contract in
plugin/entities/task/implementation-ready.mdas an advisory layer — failing it does not flip the verdict, only annotates it. - When this task is re-picked up, reconcile against
2026-05-22-task-ensure-ready-generalize-beyond-skill-md— the generalization captured there should drive the resolver contract’s shape.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/skills/task-ensure-ready/SKILL.md | modify | document the cited-invocation extractor + resolver-delegation step (non-blocking advisory). |
plugin/entities/task/implementation-ready.md | modify | note the resolver contract as an advisory layer; failing it does not flip the verdict. |
plugin/skills/task-ensure-ready/cited_invocations.py | new | extractor + resolver-dispatch helper invoked from the skill. |
.sdlc/skill-ext/task-ensure-ready/cited-invocations.sh | new | this repo’s SkillMarkdownResolver shipped via the project-local extension convention. |
plugin/conventions/sdlc-yaml.md | modify | document the resolver-registration shape under sdlc.yaml. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A task spec that cites
\gh api …/comments`against a skill whose live SKILL.md never references that string surfaces an advisory note from/sdlc:task-ensure-ready(or/sdlc:task-define) — the run still emitsREADY:` (the check is non-blocking), but the note appears in the skill’s stdout. - AC-2: A task spec whose cited invocations all match the live SKILL.md emits no advisory note. (No false positives on healthy specs.)
- AC-3: The check is documented in
plugin/entities/task/implementation-ready.mdas an advisory layer — failing it does not flip the verdict, only annotates it.
Out of scope
Section titled “Out of scope”- Auto-fixing the drift. The human author decides whether the spec or the skill is the source of truth.
- Generalizing this to non-shell drift (e.g. referenced symbol names). That’s the existing T-V8K4-task-ensure-ready-fuzzy-locates-cited-paths pattern; this task is specifically about shell-invocation lines.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-BM56-pr-check-mock-state-flag on 2026-05-21.
Review feedback (from PR #88, closed for refactor)
Section titled “Review feedback (from PR #88, closed for refactor)”Reviewer (sksizer) flagged a scope/architecture concern on the
spawned follow-up task 2026-05-21-cited-invocations-extends-to-py-scripts.md
that applies equally to this parent task:
- The cited-invocation check as designed is too SKILL.md-shaped.
Extending the regex to
*.pyis a narrow patch on a check that assumes the consumer is building Claude plugins. The SDLC plugin is meant to be a generalized orchestration framework for software (hence the name), not a tool just for making itself or other Claude plugins. - The right shape is a resolver interface carved out of
check_cited_invocations.py: shipSkillMarkdownResolveras one default, and let consumer projects register their own reference targets + verb vocabularies viasdlc.yaml(e.g.kubectl applyresolved against a deploy script,pnpm run Xresolved against apackage.json). - This means the implementation here should not just regex shell
lines and grep SKILL.md — it should define the resolver contract
first, then ship a SKILL.md-shaped resolver as the default
implementation, with
sdlc.yamlas the registration surface for consumer-specific resolvers. - A separate follow-up task
2026-05-22-task-ensure-ready-generalize-beyond-skill-mdwas drafted to capture the generalization concern. When this task is re-picked up post-refactor, reconcile against that task — the generalization is likely the actual right answer and this shell-drift check should land as a resolver, not as a hardcoded SKILL.md grep.