FM-10 groundwork: shadcn registry, design-system swap UI, second gated catalog#14
Merged
Conversation
…, second catalog, CI
- packages/shadcn-renderers: a second Registry {reuseBasic, custom} with
vendored shadcn/ui visuals (default zinc theme, Tailwind v4 compiled at
package build with no preflight, CSS-variable-scoped under
[data-design-system=shadcn] so nothing leaks into the studio shell; cva/
clsx/tailwind-merge confined to the package). 8 of 9 catalog names;
Dialog deliberately renders the unimplemented placeholder — the
incremental-adoption mechanism exercised, not just claimed. AlertDialog
renders inline for the same evidence-visibility reason the Astryx one
does, which keeps Radix out of the bundle entirely.
- withProvenance/childIds promoted from astryx-renderers to a2ui-ingest
(design-system-agnostic adapter concerns); both registries tag
data-a2ui-id, so X-ray works identically under either system.
- Swap UI: design-system selector in the restyle view writing shell-level
state; every canvas (replay, live, break, restyle) renders through the
selected registry via context. Astryx keeps its 8 themes; the theme dial
scopes to Astryx only (another system's themes are its own). FM-5
caption extended for FM-10.
- Second catalog wiring: packages/contracts carries shadcn-ui.dspack.json
byte-synced with dspack main (CI sync check extended); build emits
catalog.shadcn.* behind the same A1/A2/A3 gates via dspack-emit's own
shadcnProfile. Scenario coverage under this contract waits on the
owner-authored upstream extension (intents beyond destructive-action);
the wiring and gates run today.
- Tests: registry-parity suite against the REAL emitted catalog (names
from the catalog alone; unimplemented is exactly [Dialog]; catalog
schemas unchanged by registry). e2e honesty check in the receipts
spirit: the same fixture replayed under both design systems downloads
an IDENTICAL receipt hash while the AlertDialog markup differs and the
repaired 'Delete Account' label survives the swap. X-ray under shadcn
covered; production suite registration.
First-load JS unchanged (102 kB shell). Verified in the browser on the
static export: shadcn tokens applied (oklch zinc, rounded-md), 14
provenance-tagged nodes, recipe surface renders through shadcn markup.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR lays the groundwork for FM-10 by adding a second renderer registry (shadcn/ui) and wiring a shell-level design-system selector so all canvases can render through the selected registry without changing the underlying A2UI catalog, events, gates, or receipts. It also introduces a second (shadcn) contract build + sync-check pipeline and promotes provenance utilities into the design-system-agnostic ingest layer.
Changes:
- Add
@dspack-studio/shadcn-renderers(registry, scoped Tailwind v4 CSS build, parity tests) and wire it into the studio as an alternate design system. - Introduce shell-level design-system state/context and propagate it through replay/restyle canvases; add Playwright coverage proving receipt hash invariance across systems.
- Add a second contract (
shadcn-ui.dspack.json) with build output + CI byte-sync check against authoritative upstream.
Reviewed changes
Copilot reviewed 34 out of 36 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Updates lockfile for new shadcn renderer package and Tailwind v4 CLI/tooling deps. |
| playwright.production.config.ts | Includes the new design-system swap e2e spec in the production suite. |
| packages/shadcn-renderers/tsconfig.json | Adds TS config for the new shadcn renderers package. |
| packages/shadcn-renderers/src/styles.css | Adds shadcn-scoped Tailwind v4 theme/utilities and token variables under [data-design-system="shadcn"]. |
| packages/shadcn-renderers/src/registry.tsx | Defines shadcnRegistry mapping catalog names to shadcn visuals with provenance tagging. |
| packages/shadcn-renderers/src/registry-parity.test.ts | Adds parity tests ensuring registry coverage matches emitted catalog vocabulary and schemas. |
| packages/shadcn-renderers/src/index.ts | Exports the shadcn registry entrypoint. |
| packages/shadcn-renderers/src/components/TextRender.tsx | Implements shadcn rendering for catalog Text. |
| packages/shadcn-renderers/src/components/TextFieldRender.tsx | Implements shadcn rendering for catalog TextField. |
| packages/shadcn-renderers/src/components/TableRender.tsx | Implements shadcn rendering for catalog Table (data-driven + children modes). |
| packages/shadcn-renderers/src/components/ColumnRender.tsx | Implements shadcn rendering for catalog Column. |
| packages/shadcn-renderers/src/components/CardRender.tsx | Implements shadcn rendering for catalog Card. |
| packages/shadcn-renderers/src/components/ButtonRender.tsx | Implements shadcn rendering for catalog Button with projected variants/sizes. |
| packages/shadcn-renderers/src/components/BadgeRender.tsx | Implements shadcn rendering for catalog Badge with projected variants. |
| packages/shadcn-renderers/src/components/AlertDialogRender.tsx | Implements inline shadcn-style AlertDialog presentation. |
| packages/shadcn-renderers/src/cn.ts | Adds shadcn cn helper (clsx + tailwind-merge). |
| packages/shadcn-renderers/package.json | Declares package exports and the Tailwind build step for emitting dist/shadcn.css. |
| packages/contracts/src/build.ts | Extends contract build to emit/gate shadcn catalogs using shadcnProfile and a worked example surface. |
| packages/contracts/shadcn-ui.dspack.json | Adds the shadcn/ui dspack contract (byte-synced copy). |
| packages/contracts/package.json | Exports the shadcn contract JSON from @dspack-studio/contracts. |
| packages/astryx-renderers/src/registry.tsx | Switches provenance wrapper import to @dspack-studio/a2ui-ingest. |
| packages/astryx-renderers/src/index.ts | Re-exports provenance helpers from @dspack-studio/a2ui-ingest. |
| packages/astryx-renderers/src/components/TextRender.tsx | Uses design-system-agnostic childIds from ingest. |
| packages/astryx-renderers/src/components/TableRender.tsx | Uses design-system-agnostic childIds from ingest. |
| packages/astryx-renderers/src/components/ColumnRender.tsx | Uses design-system-agnostic childIds from ingest. |
| packages/a2ui-ingest/src/provenance.tsx | Introduces shared provenance tagging and child id extraction helpers. |
| packages/a2ui-ingest/src/index.ts | Exports withProvenance and childIds from ingest’s public API. |
| e2e/design-swap.spec.ts | Adds Playwright assertions proving receipt hash invariance and DOM differences across systems. |
| docs/renderer-abstraction.md | Updates documentation to reflect the now-real design-system swap and its e2e proof. |
| apps/web/public/take-home/astryx.dspack.json | Adds a take-home copy of the Astryx contract for the web app. |
| apps/web/package.json | Ensures shadcn CSS is built before next dev/next build; adds workspace dep on shadcn renderers. |
| apps/web/app/studio.tsx | Introduces shell-level DesignSystemContext provider/state and passes selector props to RestyleView. |
| apps/web/app/run-view.tsx | Renders the replay canvas through the selected design system registry and scopes the canvas. |
| apps/web/app/restyle-view.tsx | Adds UI for switching design systems; applies canvas scoping attributes; limits Astryx theme dial to Astryx. |
| apps/web/app/design-system.tsx | Centralizes design-system definitions, context hook, and canvas scoping props; imports shadcn CSS. |
| .github/workflows/ci.yml | Extends CI to sync-check shadcn contract copy and to test the new shadcn-renderers package. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ed status column - restyle-view + run-view: the inline light background/color/colorScheme overrides apply to the Astryx artboard only; under shadcn the scope's own tokens (including [data-mode=dark] values) own the canvas. Verified in the browser: dark mode now flips bg oklch(1 0 0) -> oklch(0.141...) with the light foreground. - shadcn AlertDialogRender: aria-labelledby/aria-describedby wired to the title and description nodes (useId); verified the references resolve to the rendered governed content. - shadcn TableRender: the status column header is labeled 'Status' (matching the Astryx renderer) and every th carries scope=col. - Removed a stray generated file (apps/web/public/take-home/ astryx.dspack.json — FM-11's build-time artifact, leaked from a local build) and gitignored the directory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conflict resolutions, combining both sides everywhere: - apps/web/package.json: dev/build chains run BOTH the shadcn CSS build and the take-home assets copy; deps carry dspack-gen + shadcn-renderers; the web vitest suite stays. - apps/web/app/studio.tsx: the view union includes 'home', the shell carries the FM-10 design-system state, RestyleView gets the selector props, and the take-home view renders. - pnpm-lock.yaml regenerated. Combined suite on the merged tree: 90 Playwright passed + 4 gated skips (take-home, design-swap, FM-7 interactive, and the rest together); web unit 6/6; contracts build clean; typecheck clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PHASE-NEXT WS2, the engineering track: everything except the owner-authored contract extension proceeds. Grounded in docs/renderer-abstraction.md's verified boundaries: the registry supplies
{ reuseBasic, custom }and nothing else, the catalog is the sole source of vocabulary, and theunimplementedplaceholder is the intended migration mechanism.What's here
packages/shadcn-renderers: vendored shadcn/ui visuals (default zinc, Tailwind v4 compiled at package build — no preflight, tokens scoped under[data-design-system=shadcn], nothing leaks into the studio shell). 8 of 9 catalog names;Dialogdeliberately renders the unimplemented placeholder — incremental adoption exercised in production. AlertDialog renders inline (the Astryx registry's evidence-visibility decision), which keeps Radix out of the bundle.packages/contracts/shadcn-ui.dspack.jsonbyte-synced with dspack main (CI sync check extended to both copies); the build emitscatalog.shadcn.*behind the same A1/A2/A3 gates via dspack-emit's publishedshadcnProfile. Gates pass on both A2UI versions today.withProvenance/childIdsmoved from astryx-renderers to a2ui-ingest (design-system-agnostic); X-ray works identically under either registry.The honesty check (receipts spirit)
e2e/design-swap.spec.tsreplays fixture-001 under both design systems and asserts the downloaded receipt hash is byte-identical while the AlertDialog markup differs and the repaired "Delete Account" label survives the swap — FM-5's "nothing about this interface changed" claim generalized to FM-10 and proven, not captioned.Owner-gated dependency (flagged, per plan)
Scenario coverage under the shadcn contract (generation, scheduling/structured-editing intents, intent-tagged examples) waits on the owner-authored extension upstream in
dspack/examples— that PR sequences first and the studio byte-syncs. Required shape is specified in docs/PHASE-NEXT.md WS2. Nothing in this PR is blocked by it: the registry swap runs on the existing astryx-contract catalog, which is what recorded fixtures carry.Verification
[Dialog]; catalog schemas unaffected by registry); all package suites green.design-swap.spec.ts3/3; full suite 82 passed + 3 gated skips; production-suite registration.Fail-first note
New-surface assertions (the selector and second registry do not exist on old code). The receipt-hash check discriminates by construction: any swap-induced change to events, gates, or audit would change the canonical bytes and fail it loudly.
🤖 Generated with Claude Code