/blueprint:story-audit
Reconcile what the codebase actually does against what the PRD says it should do, then map every story to its tests and rank the gaps. Produces one durable artifact: docs/blueprint/audits/<date>-story-audit.md.
Usage: /blueprint:story-audit [--scope <area>] [--prd <path>] [--no-write] [--report-only]
When to Use This Skill
| Use this skill when... | Use alternative when... |
|---|---|
| Auditing PRD↔code drift before a release or planning round | Drafting a brand-new PRD from scratch (/blueprint:derive-plans) |
| Finding untested critical paths through the user-story lens | Mining commits for missing tests (/blueprint:derive-tests) |
| Surfacing "implicit stories" — code-only features missing from PRD | Validating ADR relationships (/blueprint:adr-validate) |
| Producing a single artifact the team can act on top-to-bottom | Listing existing blueprint docs (/blueprint:docs-list) |
This skill is read-only apart from the audit artifact. PRD edits live in /blueprint:story-reconcile; agent dispatch for gap-fill work lives in /blueprint:work-order.
Context
- Blueprint manifest: !
find . -path '*/docs/blueprint/*' -maxdepth 3 -name 'manifest.json' - PRD directory: !
find . -path '*/docs/prds' -maxdepth 2 -type d - PRD files: !
find . -path '*/docs/prds/*' -maxdepth 3 -name '*.md' - Audits directory: !
find . -path '*/docs/blueprint/audits' -maxdepth 3 -type d - Existing audits: !
find . -path '*/docs/blueprint/audits/*' -maxdepth 4 -name '*.md' - Test directories: !
find . -maxdepth 3 -type d \( -name tests -o -name __tests__ -o -name test -o -name spec \) -not -path '*/node_modules/*' - Repo root: !
git rev-parse --show-toplevel - Today: !
date -u +%Y-%m-%d
Parameters
Parse $ARGUMENTS:
--scope <area>: Limit discovery to a single capability area (e.g.auth,image-detection). Skips areas whose entry-point paths don't match the scope. Default: full repo.--prd <path>: Override PRD auto-detection. Repeatable — pass multiple--prdflags for multi-PRD projects. Default: every*.mddirectly underdocs/prds/.--no-write: Print the audit to the conversation only; don't write todocs/blueprint/audits/.--report-only: Skip the Step 8 "What next?" prompt. Useful when running this skill from another orchestrator.
Workflow harness (template)
workflows/blueprint-story-audit.workflow.js ships beside this skill. It is a TEMPLATE to adapt,
not a script to run verbatim. Read it, then rewrite it for the work in front of you.
Adapt freely: the agent prompts, the per-PRD and per-test-root fan-out width, the discovery
globs that enumerate args.prds / args.testRoots, the tier-cutoff heuristic wording, and the
project-specific commands in the Agentic Optimizations table below.
Preserve across any adaptation: (a) the fan-out width comes from args.prds and
args.testRoots — the ## Context block's find output, or the --prd flags — never from a
prose "for each PRD"; (b) the DRIFT_STATUS, CONFIDENCE, and TIER enums in the schemas, which
force a determinate verdict per row instead of a paragraph that reads like one, and the
tierCutoff field that makes Step 4's documented cutoff non-optional; (c) the parallel() at
Step 1 is a real barrier — every downstream join is a cross-lane fact (a capability with no
story; a story with no test), so no lane's output is usable until all three have landed.
Skip the harness when: the repo has one PRD and one test directory — the modal case, which collapses to three agents total (capability + story + test) and is a linear pass where the harness is pure overhead. The steps below remain the authoritative description of what each stage must produce; the harness only fixes how the work is split.
Two constraints the template encodes because they are structure, not style:
- The capability lane is always ONE agent. You cannot partition work by a partition the work itself discovers — Agent 1's brief is literally "group by area", so the areas do not exist until it has run. Only the per-PRD and per-test-root splits are enumerable up front.
- Steps 2 and 4 stay agent stages, never JS. Step 2 mandates "verify with a quick file-level read where ambiguous" and a workflow script has no filesystem; Step 4's core/non-core cutoff is explicitly heuristic.
The template also carries this skill's own row caps unchanged — ROW_LIMIT = 200 from Step 1's
Agent 1 brief and AREA_ROW_LIMIT = 15 from the artifact template in
REFERENCE.md. They are not divided across lanes: the capability lane is a
single agent, so there is nothing to divide, and the PRD and test lanes are exhaustive extractions
("Don't infer — only extract", "List every test file") where a derived per-lane budget would
silently drop the stories and tests the audit exists to surface.
Execution
Execute this audit workflow. Each step is required unless its inputs are missing — in that case, note the missing input in the artifact and continue.
Step 1: Gather discovery inputs in parallel
Spawn three Explore subagents via the Task tool in parallel (single message, three tool calls). Each agent returns a structured findings list with file:line evidence; do not ask any agent to write the audit itself.
Agent 1 — Capability map:
Survey this codebase and list every user-facing capability. Group by area (auth, billing, search, …). For each capability emit one row:
<area> | <capability> | <entry-point file:line> | <kind>where kind isroute,cli,event-handler,component,cron, orworker. Flag dependencies that look declared-but-unused (imported library that never has its main API called). Cap output at 200 rows; if a project is larger, summarize tail areas as "+ N more in ". Read-only.
Agent 2 — Story extraction:
Read every PRD under {PRD paths from --prd or auto-detected}. Emit one row per stated user story or functional requirement:
<PRD-id> | <story-id-or-section> | <verbatim user-visible behaviour> | <linked deps if any>. Also list any "Known Drift" or status-marked entries verbatim. Don't infer — only extract. Read-only.
Agent 3 — Test inventory:
List every test file under {test directories from Context}. For each file emit:
<file> | <describe-or-suite> | <test-count> | <skipped-or-todo-count>. When a file has a top-level comment or describe block citing a story ID (PRD-NNN, FR-N.N, story-name), include it. Read-only.
Wait for all three to complete. If --scope <area> is set, filter Agent 1's rows to that area before moving on.
Step 2: Diff capabilities against stories
Build the drift report by joining Agent 1's capability map against Agent 2's story inventory. For each capability:
| Status | Meaning |
|---|---|
| ✅ implemented | Capability has a matching PRD story |
| ⚠️ partial | PRD story exists but capability is missing significant sub-behaviour the story names |
| ❌ missing | PRD story has no matching capability — feature declared but not built |
| 🆕 candidate | Capability exists but no PRD story matches — implicit story |
Match on substring overlap of capability name vs story title, then verify with a quick file-level read where ambiguous. Do not promote candidates into the PRD here — that is /blueprint:story-reconcile's job.
Also flag declared-but-unused dependencies from Agent 1's findings as ❌ missing drift entries (e.g. "tesseract listed in package.json but never imported").
Step 3: Map stories to tests
Build the coverage matrix: for every PRD story from Agent 2, find tests from Agent 3 that match by:
- Explicit story-id reference in test file/describe (highest confidence)
- File-path proximity (
auth/login.ts→auth/login.test.ts) - Keyword overlap in test description vs story title (lowest confidence, mark as
~)
Produce one row per story:
<story-id> | <linked tests> | <test-count> | <skipped/todo> | <confidence: ✓ / ~ / ✗>
Stories with zero matched tests become Tier-1 gap candidates.
Step 4: Tier-rank the gaps
Apply this default ranking. Override per-row only if the user passed explicit guidance.
| Tier | Combination | Examples |
|---|---|---|
| 1 — critical untested | core capability × zero tests | state machines, auth, payment paths |
| 2 — partial coverage | core capability × ~ confidence tests only |
UI flows tested only at the unit level |
| 3 — declared drift | ❌ missing PRD story |
OCR named in PRD, never implemented |
| 4 — implicit candidates | 🆕 candidate from Step 2 |
code-only features awaiting story promotion |
| 5 — healthy | ✅ with ✓ tests |
reference for "what good looks like" |
The tier cutoff between core and non-core is heuristic: Agent 1's kind field is the strongest signal (route and event-handler lean core; component leans non-core). Document the cutoff used at the top of the artifact so the user can override.
Step 5: Surface bugs the audit found
If Agent 3 reported test.todo / xit / skip blocks with comments that read like bug reports (rather than "not yet implemented"), collect them into a Bugs surfaced by audit section with file:line + verbatim comment. Do not auto-file issues; the user decides.
Step 6: Compose the audit artifact
Use the template at REFERENCE.md#audit-template and fill all six sections:
- Summary — counts and the headline number (e.g. "8 PRD requirements drift; 3 critical capability areas have zero tests")
- Capability map — Agent 1's output, grouped by area
- Story inventory — explicit (PRD) + candidate (code-only) lists
- Drift report — table with the four-status enum from Step 2
- Coverage matrix — story × tests with confidence column
- Tiered gap analysis — Tier 1 → 5 with one-line "why this matters" per tier
- Bugs surfaced by audit (only if Step 5 found any)
Set the artifact path to docs/blueprint/audits/<YYYY-MM-DD>-story-audit.md using the Today value from Context. If a file with that name exists, append -N (e.g. -2).
Step 7: Write the artifact and update the manifest
Skip this step if --no-write is set; print the artifact to the conversation instead.
mkdir -p docs/blueprint/audits
# Write artifact via Write tool to the path computed in Step 6.
Update the task registry in docs/blueprint/manifest.json. When the workflow harness ran, AUDIT_RESULT, STORY_COUNT, and TIER1_GAP_COUNT come from the composition agent's structured return (auditResult, storyCount, tier1GapCount) — do not recount them by hand:
jq --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg result "${AUDIT_RESULT:-success}" \
--argjson stories "${STORY_COUNT:-0}" \
--argjson gaps "${TIER1_GAP_COUNT:-0}" \
'.task_registry["story-audit"].last_completed_at = $now |
.task_registry["story-audit"].last_result = $result |
.task_registry["story-audit"].stats.runs_total = ((.task_registry["story-audit"].stats.runs_total // 0) + 1) |
.task_registry["story-audit"].stats.items_processed = $stories |
.task_registry["story-audit"].stats.tier1_gaps = $gaps' \
docs/blueprint/manifest.json > docs/blueprint/manifest.json.tmp \
&& mv docs/blueprint/manifest.json.tmp docs/blueprint/manifest.json
Where AUDIT_RESULT is "success", "{N} drift entries", or "failed: {reason}".
Step 8: Offer next actions
Skip this step if --report-only is set.
This step stays in the skill — a workflow cannot AskUserQuestion, so it has no orchestrated form. --report-only is the path an orchestrator (or the harness) takes.
Use AskUserQuestion to offer the three downstream paths the audit unlocks:
- Reconcile drift in the PRD → run
/blueprint:story-reconcileagainst this audit - Dispatch a work-order for a Tier-1 gap → recommend the user run
/blueprint:work-orderper row (a user-invocable command — surface it for the user to run, don't invoke it via the Skill tool) - I'll act on the artifact later → exit; the artifact is the durable output
Don't loop. The audit is the durable artifact; the user owns the next step.
Heuristics, templates, and edge cases
For the implicit-story detection heuristics by stack (TypeScript/Python/Go), the audit-artifact template, the tier-ranking rationale, and how the skill behaves with no PRD or no tests, see REFERENCE.md.
Agentic Optimizations
| Context | Command |
|---|---|
| Count PRD files | find docs/prds -maxdepth 1 -name '*.md' |
| Count test files (TS/JS) | find . -type f \( -name '*.test.ts' -o -name '*.test.tsx' -o -name '*.spec.ts' \) -not -path '*/node_modules/*' |
| Count test files (Python) | find . -type f -name 'test_*.py' -not -path '*/.venv/*' |
| Find skipped tests | grep -rn -E "test\.(skip|todo)|xit\(|@pytest.mark.skip" --include='*.test.*' --include='test_*.py' |
| Detect declared deps | jq -r '.dependencies // {} | keys[]' package.json (or grep '^[a-z].*=' pyproject.toml) |
| Check dep is imported | grep -rln "from <pkg>|import <pkg>|require('<pkg>')" --include='*.ts' --include='*.py' |
| Audit filename | echo "docs/blueprint/audits/$(date -u +%Y-%m-%d)-story-audit.md" |
For the audit-artifact template, implicit-story heuristics by language, and tier-ranking rationale, see REFERENCE.md.