verify-design-structure
Checks that the components a design board names actually appear at that board's route in the running build. Walks React's fiber tree in Playwright, collects each rendered component's name, and compare
SKILL.mdpackages/skills/verify-design-structure/SKILL.md
GitHubverify-design-structure
When it applies
A design made by /create-design has real-component boards: boards in design-map.json
whose components list names the product's own components. This check answers "are those
components rendered at the board's route," not "does it look right" (that is
verify-design-comparison) and not "does the journey work" (verify-flow-as-built). It works
on React and react-native-web; a Vue, Svelte, Angular, Flutter or native build is "not
verifiable here" (Rubric).
It is never silent. A design with only parts boards, or one built on a stack other than React or react-native-web, still gets its rows (Criteria), each reported "not verifiable here" with the reason. Skipping the walk is correct for those boards (AC-F12.5); leaving them out of the report is not, because an absent row reads the same as a check that never ran.
Inputs
| Input | Where it usually comes from | Required / optional | Default |
|---|---|---|---|
| Design map | docs/ui/<slug>/design-map.json |
required | — |
| Boards in scope | boards whose status is approved, building or shipped, real-component boards (a non-empty components list) and parts boards (an empty one) alike |
required | — |
| Build stack | the UI stack the build renders with (.claude/rules/stack.md, or the board's platform): React, react-native-web, or something else |
required | — |
| Route per board | the board's route in design-map.json |
required | — |
| Capture method and commands | how to open the route in a browser against the running build, with the exact command; a development build is preferred, since a production build minifies names | required | — |
| Namespace prefix | the prefix /create-design put on component names (Ns.Name), stripped before comparing |
optional | everything up to and including the first . |
Criteria
One row per board in scope, never per component. Which row a board gets:
- A real board (a non-empty
componentslist) on React or react-native-web: the row in the table below, walked per Capture. - A parts board (an empty
componentslist): rowST-<board id>, statement "Board<board id>is a parts board: the structure check does not run", Tier 1locator. It is not walked; the exerciser claims it withartifact: nulland the reason "parts board: no components to walk; verify-design-comparison carries the weight", and the Judge resolves itnot_verifiable(AC-F12.5). - Any board on a stack other than React or react-native-web: its
ST-<board id>row is not walked; claimed withartifact: nulland the reason "stack is<stack>, not React or react-native-web", and resolvednot_verifiable. - No board in scope (for example every board is still
draft): one row,ST-<design slug>, statement "Design<design slug>has no board the structure check can walk", claimed withartifact: nulland a reason naming why (no boardapproved,buildingorshipped; and the stack, when it is not React or react-native-web), resolvednot_verifiable. The check is never silent: a selected skill always leaves at least one row.
| Column | Value |
|---|---|
| ID | ST-<board id> (stable across runs, so a resumed run keeps its verdict) |
| Functional statement | "Route <route> renders the components board <board id> names" |
| Cites | design-map.json and the board id |
| Evidence that would prove it | the fiber-walk transcript for the route and a screenshot of the route, per Capture |
| Derivation | check:verify-design-structure |
| Tier 1 | locator — a component name copied verbatim from the walk transcript |
| Parts | blank |
Capture
For each board in the slice (never narrow to a subset of your own slice). A parts board, a
board on a stack other than React or react-native-web, and the ST-<design slug> row are not
walked: claim each with artifact: null and the reason Criteria gives, and skip the steps
below for it.
- Open the route in Playwright against the running build, using the capture command given. Playwright resolves from the product first, then the global install; if neither is found, report that and stop (Rubric).
- Walk the fiber tree. From the page's DOM, find host nodes carrying a
__reactFiber$*key, follow each fiber up through its parents, and collect each component'sdisplayNameor function name. Write the sorted, de-duplicated names to the transcript. - Compare with the board's
componentsafter removing the namespace prefix from each. List each board component as found or missing, and note how many collected names are one or two characters long. - Write the transcript as text to
<evidenceDir>/verify-design-structure/<board id>.txtand take a screenshot of the route to<evidenceDir>/verify-design-structure/<board id>.png(the contract's screenshot rule for any criterion that names a screen). - Claim it with a locator copied verbatim from the transcript: a component name the
transcript contains. A route that cannot be reached is claimed with
artifact: nulland a stated reason. - Any script this step needs is written at run time under
<evidenceDir>/verify-design-structure/scratch/, never into the source tree. This skill ships no such script.
Capture only: no source edits, rebuilds or restarts. A repair belongs to Debug, after the Judge. Never spawn a copy of yourself (constitution: same-type self-delegation is forbidden); a slice too large for one instance is reported, not delegated around.
Rubric
met— every component the board names was found at the route.not_met— naming each missing component; handed to Debug as a gap.not_metwith reasonnot built: <route>— the route does not exist in the build.not_verifiable("not verifiable here") — any of: the board is a parts board (an emptycomponentslist; the design comparison carries the weight); no board is in scope (theST-<design slug>row); the stack is not React or react-native-web; no__reactFiber$*key is present on host nodes; Playwright is not installed; the names are minified (no board component found and most collected names one or two characters long), in which case the reason names minification and not a missing component; or the environment is not oneverification.mdauthorises.
Write one verdicts.json entry per board judged this run (page status, one-sentence verdict,
notes); entries for boards not judged this run are kept.
Page
Written to <pagesDir>/verify-design-structure/index.html: light and dark, responsive at phone
width. One card per row, labelled with its criterion ID (ST-<board id>, or ST-<design slug>),
showing the route, a found/missing table for the board's components, and the screenshot. Rows
judged not_verifiable (parts boards, a non-React stack) show the reason in place of the table. A line under the title states the iteration and whether the
loop is still running or has exited, and with which outcome.
Safety
Only environments .claude/rules/verification.md authorises; an unlisted environment resolves
not_verifiable, never a guessed endpoint. Read-only: opening a route is the whole exercise.
Never write a credential value into the transcript, verdicts.json, the page or any return;
record where a credential lives, never its value. Do not spawn a copy of yourself.