The ADR-0020 boundary resolver (boundary_targets()/unresolved_targets()) only ever read a SKILL.md's description. A target named in the BODY -- a dispatch table row, a "run X" step, both routine in a 900-word procedure -- was checked by nothing. Two real instances shipped before either was caught by reading rather than by a gate: bin/write-docs routed twice to a deleted `to-prd` skill, and bin/triage told an agent to run a nonexistent `/setup-matt-pocock-skills` (both fixed in 03abcff; that fix was the symptom, this gate is the actual ask per #124). Added a separate, narrower extractor -- body_targets() / unresolved_body_targets() in the shared lib-boundary-resolver.sh -- rather than reusing the description resolver at wider scope. The description gate's sentence-level heuristics (BOUNDARY_MARKER, the follower test, in-sentence corroboration) are tuned for a one-to-three-sentence routing clause and misfire on dispatch-table/procedure prose in both directions, so the body gate reads only explicit route notation (`/name`, backticked-or-slash-prefixed `-> name` / `-> name`), already the description gate's own unconditionally-blocking tier. Three guards were added after running the extractor over the real 39-skill corpus and reading every hit rather than assuming the design was correct: - a target must be hyphenated, even in notation -- single-word citations like `/fork` (forge, citing Claude Code's own /fork command) and `/name` (skill-author, a placeholder) are not routes. - a bare hyphenated word after any arrow is not notation -- only ARROW_MARKED (backticked/slash-prefixed) is used, not NOTATION_ARROW's bare form, so ordinary process-chain prose ("prop -> new ref -> re-render", caveman) is not read as a route. - a name immediately preceded by `<` is a closing tag (`</what-to-do>`, grill-with-docs), not /name notation. Wired into both consumers that must agree by contract: scripts/ skill-size-check.sh (the pre-commit hook) and factory-audit's lib-checks-skill.sh (the audit). Verified identical findings across both over the whole corpus. tests/test-adr0020-targets.sh gains a dedicated section pinning the two live true positives and all three guards. docs/spec/gates.md and ADR-0020 get a matching amendment. Fixes: #124 ADR: 0020 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
4.2 KiB
name, description, allowed-tools, metadata
| name | description | allowed-tools | metadata | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| factory-audit | Use when the user wants a skill directory or agent definition audited, including "is this ready to ship", or after hand-editing one outside its author skill. Not applying skill fixes -> skill-author. Not applying agent fixes -> agent-author. | Bash Read |
|
Gotchas
- Do not narrate PASS/FAIL per check while auditing. Gather findings internally and surface them only in the Step 4 report. Narrating each check as you go is the default failure mode here.
- A file carrying
disable-model-invocation: trueis hand-invoked — its description is never routed against, so the trigger, capability and boundary rules do not apply. Audit it as one plain human-facing sentence instead. - Vale reporting
0 filesscanned means NOT RUN, not clean. Fall back to full Step 3 judgment for every dimension it would have covered.
Step 0 — Dispatch
Resolve the flow from the target path before running anything. The two flows run different validators over different dimension vocabularies, so dispatching after Step 1 means the wrong validator has already produced the wrong findings. The rows mirror the shapes scripts/validate.sh accepts; take the first that matches.
| Target | Flow | Read |
|---|---|---|
A directory containing SKILL.md |
skill | references/skill-flow.md |
A file named SKILL.md — audit its parent directory |
skill | references/skill-flow.md |
A file named *.agent.md |
agent | references/agent-flow.md |
A .md file whose immediate parent directory is agents/ (.apm/agents, .claude/agents, .github/agents, .copilot/agents) |
agent | references/agent-flow.md |
Anything else — a missing path, a directory without SKILL.md, any other file |
none | — |
Read only the file its row matched. Each carries Steps 1 to 3 — the deterministic checks, the read, and the qualitative audit — and is self-contained. Return here for Step 4.
On the last row, stop: run no validator and tell the user the two accepted shapes — a skill directory (or its SKILL.md), or an agent file (*.agent.md, or a .md directly under an agents/ directory). Guessing a flow audits the path against the wrong spec.
The scripts re-detect the flow from the path. If validate.sh reports on the other artifact type than your row, discard what you have and restart here — the flow file, not the script, picked your rubrics, coverage line and remediation line.
Step 4 — Report
Open with the coverage line for the flow you took, naming every dimension checked.
Skill flow:
Checked: structure · description · body-discipline · patterns · file-structure · formatting · scripts · internal-consistency · provenance
Agent flow:
Checked: structure · provider-safety · description · body · delegation · comment-discipline · pair-consistency · provenance
On the agent flow at plugin/APM scope, drop pair-consistency — there is no pair to check.
Then output only the dimensions that have findings, grouped under H3 headings, FAILs before SUGGESTIONs within each. Omit clean dimensions — their absence is what confirms they passed.
Each finding:
FAIL/SUGGESTION <finding> — file:line
Why: <why this is a problem>
Fix: <exact change — quote before/after where applicable>
Close with a ## Result block holding one line: PASS, PASS (N suggestions), or FAIL (N fails · M suggestions), each optionally followed by · P info. INFO findings are observational and never change PASS/FAIL; omit · P info when there are none. Add a second line whenever there is at least one finding — Run skill-author to address findings. on the skill flow, Run agent-author to address findings. on the agent flow. Do not apply fixes — report and propose only.