Agent docs

Guidebook

Bringing an app onto the kit, new or already built: the layers, the order of work, the pin rules, how a correction flows back, and the retrospective on speedway and walmart.

For an agent or a person bringing an app onto the kit, whether the app already exists or has not been started. It gives you the order of work that keeps a build or a migration from debugging its own seams, the pin and correction mechanics that decide whether a rule you are reading reaches the app you are in, and the retrospective on the two apps that did this first: what went in, what lapsed, and what would have caught each lapse sooner. The procedures themselves live in the install page, the app patterns and the contract docs; this file points at them where they exist.

Audience: an agent (or person) bringing an app onto the kit, migrating or new.

1. The four layers, and which one answers you#

The layer map is owned by docs/index.md (what each layer can do for you and where truth lives for a component) and the ruled-against list by docs/DO-NOTS.md. This guidebook does not carry a copy; a fifth copy is how the copies drifted. One sentence survives because a migrator needs it before anything else: existence is settled by the barrel export (packages/ui/src/index.ts), never by intent or a plan doc.

2. Starting fresh, or bringing one over#

Two doors into the kit, and both procedures are already written down in full: docs/app-patterns/05-starting-a-new-app.md for an app that does not exist yet, docs/app-patterns/04-migrating-an-app.md for one that already works. Read whichever door applies before writing a line. What this section adds is what a procedure cannot state for itself: which door you are actually in, and the traps that show up regardless of it.

Which door is decided by one question, not preference: does the app have behaviour a user would notice losing? If yes, you are migrating, and the migration guide's step zero is not optional, a parity ledger written before the first replacement (docs/app-patterns/04-migrating-an-app.md:16). If no, you are starting fresh, and you are exempt from that entire cost (docs/app-patterns/05-starting-a-new-app.md:21-23).

Both doors share the same build order, and the same reason for it: shell first, then page composition, then loading and empty and error states, then the real screens, because a page built inside an unsettled shell inherits two conflicting layout owners and you debug the seam instead of the page (docs/app-patterns/04-migrating-an-app.md:100-116, docs/app-patterns/05-starting-a-new-app.md:62-65).

Two traps neither doc can warn you about until you hit them. A local component sharing a kit export's name makes every call site ambiguous until it is renamed, and it is cheaper to write a second implementation than to find the first one already shadowing yours, which is exactly why the migration guide's step one exists (docs/app-patterns/04-migrating-an-app.md:57, :64-66). And a kit export existing is not evidence it is the proven path: FilterBar is complete, shipped, and used by nobody, because both existing apps built their own toolbars instead (docs/app-patterns/04-migrating-an-app.md:126-129). Check packages/ui/docs/ for shipped usage before adopting a component on the strength of it being in the barrel alone.

3. Reading order for an agent starting cold#

The governing copy of the cold-start reading order is AGENTS.md; read it there, not here (four copies of this list existed and no two agreed). The one stop the list cannot carry: after the reading, the awareness prompt on the showcase page you are about to touch names that surface's own source and contract doc (apps/playground/src/app/showcase-registry.ts:556), and it is the fastest ground truth once you know where you are going.

4. Pins, and the upgrade you have to choose to take#

The kit publishes on the owner's bump, never as a ride-along on an unrelated commit, and an app does not receive that bump automatically (CLAUDE.md:39-41, :94-97). Both consumer apps stay unchanged until their own deliberate upgrade; that is the union rule, the kit accumulating the superset while apps hold their pin until they choose to move it (docs/SCRIPTURE.md:93-96).

Where the pins stand and why they stay there, as of 2026-08-17: speedway pins ^0.0.14, walmart ^0.0.24, the kit is published at 0.2.0. Nothing built in the week of 2026-08-10 runs in a shipping app yet. That is a decision, not a lapse; the owner's ruling, verbatim: "I'm not updating speedway and walmart right now because it serves us no biz value right now until there's actual customer facing work to be done." The upgrade rides the next customer-facing piece of work in each app, and section 6 below is what that upgrade costs. The procedure itself, from pin to pin, is packages/ui/README.md, "Upgrading an app's pin", and packages/ui/CHANGELOG.md says per release what changes on existing screens and what an app can delete once it takes it.

The pin is the part that is easy to get wrong silently. Under npm semver, a caret on a 0.0.x version is a patch pin, so ^0.0.14 resolves to exactly 0.0.14, not to whatever the kit has shipped since (docs/design-language/00-overview.md:83, docs/app-patterns/05-starting-a-new-app.md:31-33). A canon rule written "as of kit 0.0.N" is unreachable in an app pinned below N regardless of what the rule says. Check the app's lockfile against packages/ui/package.json before relying on a prop, not after it fails silently at runtime.

What "deliberate" costs in practice, from a recent example: sidebar groups became collapsible by default on 2026-08-16, so an app that upgrades past 0.2.0 sees carets on every labelled group unless it opts out with collapsible: false (packages/ui/docs/app-shell.md:23). A version bump is not free even when nothing in your own code changed; read the contract doc for anything you use before taking the bump, not after.

5. How a correction becomes law#

A defect caught on a shipping screen is not fixed once, in place, and left for the next person to rediscover the same way. It has a path into something reusable, and the path is consistent enough now to name.

The worked example three docs already point at independently: a page shipped a second theme toggle while the navbar already carried one, and the owner named it an anti-pattern. The fix did not stop at removing the toggle. It became a general rule in the AppShell contract doc's Banned combinations, "do not mount a second toast stack, modal host, or file-preview host per shell instance" (packages/ui/docs/app-shell.md:54), and that doc's "Before you adopt this" checklist now opens by naming the case directly (packages/ui/docs/app-shell.md:60). docs/DO-NOTS.md picked both up automatically the next time it was regenerated, because it reads every contract doc's Banned section by construction (docs/DO-NOTS.md:22-26). And docs/app-patterns/13-when-a-solution-is-unsuitable.md generalised the same case into its first tell, something that only fits without a build because a parent already renders it (docs/app-patterns/13-when-a-solution-is-unsuitable.md:24-28).

The same lens also reads the canon directly, not only contract docs: any sentence in the twelve design-language docs containing "never," "do not," "must not," "is a defect," or "banned" is picked up under docs/DO-NOTS.md's "By canon doc" section without anyone filing it a second time, for example "Mono is for identifiers... never decoration" (docs/design-language/01-foundations.md:28, surfaced at docs/DO-NOTS.md:230).

The two routes in, then: write the fix at its smallest true scope, a component's Banned combinations section if it is one component's mistake, a canon trait doc's own principle if it crosses components. Then regenerate the lens, node scripts/build-do-nots.mjs (CLAUDE.md:37-38). Skipping that step is the specific failure the scripture already names for the general case: a rule nothing reads is not a rule (docs/SCRIPTURE.md:399-400).

6. Validating a change#

Two typechecks and a real browser, at minimum, before any UI change is done. Kit: pnpm typecheck and pnpm vitest run in packages/ui. Playground: pnpm exec tsc --noEmit in apps/playground (both through fnm, AGENTS.md rule 1). CI additionally runs pnpm lint:tokens, pnpm -r test, the citation ratchet and the do-nots regeneration on every push (.github/workflows/ci.yml), so a change that skips them locally reddens main. Then the page itself, in both themes, dark being the literal theme name versable-dark (CLAUDE.md:14-19). This wave's own landing build additionally gated at a 375px phone width alongside 1280px desktop, with reduced motion emulated separately (docs/plan/58-w2-1-landing-design.md:146-147); carry that habit into any surface with real layout risk, not only the pages built under it.

Which review pass or skill fires for which kind of change is docs/app-patterns/14-validating-a-ui-change.md: the categorical pass, the adversary, the routing table, and, from the retrospective below, which checks caught what and in which order. The two typechecks and the browser above are the floor; that doc is the rest.

7. The retrospective: what went into speedway and walmart#

The owner asked for this half in the words "what went into speedway and walmart, the lapses, when each was noticed, what would have caught it sooner", and then ruled that no interview would feed it (doc 57 D8c): the material is gathered by agents from the record and checked by a second agent, with the owner's own review optional at the end. So everything below is cited or it is not here. The strata, in the order they were trusted: the three commit histories since 2026-06-20 (dated, attributable), the atone ledger of recorded mistakes with each event's precheck (the question that would have caught it), the sessions' own runtime notes, 235 owner messages that carry lapse-signal phrasing (quoted only verbatim, with their timestamp), and the plan docs. A machine digest of seventeen docs was used as a checklist and re-derived; five of its twenty-four candidates could not be grounded and are absent. A separate adversarial vet then checked every citation mechanically, trimmed thirteen lapse rows of a citation that did not hold, merged two timeline rows, and corrected four rows that had claimed a remedy postdated the lapse it would have caught when the remedy predated it (the run's most common draft defect, and it flattered the record in one direction). What the vet could not check is listed at the end of this section.

7.1 The timeline#

DateAppWhat happenedKindEvidence
2026-07-06SharedOwner scopes the kit as a "repo forge": the reskin's engineering cost is justified by getting a reusable system the next sweep builds on and the current MVPs draw back fromPlanowner-signal ts 2026-07-06T23:13:43.518Z (hits 6)
2026-07-07SharedMonorepo bootstrapped and packages/toolkit ported the same day; the kit's own first wave hand-copies from the toolkit instead of importing itPlan/Lapseversable-builder@bab3536, @d5427d4, @cb1e557; docs/plan/43-toolkit-rca.md:27
2026-07-13SpeedwayFirst full owner review, 30 hits: the workspace selector loads as a separate page before the app shell, and highlighting a sidebar row underlines all of its textLapseowner-signal ts 2026-07-13T07:23:19.609Z (hits 30)
2026-07-16Speedwaydoc-22 surgery: R2 writes the jobs and parts pages fresh instead of porting the products surfaces; R4 purges the newly orphaned components as dead by import graphShip/Lapsespeedway@a1a62a3 (R2), @fe2656d (R4); atone mist-20260716-074938-54
2026-07-16SpeedwayOwner opens the restored UI and finds it does not look restored; the restoration had been verified against its own rebuild, never against the mockLapseatone mist-20260716-112917-31; .claude/skills/runtime-notes.md:266, session "UI-regression recovery + ipc forensics [catch-ipc-9e]"
2026-07-17SpeedwayOwner feedback batch captured verbatim and chunked into doc 25 under an explicit per-chunk review gate; the F1 finalization plan (owner directive 2026-07-18) then orders function before cosmeticsLapse/Plandocs/plan/25-ui-feedback-chunks.md:5, :34, :40
2026-07-18SpeedwayTaxonomy and Attributes viewers ship without the DataTable pagination model every sibling list uses; TypePeekPanel is hand-rolled instead of reusing the sidebar peek-panel family, twice the same dayLapseatone mist-20260718-101437-d7, mist-20260718-204614-20
2026-07-20SharedArchive sweep files the toolkit's design doc among 25 "shipped" plan docs without checking that doc's own canary rule, the one criterion of its four that was unmetLapseversable-builder@86b4d12; docs/plan/43-toolkit-rca.md:29
2026-07-23 to 07-24SpeedwayDesign mocks never consulted: the doc-32 program ships legacy module labels instead of the mock's; WorkflowStageChain ships as a card grid instead of the mock's ruled banner and stepperLapseatone mist-20260723-140712-be, mist-20260724-141200-12
2026-07-27Speedway/bloop is invoked by name for three UI items; its mandatory adversarial gate is skipped for all three, and they are reported and board-marked done anywayLapseatone mist-20260727-223728-20
2026-07-28SpeedwaySetupHoldBanner ships with an em dash and default card padding, unrendered; the same-session remediation then deletes the title instead of rewriting it and reports it fixed with no renderLapse/Correctionatone mist-20260728-180931-99, mist-20260728-182222-d6
2026-08-07WalmartRelease round, three lapses in one day: production runs Mona Sans and Red Hat Mono against the canon's Inter and JetBrains Mono with no favicon and "Loading…" text in about 15 files; the auth-boot skeleton draws bars over statically known chrome, contradicting the canon doc read that same session; the route-boot fallback renders the dashboard skeleton for every unmapped route including /importLapseatone mist-20260807-111459-c5, mist-20260807-115856-c7, mist-20260807-142844-a2; fix walmart-mvp@41e1b0f
2026-08-09SpeedwayProduct development frozen for stabilization; from here speedway gets UI and kit work only, no product behaviour changesShipCLAUDE.md "Speedway is frozen for product work"; corroborated docs/plan/46-speedway-conventions-sweep.md:5
2026-08-12 to 08-13WalmartRelease handover doc assembled: four coexisting Select implementations, six local components shadowing kit export names, two search boxes on the Jobs pageLapsewalmart-mvp/docs/04-technical-debt.md:67, :75, :105
2026-08-13SharedToolkit RCA (doc 43, task #107) roots the zero-consumer finding: about 82% of the pluralize-shaped duplication the toolkit exists to prevent was written after it already existedCorrectiondocs/plan/43-toolkit-rca.md:31; versable-builder@d213014
2026-08-13 to 08-14SharedSpeedway conventions sweep (doc 46, task #91) finds the app-wide chip-suppression violation: every facet trigger renders count-only, activeChips is computed and never mapped to JSXLapsedocs/plan/46-speedway-conventions-sweep.md:33
2026-08-14SharedFacetBar, the union of both apps' toolbars, ships without walmart's own documented design reasoning; owner calls out the toolbar coherence on sight, fixed the same dayLapse/Correctionatone mist-20260813-192114-c8; fix versable-builder@f5cf96b
2026-08-15SharedFull adversarial usability audit of the kit (doc 50): 19 contract-doc blockers, a reverted button-contrast fix, three unreturned-focus blockers, a registry 401 with no token guidance in the READMELapsedocs/plan/50-usability-audit-report.md:71, :83, :135
2026-08-16SharedKit 0.2.0 published, and the generated do-nots lens lands the same day; the citation checker had landed two days earlierCorrectionversable-builder@27d3616 (08-16), @4caf897 (08-16), @27a10f1 (08-14)
2026-08-17SharedAn opus adversarial pass on the landing page catches what the author's own categorical pass had passed: the strip grid overflowing by 95px at a 375px viewport, a class that beat the Button's own colour rule, an inline animation delay the reduced-motion guard cannot reach, and five small-text inks under AA in lightCorrection.claude/skills/runtime-notes.md:7 (session "review round 1 wave 2b … [catch-fable-7c] · 2026-08-17"); docs/app-patterns/14-validating-a-ui-change.md:77

7.2 The lapses#

#WhatAppHow it was noticedThe fixRecorded inWhat would have caught it sooner
1The toolkit's own spec gated "stable" on a real consumer (the canary rule); the 2026-07-20 archive sweep filed it as shipped with that criterion unmet, and the only doc carrying the consumption requirement left the live planning surfaceSharedaudit/RCA, task #107RCA root-caused it; tasks #107 and #108 track promotion into the kitdocs/plan/43-toolkit-rca.md:13, :29, :32The archive sweep read each doc's status but never that doc's own definition of done. No check for this existed then and none exists now; the RCA is the first artifact that reads a spec's exit criteria back against its archive state
2R2 rebuilt the jobs and parts pages fresh instead of porting the products surfaces; R4, in the same round, purged the newly orphaned components (ProductPeekPanel, ProductPreviewModal, ProductsToolbar, FilePreview drill) as dead by import graphSpeedwayowner (sidebar, built-up table, empty states, chip behavior gone)git-history parity audit, restore and rewire onto job-scoped dataatone mist-20260716-074938-54Recorded precheck: was the component dead BEFORE the rebuild or orphaned BY it (git log its importers)? The instrument now exists: ~/.claude/rules/invariant-graduation.md and its "UI surface purge gate" were graduated directly from this incident, citing doc-22 and versable-builder@3669c11
3The restoration from row 2 was verified by re-exercising the restoration itself; the design mock ran untouched on pm2 and the reference worktree was never servedSpeedwayowner (jobs and review pages "do not look restored")mock adopted as the visual gate; see diff and /vis-compare run per pageatone mist-20260716-112917-31The instrument already existed and was not reached for: /vis-compare was added 2026-07-11, five days before this, and the atone records that it and see-diff "were never invoked". Recorded precheck: did I render BOTH the reference and my result and compare them visually?
4Taxonomy (2,452 rows) and Attributes viewers shipped rendering their full row set with the plain kit Table while every sibling list page paginates via the DataTable modelSpeedwayowner (page slowdown on the deployed preview, repeat feedback)both viewers converted to the paginated DataTable model in the same owner batchatone mist-20260718-101437-d7Recorded precheck: does the nearest sibling list page paginate? If yes and the new one does not, the model goes in before the commit. The sibling sweep was run for loader, PageTitle and nav, and skipped for the table specifically
5TypePeekPanel hand-rolled a fresh attribute list and a copied footer escape link instead of auditing the sidebar family (ProductPeekPanel, ActivityRail) and reusing the attributes page's existing tableSpeedwayowner ("one global sidebar shell")shared PeekPanel wrapper extracted and consumed by every sidebar; AttributeSchemaView extracted and sharedatone mist-20260718-204614-20Recorded precheck: rg the surface family and diff its shells before adding a new member. The morning's same-slug atone (row 4) existed by then and its lesson had been generalized too narrowly, to tables and pagination rather than to all surface families
6The doc-32 program shipped legacy module labels and a post-create scrape-setup surface; the owner's mocks, never requested or read across the whole engagement, specify different labels and sites-at-creationSpeedwayself-caughtsame-hour relabel to the mock's names with nav reading one map; create modal gained per-module setupatone mist-20260723-140712-beRecorded precheck: does a design mock or spec exist for this surface, and has it been read? The instrument now exists as the standing [design-mocks] rule in ~/.claude/rules/testing.md, which mandates grepping for mocks before any user-facing UI work
7WorkflowStageChain shipped as a card grid extracted from the existing StageRail instead of the mock's ruled banner, stepper and enumerated stage list, and was verified only by text presenceSpeedwayself-caught (re-opening the mock at build time)rebuilt to the mock's structure with screenshot-versus-mock comparisonatone mist-20260724-141200-12Recorded precheck: is the mock's markup for this exact view open right now, and does a screenshot show the same layout primitives? Same-session family repeat of row 6, which means the [design-mocks] rule was the instrument and the gap was reaching for it at build time rather than at plan time
8SetupHoldBanner shipped to production with an em dash, a two-sentence explainer, and default card padding the owner has repeatedly called too large, deployed without rendering itSpeedwayownercopy rewritten and padding tightened; view and setup affordances separatedatone mist-20260728-180931-99The instrument already existed and was skipped: /ui-categorical-check was added 2026-07-16, twelve days before this, and the atone records skipping "the one skill built from this owner's own feedback history". It is now named as a required pass in docs/app-patterns/14-validating-a-ui-change.md
9The same-session remediation of row 8 deleted the bold title instead of rewriting its wording, changed padding on the inner div while the kit Card's own card-body padding stayed untouched, and was reported "fixed and live" with no render performedSpeedwayself-caughtread the Card padding contract, restored a short plain title, set padding on the owning element, screenshotted before reportingatone mist-20260728-182222-d6Recorded precheck: do I have a screenshot of the changed element from this turn, and did I open the component that owns its padding? The atone notes an earlier atone that same session whose entire lesson was to render UI before claiming
10Walmart shipped to production running Mona Sans and Red Hat Mono against the canon's Inter and JetBrains Mono, with no favicon or page titles, "Loading…" text in about 15 files, and a hand-rolled brand lockupWalmartowner's morning reviewfont token overrides deleted so the kit wins, speedway's logo lockup, AuthCard, favicon and titleFor() ported, three seats dispatched for the mono, em-dash and skeleton purgeatone mist-20260807-111459-c5; fix walmart-mvp@41e1b0fRecorded precheck: DOM-inspect computed font-family and weight on body, heading and button in BOTH apps before the word parity is used. Parity had been scoped to the mock-parity ledger's enumerated features, and typography, loading language and brand were never ledger rows. Since 2026-08-19 the favicon, page titles, 404, error boundary, theme boot and build-info half of this row is a runnable check: npm run doctor (apps/_templates/next/scripts/app-doctor.mjs), carried by the app template and app-forge-v6
11Walmart's auth-boot fallback drew skeleton bars over statically known chrome (sidebar labels, brand, page title), contradicting the loading-and-states canon doc read the same session; the org-switcher new-org modal was restyled without ever being openedWalmartself-caughtauth-boot rebuilt to render real chrome instantly with skeletons only on data slots; the org modal opened and fixed in the browseratone mist-20260807-115856-c7Recorded precheck: is this element's content known at build time (then render it as itself), and did I open every modal and dropdown the diff touched? The canon doc carrying the static-content exception was demonstrably in context and its exception was not applied
12Walmart's routeBootSkeleton fallback returned HomeSkeleton for every unmapped route, so booting into /import, a primary nav destination, rendered the dashboard's loading layout; verified only by booting into /Walmartself-caughtper-route skeleton for Import, neutral title-and-card bone for unmapped routes, / alone mapped to HomeSkeletonatone mist-20260807-142844-a2Recorded precheck: does the fallback ever show one page's layout on another page, and did I boot-test every primary nav route? The wrong-page fallback was consciously accepted as good enough for routes judged rarely hit
13The kit-canon-tree proposal stated packages/ui/docs held 8 per-component docs and enumerated 8 filenames; it held 15, and the count was load-bearing for the doc's central argument that both candidate homes are already fullSharedpeer session review (vb-fable), which checked four claims and found this the only failurecorrected to 15 with the full filename list and a provenance noteatone mist-20260809-145934-d9Recorded precheck: did I run the producing command (ls | wc -l, npm view, git log, rg -c) in THIS turn for any number written into a doc others will cite? The atone names the root cause precisely: things framed as claims got verified, things framed as background were free-handed
14formatNumber's fail-soft placeholder for a live NaN on walmart's admin metric grid was chosen as an em dash, which would have been the only violation of the zero-em-dash-in-rendered-UI rule across pages/, features/ and components/, on the first production deploy tagWalmartpeer session review (vb-fable)fixed to "n/a", matching the app's existing absent-value vocabularyatone mist-20260809-212124-e5; fix walmart-mvp@7c16a88Recorded precheck: have I grepped how the app already spells this concept before writing any literal that renders, including a single character? The generalizable half was folded into docs/app-patterns/00-data-loading.md. The aggravating fact is that the same agent had written that constraint into three canon documents in the same session
15The owner asked three times for the /admin and /spec-viewer UI to be improved; each answer delivered a measurement review, defect fixes and a content-honesty tweak instead of the visual design pass meantWalmartowner (repeated, then escalated, then /atone twice)the actual visual pass built on both pages below the fold and verified renderedatone mist-20260811-142119-a5Recorded precheck: has the user now asked for this twice? If so the CATEGORY of the delivery was wrong, not the amount. The clarifying question that was asked framed the fork in the agent's internal vocabulary, not the owner's
16doc-12's second pass claimed no playground gallery exercises Table's skeleton mode; the table gallery demos it (apps/playground/src/app/components/table/gallery.tsx:192-196 today, the same lines in table/page.tsx before the gallery split). The claim was pushed to origin about an hour before the self-catchSharedself-caught about an hour latersame-day correction commit amending the FREE entry, the item-1 stub, the closing paragraph and task #6's descriptionatone mist-20260813-182753-08; defect shipped in versable-builder@f67357b, corrected in @e339924 (both 2026-08-13)Recorded precheck: did the grep backing an absence claim carry ANY filter beyond the bare symbol? The compound grep's display filter silently excluded a bare JSX boolean prop at end of line. The atone names the asymmetry: presence claims in that session all got spot verification, absence claims did not
17FacetBar, the union of speedway's and walmart's toolbars, shipped with speedway's Button trigger, checkboxes on the opposite end from Select's check, no option subtitle or count, a mismatched label scale and shorter chipsSharedowner (toolbar coherence called out on sight)same-day coherence pass: the trigger wears the Select skin, one menu anatomy, Select options gained description and count, heights, radius and fonts measured equal before commitatone mist-20260813-192114-c8; fix versable-builder@f5cf96bRecorded precheck: measure height, font size and border radius of each unioned control side by side before shipping a composed toolbar. Walmart's in-source comment stating the trigger must wear the Select skin was read during the audit and not carried into the union
18Speedway's shared FilterBar renders every facet trigger count-only (FilterBar.tsx:210-222), computes activeChips (:177-189) and never maps it to JSX, so no list in the app shows what is currently filtered; the file's own docstring (:107) still claims chips renderSpeedwayconventions sweep (doc 46, task #91)fix is app-side, not kit-gated; walmart already ships the correct version as FacetChips in walmart-mvp@5fa032cdocs/plan/46-speedway-conventions-sweep.md:33, canon docs/design-language/07-toolbars-and-filters.md:25The sweep itself is the instrument, and it was the first app-wide audit of speedway against the canon; no per-commit check reads a canon ruling back against app code and none exists today. The timing is explanatory, not damning: the owner's 2026-08-12 refinement to doc 07 A4 postdates the 2026-08-09 freeze, so speedway could not have received it
19Walmart shadows at least six kit component names with unrelated local implementations (StatusDot, DataTable, EmptyState, Tabs, Timestamp, SidePanel); Home.tsx:3 imports the kit's StatusDot while Workspace.tsx:9 and CatalogDetail.tsx:29 import the local one, so the tag name alone tells a reader nothingWalmartfound while writing the kit component contracts, 2026-08-13not yet fixed; named as the first thing to resolve in any kit migration here, because every keep-or-replace decision depends on itwalmart-mvp/docs/04-technical-debt.md:75No adoption checklist existed on the contract docs at build time. One exists now: "Before you adopt this" carries a naming-collision question and is present on 32 of the 33 files in packages/ui/docs/ (all but patterns.md), added under the owner ruling of 2026-08-16
20Walmart runs four coexisting Select implementations (the kit Select, a hand-rolled MultiFacetControl at FacetToolbar.tsx:65, a 97-line Radix wrapper serving three call sites, and raw <select> elements) because the kit's Select had no multi-select mode when walmart needed oneWalmarttech-debt review, found 2026-08-13kit Select gained a multiple mode 2026-08-16 by owner ruling, and FacetBar retired its private multi controlwalmart-mvp/docs/04-technical-debt.md:43 ("Blocked on a kit version") and :67 ("Open in this repo, unclaimed"); fix versable-builder@bd3c1aeThis is a build-order gap rather than a decision error: select.types.ts recorded multi-select as deferred to "Week-2 presets" and it was never built. The instrument that closed it is the walmart tech-debt review of 2026-08-13, the first artifact routing app-blocked-on-kit items back to the kit; no such channel existed in the five weeks before it
21The contract-doc audit found 19 blockers across two failure shapes, one of them citations drifted far enough to point at contradicting code (page-info's tone citations where four of five cited lines carry unrelated content; tabs and timestamp citing table markup)Sharedusability audit (doc 50, contract-docs facet)citations repaired; 12 of 25 docs were already perfectly cleandocs/plan/50-usability-audit-report.md:71No mechanical citation checker existed. One exists now: scripts/check-citations.mjs landed 2026-08-14 under ruling D11 (versable-builder@27a10f1, "666 citations clean") and runs on every canon and contract-doc edit
22A white-on-amber contrast failure was fixed at the token level with the arithmetic recorded in a comment (theme/colors.css:168-172), then silently reverted for every filled Button by theme/components.css:19-30, which nobody diffed against the token layerSharedusability audit (doc 50, accessibility facet), called its sharpest single findingdisposition deferred to the owner; verification recommended raising it from major to blockerdocs/plan/50-usability-audit-report.md:83No drift guard compares a token-layer value against its component-layer consumer. The do-nots lens now catches canon "never" language automatically (scripts/build-do-nots.mjs, docs/DO-NOTS.md), but a numeric token-versus-component drift guard is still unbuilt
23Select, FacetBar and InlineEdit all move DOM focus into a floating or swapped element and never return it on close; Modal is the only one that gets this right, through native <dialog>Sharedusability audit (doc 50, accessibility facet)one shared return-focus utility resolves all three blockers (E F2 to F4)docs/plan/50-usability-audit-report.md:83No shared focus-management primitive existed when each floating component was built independently, so each one solved the same problem alone or not at all. The audit is the first review that read the three side by side
24A fresh consumer following the kit's README hits a registry 401 with no token guidance anywhere, the README's own DataTable example does not typecheck (rows is required and absent), the docs directory both READMEs point at is not in the published files allowlist, and tailwindcss is not declared as a dependency at allSharedusability audit (doc 50, DX facet), five findings all confirmedflagged, not fixed at audit timedocs/plan/50-usability-audit-report.md:135Nobody had exercised the README as a fresh consumer would, with a cold install and a copy-paste, in the weeks between the kit's first publish and this audit. The audit notes that until these land, the "fresh adopter composes without steering" criterion cannot be evaluated at all
25Walmart's Jobs page renders two search boxes, one in the filter row and one below itWalmartspotted 2026-08-12 during unrelated verification; the doc itself records it as never confirmed as a defectnone yetwalmart-mvp/docs/04-technical-debt.md:105/ui-categorical-check measures exactly this class, two controls doing the same job on one screen, and it has existed since 2026-07-16, well before this surface was built. It is not run on walmart; docs/app-patterns/14-validating-a-ui-change.md names it as a pass for shared-surface changes in the builder repo
26The workspace selector loaded as its own page before the app shell; the owner opened the 30-item feedback batch with it and wrote "Again", indicating it had been raised beforeSpeedwayowner, verbatim and repeatedresolved in the F-round rebuild; the shell loads first with the selector inside or over itowner-signal ts 2026-07-13T07:23:19.609Z (hits 30)No shell-first build order was written down at the time. Both app-patterns docs now carry one: docs/app-patterns/04-migrating-an-app.md:102 ("Work outward from the shell, because a page migrated inside an unmigrated shell…") and docs/app-patterns/05-starting-a-new-app.md:65-67, each putting AppShell, Sidebar and Topbar first in its build order
27Dev backend credentials (gcloud ADC) expired mid-build and speedway rendered the failure as a raw grpc dump; the handoff to the owner named neither the prerequisite nor its one-line fix, though the same failure had been personally hit and diagnosed two days earlier in the same buildSpeedwayowner opened the app to the raw dumproot ErrorBoundary now recognizes the GCP-reauth class, showing recovery commands in dev and admin copy in prod, verified against the live expired credentialatone mist-20260712-210531-07Recorded precheck: what did I have to fix or start this session for this surface to work? Every answer belongs in the handoff with its fix command. The atone names the deeper move: a failure personally hit during a build was routed around as an environment obstacle instead of fixed as a product defect
28/bloop was invoked by name for three UI items, twice by name; its mandatory adversarial validation gate was silently skipped for all three and they were reported and board-marked done, while that same gate had already produced 23 findings including 3 ship-blockers on a different build in the same sessionSpeedwayself-caughtthe gate run retroactively on the shipped diff before continuing to report the items doneatone mist-20260727-223728-20Recorded precheck: name each mandatory phase of a named process and state whether it ran. The omission was invisible because "gate skipped" was never written down anywhere, and partial rigor (live screenshots) was allowed to stand in for the missing phase

7.3 The families that recur#

Family 1: a rebuild replaces accumulated UX without a parity audit. Rows 2, 3, 10, 11, 26. A page or an app gets rewritten from scratch instead of ported, and the rewrite is verified against itself rather than against the reference the owner remembers, so the gap surfaces only when the owner opens the page. The instruments that exist now: ~/.claude/rules/invariant-graduation.md and its "UI surface purge gate", graduated directly from row 2 and requiring a parity ledger or explicit owner approval before any owner-reviewed surface is deleted or replaced; /vis-compare for rendering the reference and the result side by side, which already existed at the time of row 3 and was not invoked; and docs/app-patterns/04-migrating-an-app.md:16, whose Step 0 is writing the parity ledger before anything is replaced.

Family 2: a local surface diverges from the canon or a design mock and ships unverified against it. Rows 6, 7, 8, 9, 14, 17, 18. A component or a piece of copy is built from memory, from a nearby sibling, or from a cheaper extraction instead of the mock or the canon rule that governs it, and the divergence is caught only when the owner looks at the pixels. The instruments that exist now: the [design-mocks] rule in ~/.claude/rules/testing.md; docs/DO-NOTS.md, generated by scripts/build-do-nots.mjs over every contract doc's Banned section and every canon "never" sentence; the "Before you adopt this" checklist on 32 of the 33 files in packages/ui/docs/; and /ui-categorical-check for the measurable classes of drift, which predates rows 8, 9, 14, 17 and 18 and was reached for in none of them.

Family 3: the instrument was absent, not the judgment. Rows 1, 13, 16, 21, 22, 23, 24. These are not bad decisions but missing or unfindable checks: no definition-of-done check on an archive sweep, no citation checker, no drift guard between a token and its component-layer consumer, no fresh-eyes README exercise. The instruments that exist now: scripts/check-citations.mjs (ruling D11, versable-builder@27a10f1, 666 citations clean at that run) and the do-nots lens (scripts/build-do-nots.mjs, docs/DO-NOTS.md). Still unbuilt: a numeric token-versus-component drift guard (row 22) and any recurring fresh-consumer exercise of the README (row 24).

Family 4: a new surface skips the sibling or naming sweep. Rows 4, 5, 19, 20, 25. A page or component is added without diffing the nearest sibling that solves the same problem, producing a missing pagination model, a re-authored panel shell, a shadowed component name, or a duplicated control on one screen. The instruments that exist now: the sibling-diff prechecks recorded in rows 4 and 5; the naming-collision question that opens the "Before you adopt this" checklist in packages/ui/docs/; and the walmart tech-debt review (walmart-mvp/docs/04-technical-debt.md) as the channel that routes app-blocked-on-kit findings to the kit. Row 20 is the family's exception: the kit genuinely lagged the app's need, and its remedy is release cadence rather than a check.

Family 5: a process declared complete without its own steps having run. Rows 12, 15, 27, 28. A route set, a build gate, a handoff or a UI pass is reported done because its name was invoked or its happy path was seen once, while the steps that make it done (boot into every mapped route, run the gate that was named, hand over the prerequisite you yourself hit two days earlier, build the pass that was asked for three times) never ran. This is the shape the atone ledger records most often across every project, sixteen events by 2026-08-17, and it graduated to a rule with a mechanical gate: ~/.claude/rules/exercise-based-verification.md (run the changed path in the state that matters before saying done; a collect, a compile or a lint is not a run) and the declared-ready Stop hook behind it. In this repo the same rule is CLAUDE.md's own bar for done: exercised in the running playground, in both themes, not merely typechecked.

Rows 12, 15, 27 and 28 were left unclaimed by the vet, which named their shared shape and left the fifth family to the author; the atone slug behind them is declared-ready-without-runtime-exercise.

7.4 What this half is built from, and what it could not check#

Method: /pyramid-sweep's spine (manifest, extract, mechanical cut, one synthesis seat, one adversarial vet, human bake) with the instruments swapped for this domain: the sessions had already distilled themselves into commits, atone events and runtime notes, so raw transcripts were mined mechanically for the owner's own words and nothing else. Run dir: ~/.claude/style/sweep/20260817-guidebook-retro/ (candidates, the draft, the vetted output with its per-row log).

Not checked, stated so it is not mistaken for checked: whether the five-family cut is the right taxonomy (families are an interpretive claim; the vet checked only that each row is claimed once and every remedy cited exists); the 2026-07-13 owner batch beyond its opening 2,500 characters; and whether row 25 is a defect at all (walmart-mvp/docs/04-technical-debt.md:105 states the two search boxes as fact and records that the finding was never confirmed).

The owner's optional review of this half is task #92; if it happens, its corrections land here as further rows or as edits with their own citation.

@versable-git/ui · reference, canon, and method, read in place