| name | state-audit |
| description | Audit an existing software product or design by deriving its likely state space and comparing it to what the codebase actually handles, naming the gaps where states exist in the system but have not been designed. Use whenever a user is applying state-first thinking to an existing product (rather than greenfield work), wants to identify undesigned states in a product with a history of complaints or bug reports concentrated on specific surfaces, needs evidence to make the case for state-first work to stakeholders, or is the on-ramp for a designer/engineer/PM without team authority to restructure process; the audit produces a concrete artefact and a stakeholder-ready argument. The primary entry point for existing-project work in the Stateful methodology. Requires filesystem access to the codebase being audited; cites `file:line` evidence for the gaps it claims. Do not use for new projects (use system-sentence and state-list instead) or as a substitute for the method (it is a diagnostic, not a replacement). Do not produce a "things to fix" list; the output is a description of the state-space gap, not a bug report. |
State Audit
Identifies states that exist in an existing product but do not appear to have been designed, by comparing the likely state space against what the codebase actually handles. Output cites file:line evidence for each claimed gap.
Output discipline
No preamble, no narration of the code-reading as it happens, no restating the method. Deliver the output format below plus only what needs the user's decision. Terse but complete: gap narratives stay one paragraph; evidence is a file:line citation, not a pasted code block.
After this skill produces its gap list, the standard flow continues with the state-triage skill (on the gaps) and the reentry-pass skill (on the gaps that are in-scope active states).
Procedure
-
Identify the directory to audit. Detect the directory the agent is currently operating in (the project root, typically). Show it to the user and ask:
I can audit <detected-root>. Should I audit this directory, or a subdirectory? Example subdirectories: app/auth/reset/, src/components/dashboard/. Reply with "confirm" or a path.
Wait for the user's response. The working directory for the rest of the audit is whatever they confirm. If no filesystem access is available, say so and exit.
-
Read STATEFUL.md from the working directory if it exists. Use any existing system sentence, surface description, or prior decisions as context; do not re-derive what is already there.
-
Derive a likely state space for the surface using the state-list approach. Work from first principles based on what the surface is supposed to do. Do not reference the existing code during this step; the point is to produce an independent view of what the surface should support. Anchor the derivation with the five raw-material probes from the system-sentence skill, answered from the codebase's structural evidence: schedulers, TTLs, and expiry constants (time); entity status enums and lifecycle columns (lifecycle); outbound email, push, and webhook senders (channels); session, device, and sync handling (completion differences); routes, templates, widgets, and notification code (surfaces). Reading for what the system is differs from reading for which conditions the code handles (that is step 4); the former anchors the derivation without contaminating its independence. Confirm ambiguous answers with the user. If the product has a cross-cutting inventory of recurring conditions (unauthenticated, offline, subscription expired, sync conflict, etc.), reference it while deriving rather than re-listing; note which derived states inherit from the cross-cutting inventory. Apply the optional dimensions while deriving: annotate layers (frontend, backend, data-model, infrastructure) per state, and cause (user-input, system, external, policy) per failure state. These dimensions are essential for the audit's value because they tell stakeholders which discipline picks up each gap and what kind of response surface each failure needs.
-
List the states the existing code already handles. Read whatever code constructs the surface: routes/pages/components in a web app, view controllers and view models in a mobile app, equivalent constructs elsewhere. Look for conditional rendering branches, state machines, reducers and store slices, error handlers, validation logic, loading and empty-state branches, tests, and storybook entries. Record file:line for each state found, and annotate layers and (for failures) cause from what the code reveals about each state's layer engagement and rejection source.
-
Compare the two sets. States in the derived space but missing from the code-handled set are the gaps.
-
Rank the gaps by likelihood of user encounter. A gap in a high-traffic failure or interruption state is more important than a gap in a rare surface state.
-
For the top three to five gaps, describe:
- the state,
- what the user most likely experiences today (a default component, an error page, a silent failure, a redirect) with
file:line evidence from step 4,
- the design implication of closing the gap,
- which layers would need to change to close it:
frontend, backend, data-model, infrastructure. This is the layers annotation; include it so stakeholders see at a glance which discipline picks up each gap.
- if the gap is a failure state, its
cause: user-input, system, external, policy. This tells stakeholders the source of the rejection independently of how it might render, which is essential when designing the response surface.
-
Update STATEFUL.md in the working directory. Replace the contents of the ## Audit section with the gap list and top-three. If the file does not exist, create it with at least: a ## System sentence section (derive a sentence from the audited surface, or leave blank with a TODO note), a ## Surface(s) in scope section listing the audited directory, and the ## Audit section. Stamp Last updated: <date> by state-audit. If STATEFUL.md contains a ## Graph section, regenerate it from the updated map following the state-graph skill's conventions, preserving the cut recorded in ## Decisions.
-
Ask the user whether they want a machine-readable mirror of the audit. If STATEFUL.md already records a decision on this in its ## Decisions section, respect it. Otherwise ask:
Would you also like a state-map.json mirror produced from this audit? This is an optional JSON file useful if you intend to extend the audit into a full state map, or want machine validation and downstream tooling. The methodology does not require it; STATEFUL.md is the primary artefact. Reply yes or no.
If yes, produce a state-map.json containing the derived state space (states with id, name, category, layers), and record state-map.json: yes in the ## Decisions section. If no, record state-map.json: no instead.
-
Return the full gap list plus the narrowed top-three for stakeholder conversations.
Inputs required
- Filesystem access to the directory being audited (mandatory).
- Optional: a
STATEFUL.md in the working directory (read for context; created or updated by the skill).
- Optional: a summary of known complaints, support tickets, or bug reports that concentrate on this surface.
Output format
## Derived state space
<the full four-category state list, from step 3>
## States the code already handles
<the states found in source, with file:line for each>
## Gaps
| State | Category | Layers | Cause (failures only) | Likely current behaviour (with evidence) | Design implication |
|---|---|---|---|---|---|
| <state> | <category> | fe, be | <user-input \| system \| external \| policy or blank> | <what users see today>, `<file>:<line>` | <what closing the gap requires> |
## Top gaps for stakeholder conversation
1. <state>: <one-paragraph narrative with file:line evidence>
2. <state>: <one-paragraph narrative with file:line evidence>
3. <state>: <one-paragraph narrative with file:line evidence>
Common failure modes
- Working from hearsay. If the agent has not actually read the code, the gap list is hypothesis, not evidence. The procedure requires reading; the output requires citations. Without both, the audit is not an audit.
- Deriving the state space from the screens or the code. Circular: if step 3 references what already exists, the gaps collapse. Derive step 3 independently from what the surface is supposed to do.
- Listing every gap as equally important. The point of the audit is to produce a prioritised view; unranked lists do not support the stakeholder argument.
- Framing the output as a bug report. The output describes the state space, not specific defects. The user makes the structural argument; the bug tracker handles bugs.
- Reporting absence without observed behaviour. "This state is missing" is weaker than "this state is currently rendered by the framework's default 404 page at
app/errors/default.tsx:12". The observation is what moves stakeholders.
- Scoping the audit too wide. A whole product at once produces an unmanageable list. Audit one surface, or one flow, at a time. Use the bootstrap question to narrow before starting.
Example
Input: User confirms app/medication/ as the directory to audit.
Output (abbreviated):
## Gaps (top three)
1. **Overdue dose state.** Category: active. Current behaviour: `app/medication/today/DoseRow.tsx:48` renders the dose row identically past its due time; only the relative-time text changes. Implication: the overdue condition requires its own rendering with copy, colour, and a distinct action set (take now / skip / reschedule).
2. **Dose taken late.** Category: active. Current behaviour: `app/medication/actions/markTaken.ts:22` records `now()` rather than the scheduled timestamp; late doses are indistinguishable from on-time ones in `app/medication/history/HistoryRow.tsx:31`. Implication: the data model and the history rendering both need the distinction.
3. **Medication paused by provider.** Category: interruption. Current behaviour: no design exists; `app/medication/schedule/computeNext.ts:14` treats paused medications as if discontinued, suppressing them from the schedule without surfacing the pause. Implication: the schedule state must support a paused-not-discontinued condition.
The full audit would list additional gaps across all four categories. The top three are the wedge for the stakeholder conversation.