Design System Contracts

How it works · question 3

What about 100 components with nested dependencies?

Say a giant product inventory dashboard: hundreds of instances, components nested in components. The model doesn’t change — it’s the same two rules from the previous pages, applied transitively. The proof below is a real 1,618-set enterprise kit, measured at site-build time.

The model, precisely

Contracts are per-component. A screen — that dashboard — is a composition of instances, and every instance resolves to exactly one contract. Nesting is the component-ref edge repeated: Dialog refs Button, Button refs Icon; each contract owns its own API and styling, and a parent can only thread declared props through. So “100 components with nested dependencies” is not a new problem class — it is a dependency graph, and graphs are what the machinery is built on: unknown refs and cycles fail the build by name, and sortByDependencies gives every consumer a deterministic, leaf-first build order.

The dependency graph of a real kit

This is not a stock illustration. At site-build time, the site reads the committed whole-kit capture — 1,618 component sets from a live enterprise kit — and renders every instance edge it finds: 80 sets draw instances of other sets (70 of them multi-variant composites), 174 distinct dependency edges over 2,718 drawn instances, nesting up to 6 levels deep (Dialog → Button-Brand Primary → Icon is the chain the previous page replays).

The dependency graph computed from the committed whole-kit capture: composites arranged by dependency depth with every instance edge drawn; edges into the Icon hub aggregated; sets with no instance edges elided, with counts stated in the legend.The dependency graph computed from the committed whole-kit capture: composites arranged by dependency depth with every instance edge drawn; edges into the Icon hub aggregated; sets with no instance edges elided, with counts stated in the legend.

The graph renders at natural size and scrolls sideways — shrinking 1,854 px of real labels to fit the column would turn evidence into decoration. Open the light SVG full-screen ↗ · dark ↗

What is elided, named: edges into Icon (in-degree 59 — drawing them makes wallpaper, so they are aggregated as a marker), and the 1,519 sets that participate in no instance edge (icon glyphs and standalone components). One drawn edge resolves to no set in the capture — _Country code → “US - United States” — because the file draws duplicate-named components and the name-keyed capture keeps one; the pipeline stubs it honestly rather than guessing, exactly the keyed-identity discipline of the previous page.

The shape is what design systems actually look like at scale: a handful of hubs — Icon (59), Avatar (9), _Helper text (8), _Input label (8), Badge Notification (7), _Error text (6), Button-Brand Primary (6), Badge (5) carry the highest in-degree — and composition concentrated in patterns: Table-Data cell (9), Navigation-Side (7), Dialog (6), Dropdown-MutliSelect (6), Input Number (6), List item (6), Dropdown (5), Navigation-Header (5) have the widest fan-out.

Deterministic build order

Given the graph, build order is not a judgment call. The schema module’s sortByDependencies orders any contract set leaf-first — children before every parent that refs them — and refuses cycles by name. Here it is, run at site-build time over this repository’s own 51 shipping contracts:

sortByDependencies over contracts/ — computed at site-build time; leaf-first, so every ref resolves when its parent generates
ds.accordion-item  ds.avatar  ds.avatar-group  ds.badge
ds.button  ds.banner  ds.blockquote  ds.breadcrumb-item
ds.breadcrumbs  ds.card  ds.chat-message-metadata  ds.chat-message
ds.chat-system-message  ds.checkbox  ds.citation  ds.code
ds.divider  ds.empty-state  ds.field  ds.heading
ds.icon-button  ds.inline  ds.kbd  ds.list-item
ds.list  ds.metadata-list-item  ds.metadata-list  ds.pagination
ds.progress-bar  ds.section  ds.side-nav-item  ds.skeleton
ds.slider  ds.spinner  ds.stack  ds.status-dot
ds.switch  ds.tab  ds.tab-list  ds.table-cell
ds.table-header-cell  ds.table-row  ds.table  ds.text-area
ds.text-field  ds.toast  ds.token  ds.toolbar
ds.top-nav-item  ds.top-nav  ds.typeahead-item

Does the whole kit actually resolve?

Counted, not claimed. The whole-kit census replays every set of that kit through the full import pipeline — propose → captured-token layer → validate → all four emitters: 1,618/1,618 sets clean, including all 76 real variant composites. And the mixed-order mega-session (ten sets, composites deliberately imported before some children, then relinked) closes with zero refs left stubbed despite their set being in scope — see the upgrade table.

Receipts: CENSUS.md (npm run extract:figma:gauntlet) — clean rate plus facts-carried, named-notes, and degradation counts per set, because refusal-free ≠ pixel-right — and extract/figma/gauntlet/live/mega-session.json.

What a contract deliberately does NOT cover

Page layout — which components a dashboard uses, where they sit, how the grid responds — is out of scope. The spec governs components: their API, anatomy, bindings, and composition edges. A screen is your product’s composition of governed instances, not a governed artifact itself. That boundary is a strength, and the A/B evaluation shows why: an agent assembling screens from governed components scored 100/100 with zero violations precisely because every piece it placed was contract-checked — while the screen itself stayed free. Governing the pieces, not the page, is what makes both trustworthy.