Skip to content

FM-10 groundwork: shadcn registry, design-system swap UI, second gated catalog#14

Merged
ryandmonk merged 3 commits into
mainfrom
feat/fm10-swap-groundwork
Jul 14, 2026
Merged

FM-10 groundwork: shadcn registry, design-system swap UI, second gated catalog#14
ryandmonk merged 3 commits into
mainfrom
feat/fm10-swap-groundwork

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

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 the unimplemented placeholder 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; Dialog deliberately 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.
  • Swap UI: a design-system selector in the restyle view writes shell-level state; every canvas (replay/live/break/restyle) renders through the selected registry. The Astryx theme dial scopes to Astryx only.
  • Second catalog wiring: packages/contracts/shadcn-ui.dspack.json byte-synced with dspack main (CI sync check extended to both copies); the build emits catalog.shadcn.* behind the same A1/A2/A3 gates via dspack-emit's published shadcnProfile. Gates pass on both A2UI versions today.
  • Provenance promoted: withProvenance/childIds moved 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.ts replays 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

  • Unit: shadcn registry-parity suite 3/3 against the real emitted catalog (names from catalog alone; unimplemented exactly [Dialog]; catalog schemas unaffected by registry); all package suites green.
  • Contracts build: astryx + shadcn catalogs gate clean, A2UI 0.9.1 + 1.0 (shadcn worked example feeds A3; emitter warnings are the documented flatten/synthesize casualties).
  • Playwright: new design-swap.spec.ts 3/3; full suite 82 passed + 3 gated skips; production-suite registration.
  • Browser (static export): shadcn tokens computed on the canvas (oklch zinc, rounded-md), 14 provenance-tagged nodes, recipe surface renders through shadcn markup; first-load JS unchanged (102 kB shell).

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

…, 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>
Copilot AI review requested due to automatic review settings July 14, 2026 19:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread apps/web/app/restyle-view.tsx Outdated
Comment thread packages/shadcn-renderers/src/components/AlertDialogRender.tsx Outdated
Comment thread packages/shadcn-renderers/src/components/TableRender.tsx
ryandmonk and others added 2 commits July 14, 2026 16:33
…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>
@ryandmonk
ryandmonk merged commit abaac0b into main Jul 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants