T-JL2Q-scope-skill-docs-gate-to-staged
State: open/ready · Impact: medium · Complexity: small
AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-09-13 at the direct request of the spawning flow. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.
Pre-commit’s .claude/skills/project-check/check_skill_docs.ts renders
every mermaid block through a headless browser on every commit,
regardless of what is staged, adding 4 to 12 minutes to each commit.
Scope the gate to only the skill docs actually staged in the commit.
Pre-commit’s .claude/skills/project-check/check_skill_docs.ts renders every mermaid block through a headless browser on every commit regardless of what is staged, adding 4 to 12 minutes per commit. Scope the gate to only the skill docs actually staged in the commit.
— from T-4VNC-learning-p1-scaffold-solution’s post-mortem
| Location | Role today |
|---|---|
.claude/skills/project-check/check_skill_docs.ts | Walks every solutions/ontological/skills/<slug>/SKILL.md unconditionally and, for each one, renders its companion docs/skills/<slug>.md’s mermaid blocks through mmdc and checks doc-coverage — no notion of which files are staged. |
lefthook.yml | The pre-commit.commands.project-check-skill-docs job invokes the checker with no glob: filter and no {staged_files} argument, so it always runs and always processes every skill on every commit, regardless of what that commit touches. |
scripts/guard-control-chars.ts | A sibling pre-commit gate already scoped to staged files: it takes bare positional file-path args (fed {staged_files} by lefthook) and falls back to scanning every tracked file only when invoked with none — the convention this task mirrors. |
.claude/skills/project-check/tests/check_skill_docs.test.ts | Shells check_skill_docs.ts against fixtures under --skills-dir/--docs-dir; no existing case exercises a staged-file scoping argument. |
Proposed
Section titled “Proposed”Give check_skill_docs.ts an optional list of staged file paths — the
same {staged_files} lefthook already feeds guard-control-chars.ts —
and use it to narrow the skill walk to only the slugs those paths
implicate (a staged SKILL.md under solutions/ontological/skills/ or a staged
companion doc under docs/skills/). No paths given (a bare/manual/CI
run) keeps today’s full-repo scan. Wire lefthook.yml’s
project-check-skill-docs job to pass {staged_files} and add a
glob: so the job — and its mmdc resolution — never fires at all on a
commit that touches neither a skill’s SKILL.md nor its companion doc.
Approach
Section titled “Approach”- In
.claude/skills/project-check/check_skill_docs.ts#parseArgs, collect any non-flag argv entries into astagedFiles: string[]onParsedArgs(default[]) instead of throwingArgErroron an unrecognized bare argument. - Add a helper, e.g.
slugsFromStagedFiles(stagedFiles, skillsDir, docsDir): Set<string> | null, resolving each staged path and returning the slug when it falls under<skillsDir>/<slug>/SKILL.mdor<docsDir>/<slug>.md. ReturnnullwhenstagedFilesis empty (meaning “no scoping requested” — preserves today’s full scan for a bare/manual/CI invocation), and an emptySetwhen paths were given but none matched a skill doc. - In
main, afterfindSkillFiles(skillsDir)computes the full list, compute the scoping set and, when it is non-null, filter the skill list down to the matched slugs before resolvingmmdc— so a commit whose staged-file list matches zero skill docs exits0immediately (printing the existing0 skill(s) checked, no skill-doc drift.summary) without ever probing formmdconPATH. - Update the top-of-file doc comment’s
Options:block with a shortUSAGEnote documenting the new positional usage, mirroringscripts/guard-control-chars.ts’s two-lineUSAGEconvention (bare invocation vs. staged-file-scoped invocation). - In
lefthook.yml’sproject-check-skill-docsjob, addglob: ['solutions/ontological/skills/**/SKILL.md', 'docs/skills/**/*.md']and append{staged_files}to bothbun runinvocations (themmdc-present branch and the--skip-mermaidfallback branch). - Add regression cases to
.claude/skills/project-check/tests/check_skill_docs.test.ts: one staging only one fixture skill’sSKILL.mdamong several fixtures and asserting the run’s stdout reports only that skill’s slug; one passing a staged-file list that touches none of the fixture skills and asserting exit0, a0 skill(s) checkedsummary, and (by passing a deliberately-bogus--mmdcpath) thatmmdcresolution was never attempted.
| Area | Note |
|---|---|
.claude/skills/project-check/check_skill_docs.ts | Accept trailing staged-file-path args, add the slug-scoping helper, filter findSkillFiles’s output by it, skip mmdc resolution when the scoped set is empty, and update the USAGE/Options: doc comment. |
.claude/skills/project-check/tests/check_skill_docs.test.ts | Add the two staged-scoping regression cases described in Approach. |
lefthook.yml | Add glob: to project-check-skill-docs and pass {staged_files} to both bun run check_skill_docs.ts invocations. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
bun run .claude/skills/project-check/check_skill_docs.tswith no positional file arguments still checks every skill undersolutions/ontological/skills/— the full-scan behavior for a manual or CI run is unchanged. - AC-2:
bun run .claude/skills/project-check/check_skill_docs.ts <staged-file-paths...>limits itsOK/FAILoutput to only the skills whoseSKILL.mdor companiondocs/skills/<slug>.mdappears among the given paths; skills not implicated by any given path are neither rendered throughmmdcnor reported. - AC-3: Given a staged-file-paths list that touches no skill doc, the
checker exits
0immediately, prints a0 skill(s) checked, no skill-doc drift.summary, and never resolves or shells out tommdc. - AC-4:
lefthook.yml’sproject-check-skill-docsjob passes{staged_files}tocheck_skill_docs.tsand carries aglob:restricting it tosolutions/ontological/skills/**/SKILL.mdanddocs/skills/**/*.md, so a commit touching neither never invokes the job at all. - AC-5: Running
bun testagainst.claude/skills/project-check/tests/check_skill_docs.test.tspasses, including the new cases covering AC-2 and AC-3.
Out of scope
Section titled “Out of scope”- Changing the mermaid-parse or doc-coverage check logic itself
(
skill_md_harness.ts/skillDocRule) — this task scopes which skills the checker walks, not what each per-skill check does. - Speeding up
mmdcitself or replacing the headless-browser render with a faster mermaid validator. - Scoping any other
project-check-*pre-commit job (e.g.project-check-site-build,bun ... docs generate --check --staged) — this task is only aboutproject-check-skill-docs/check_skill_docs.ts. - Detecting an indirect change that should invalidate a skill’s doc
without a file under
solutions/ontological/skills/ordocs/skills/being staged (e.g. a shared partial the doc transcludes) — the gate scopes by staged-path membership, not by semantic dependency tracking.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-09-13 UTC from T-4VNC-learning-p1-scaffold-solution in git@github.com:sksizer/dev.git.