From e9e55a09fedad902b7f99f21bf01bd589f8a84dd Mon Sep 17 00:00:00 2001 From: Ryan Dombrowski Date: Thu, 6 Aug 2026 21:45:36 -0400 Subject: [PATCH 1/3] =?UTF-8?q?build:=20swap=20to=20dspack-emit=200.5.0=20?= =?UTF-8?q?+=20dspack-gen=200.2.1=20=E2=80=94=20one=20emitter=20version,?= =?UTF-8?q?=20at=20last?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.5.0 foundation release integration, and the retirement of a trace-risk on the register since July: the dependency tree previously carried TWO emitter versions (0.4.1 direct, 0.3.1 via dspack-gen's lockfile-frozen range), which is exactly the divergence that could evade gate A3. With dspack-gen 0.2.1 admitting the new emitter, the tree now resolves exactly one dspack-emit@0.5.0 and one dspack-gen@0.2.1, regenerated from the npm registry with no file, tarball, override, or worktree references. Consumer behavior is proven identical, not assumed: the committed catalogs rebuild byte-identically under 0.5.0 (v1 profiles are byte-frozen by the emitter's own pinned gates), the shadcn contract pin stays at v2.3.0 @ 805732c (sha256 verified, self-announcing), and the full battery is green — 155 unit tests across seven packages plus agent and web, renderer parity, typechecks, both static exports, exhibit Playwright 106, composer agent-mode + accessibility 42. Ranges: packages/contracts pins emit exactly (0.5.0, the byte-sync discipline); apps/agent and apps/composer take ^0.5.0 (composer's was in devDependencies — the single-version proof caught the miss); web/composer/ agent take gen ^0.2.1. No representation capabilities are consumed by this swap: profile v2, fidelity, --strict-surface and functions ship in the emitter but Studio's profiles remain v1 and byte-identical. T1-T5 remain unimplemented. No contract pin moves. No v3 migration. Co-Authored-By: Claude Opus 5 --- apps/agent/package.json | 4 ++-- apps/composer/package.json | 4 ++-- apps/web/package.json | 2 +- packages/contracts/package.json | 2 +- pnpm-lock.yaml | 38 ++++++++++++++++----------------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/agent/package.json b/apps/agent/package.json index 947e395..118b9d9 100644 --- a/apps/agent/package.json +++ b/apps/agent/package.json @@ -13,9 +13,9 @@ "record:catch": "tsx src/record-catch.ts" }, "dependencies": { - "@aestheticfunction/dspack-emit": "^0.4.1", + "@aestheticfunction/dspack-emit": "^0.5.0", "@aestheticfunction/dspack-export": "^0.5.0", - "@aestheticfunction/dspack-gen": "^0.2.0", + "@aestheticfunction/dspack-gen": "^0.2.1", "@aestheticfunction/dspack-spec": "^0.4.2", "@dspack-studio/agui-bridge": "workspace:*", "@dspack-studio/composer-core": "workspace:*", diff --git a/apps/composer/package.json b/apps/composer/package.json index fb2834c..f8e46b0 100644 --- a/apps/composer/package.json +++ b/apps/composer/package.json @@ -11,7 +11,7 @@ "typecheck": "node scripts/demo-assets.mjs && tsc -p tsconfig.json" }, "dependencies": { - "@aestheticfunction/dspack-gen": "^0.2.0", + "@aestheticfunction/dspack-gen": "^0.2.1", "@aestheticfunction/dspack-spec": "^0.4.2", "@dspack-studio/a2ui-ingest": "workspace:*", "@dspack-studio/agui-bridge": "workspace:*", @@ -23,7 +23,7 @@ "react-dom": "19.2.7" }, "devDependencies": { - "@aestheticfunction/dspack-emit": "^0.4.1", + "@aestheticfunction/dspack-emit": "^0.5.0", "@types/node": "^22.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/apps/web/package.json b/apps/web/package.json index e3042c6..9af8858 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,7 +12,7 @@ "typecheck": "tsc -p tsconfig.json" }, "dependencies": { - "@aestheticfunction/dspack-gen": "^0.2.0", + "@aestheticfunction/dspack-gen": "^0.2.1", "@astryxdesign/core": "0.1.4", "@astryxdesign/theme-butter": "0.1.4", "@astryxdesign/theme-chocolate": "0.1.4", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 94f1adc..a046f70 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -20,7 +20,7 @@ "typecheck": "tsc -p tsconfig.json" }, "dependencies": { - "@aestheticfunction/dspack-emit": "0.4.1" + "@aestheticfunction/dspack-emit": "0.5.0" }, "devDependencies": { "@astryxdesign/cli": "0.1.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7d6ec0..ec84a5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ importers: apps/agent: dependencies: '@aestheticfunction/dspack-emit': - specifier: ^0.4.1 - version: 0.4.1 + specifier: ^0.5.0 + version: 0.5.0 '@aestheticfunction/dspack-export': specifier: ^0.5.0 version: 0.5.0 '@aestheticfunction/dspack-gen': - specifier: ^0.2.0 - version: 0.2.0(zod@4.4.3) + specifier: ^0.2.1 + version: 0.2.1(zod@4.4.3) '@aestheticfunction/dspack-spec': specifier: ^0.4.2 version: 0.4.2 @@ -61,8 +61,8 @@ importers: apps/composer: dependencies: '@aestheticfunction/dspack-gen': - specifier: ^0.2.0 - version: 0.2.0(zod@4.4.3) + specifier: ^0.2.1 + version: 0.2.1(zod@4.4.3) '@aestheticfunction/dspack-spec': specifier: ^0.4.2 version: 0.4.2 @@ -92,8 +92,8 @@ importers: version: 19.2.7(react@19.2.7) devDependencies: '@aestheticfunction/dspack-emit': - specifier: ^0.4.1 - version: 0.4.1 + specifier: ^0.5.0 + version: 0.5.0 '@types/node': specifier: ^22.0.0 version: 22.20.1 @@ -113,8 +113,8 @@ importers: apps/web: dependencies: '@aestheticfunction/dspack-gen': - specifier: ^0.2.0 - version: 0.2.0(zod@4.4.3) + specifier: ^0.2.1 + version: 0.2.1(zod@4.4.3) '@astryxdesign/core': specifier: 0.1.4 version: 0.1.4(@stylexjs/stylex@0.18.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -295,8 +295,8 @@ importers: packages/contracts: dependencies: '@aestheticfunction/dspack-emit': - specifier: 0.4.1 - version: 0.4.1 + specifier: 0.5.0 + version: 0.5.0 devDependencies: '@astryxdesign/cli': specifier: 0.1.4 @@ -424,8 +424,8 @@ packages: '@a2ui/web_core@0.10.3': resolution: {integrity: sha512-B0+zhC1gac4vweqrWxcW1tlmdspMuZl8YzNXSrza3ppayoFYcJblMuvu8g8+6l++aycNQK5D4WaBX85KVvVx+g==} - '@aestheticfunction/dspack-emit@0.4.1': - resolution: {integrity: sha512-/p1Y4dAWlcwtPcfM81t2EjPChifCb9VvnIQCZ9A1dkbU13mSVYk+AQquxvY51PV9naxFAktFYLdx1mFjIOZqrQ==} + '@aestheticfunction/dspack-emit@0.5.0': + resolution: {integrity: sha512-PYGTyAV7tuKN9H5TkQbei5CamRBDHtHUZIX2xiWoxVqvDoziGvyXMOasOppar2JrE7m0XXa4a7pcpCC3l66cIw==} hasBin: true '@aestheticfunction/dspack-export@0.5.0': @@ -433,8 +433,8 @@ packages: engines: {node: '>=22.0.0'} hasBin: true - '@aestheticfunction/dspack-gen@0.2.0': - resolution: {integrity: sha512-+oaMqk/pRH0FkK8On7vDKRBQvAw+qROujaP9yRduvm9xbElTk7KAkgNYhYqbLTnY16+rbqAk22Zud+fgsJ4paQ==} + '@aestheticfunction/dspack-gen@0.2.1': + resolution: {integrity: sha512-cUiQMHOi0kIyhAtzF9Tn2pfYMETyHarIL1PPlghFk8h6qLQ5WzTd2GoPyn7GcrMgWyEGuJZ+VRqiRBNoKu0gZg==} engines: {node: '>=20.0.0'} hasBin: true @@ -2329,7 +2329,7 @@ snapshots: zod: 3.25.76 zod-to-json-schema: 3.25.2(zod@3.25.76) - '@aestheticfunction/dspack-emit@0.4.1': + '@aestheticfunction/dspack-emit@0.5.0': dependencies: ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) @@ -2347,9 +2347,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@aestheticfunction/dspack-gen@0.2.0(zod@4.4.3)': + '@aestheticfunction/dspack-gen@0.2.1(zod@4.4.3)': dependencies: - '@aestheticfunction/dspack-emit': 0.4.1 + '@aestheticfunction/dspack-emit': 0.5.0 '@anthropic-ai/sdk': 0.109.1(zod@4.4.3) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) From 1f64b2199915cd7badacb5189721224ea287a707 Mon Sep 17 00:00:00 2001 From: Ryan Dombrowski Date: Sat, 8 Aug 2026 00:00:57 -0400 Subject: [PATCH 2/3] =?UTF-8?q?feat(shadcn-renderers):=20DialogRender=20cl?= =?UTF-8?q?oses=20the=20last=20registry=20placeholder=20=E2=80=94=2012/12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured first (2026-08-08): across the whole studio corpus — 19 files, contracts-build surfaces + replay fixtures — the shadcn registry already renders 100% of emitted instances. The 11/12 coverage was a completeness asymmetry with Astryx, not a rendering gap: 'Dialog' is declared catalog vocabulary that NO worked example, scenario, or replay fixture emits (0 instances), so the placeholder was never actually hit in production. DialogRender draws the governed content (title + child) inline with shadcn's dialog-content idiom — same canvas posture as AlertDialogRender, no portal, no Radix in the bundle. variant widens the surface; purpose is carried as a data attribute without inventing chrome the catalog doesn't model. This removes the advertised placeholder and restores Astryx/shadcn symmetry at near-zero cost. The corpus-exercise parity invariant was inverted to the direction that is actually a correctness property: every EMITTED component must have a renderer (no unimplemented instance), non-vacuous via >100 instances. The reverse — every renderer must be exercised by THIS corpus — is not correctness: a registry may cover catalog vocabulary a given corpus does not use. DialogRender is verified by a focused render test instead. shadcn-renderers 20/20; web typecheck clean. Co-Authored-By: Claude Fable 5 --- apps/web/app/design-system.tsx | 2 +- .../src/components/DialogRender.tsx | 43 +++++++++++++++++ .../src/dialog-render.test.tsx | 47 +++++++++++++++++++ .../src/emitted-prop-parity.test.tsx | 21 ++++++--- .../src/registry-parity.test.ts | 6 +-- packages/shadcn-renderers/src/registry.tsx | 13 ++--- 6 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 packages/shadcn-renderers/src/components/DialogRender.tsx create mode 100644 packages/shadcn-renderers/src/dialog-render.test.tsx diff --git a/apps/web/app/design-system.tsx b/apps/web/app/design-system.tsx index badeb15..e49d98a 100644 --- a/apps/web/app/design-system.tsx +++ b/apps/web/app/design-system.tsx @@ -38,7 +38,7 @@ export const DESIGN_SYSTEMS: Record = { id: "shadcn", label: "shadcn/ui", registry: shadcnRegistry, - note: "11 of 12 catalog components render through vendored shadcn/ui visuals; Dialog shows the unimplemented placeholder (incremental adoption, stated plainly).", + note: "All 12 catalog components render through vendored shadcn/ui visuals.", }, }; diff --git a/packages/shadcn-renderers/src/components/DialogRender.tsx b/packages/shadcn-renderers/src/components/DialogRender.tsx new file mode 100644 index 0000000..ca99a4a --- /dev/null +++ b/packages/shadcn-renderers/src/components/DialogRender.tsx @@ -0,0 +1,43 @@ +/** + * Catalog `Dialog` -> shadcn/ui Dialog content, rendered INLINE for the same + * reason AlertDialogRender is: on the studio canvas the governed content is + * visible evidence, not hidden behind a portal. The markup and classes are + * shadcn's dialog-content idiom; the portal/overlay behavior is deliberately + * not used, so no Radix dependency enters the bundle. + * + * This completes the shadcn registry to 12 of 12 catalog names — the + * incremental-adoption placeholder docs/renderer-abstraction.md named is now + * exercised as a real visual rather than the unimplemented fallback. + * + * `variant` (standard | fullscreen) widens the surface; `purpose` + * (required | form | info) is carried as a data attribute for styling hooks + * and assistive context without inventing chrome the catalog does not model. + */ +import { useId, type FC } from "react"; +import { cn } from "../cn"; + +export const DialogRender: FC = ({ props, buildChild }) => { + const titleId = useId(); + const fullscreen = props.variant === "fullscreen"; + return ( +
+ {props.title && ( +
+

+ {String(props.title)} +

+
+ )} + {props.child ? buildChild(props.child) : null} +
+ ); +}; diff --git a/packages/shadcn-renderers/src/dialog-render.test.tsx b/packages/shadcn-renderers/src/dialog-render.test.tsx new file mode 100644 index 0000000..44048a6 --- /dev/null +++ b/packages/shadcn-renderers/src/dialog-render.test.tsx @@ -0,0 +1,47 @@ +/** + * DialogRender — the visual that closed the last shadcn registry placeholder. + * + * Fail-first: before DialogRender existed, `shadcnRegistry.custom.Dialog` was + * undefined and a Dialog instance drew the a2ui-ingest `unimplemented` + * placeholder. `Dialog` is declared catalog vocabulary no worked example + * emits (measured 2026-08-08), so it has no corpus parity coverage — this + * focused test is its verification: given the catalog's Dialog props, the + * renderer draws the governed content (title + child) inline, no portal. + */ +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vitest"; +import { shadcnRegistry } from "./registry"; + +const buildChild = (id: string) => createElement("div", { "data-child": id }, `body:${id}`); + +const render = (props: Record): string => { + const Visual = (shadcnRegistry.custom as Record).Dialog; + return renderToStaticMarkup(createElement(Visual, { props, buildChild })); +}; + +describe("DialogRender", () => { + it("is registered — the last placeholder is now a real visual", () => { + expect((shadcnRegistry.custom as Record).Dialog).toBeDefined(); + }); + + it("draws the governed title and child inline (role=dialog, not modal)", () => { + const html = render({ title: "Invite people", child: "body_1", variant: "standard", purpose: "form" }); + expect(html).toContain('role="dialog"'); + expect(html).toContain('aria-modal="false"'); + expect(html).toContain("Invite people"); + expect(html).toContain("body:body_1"); + expect(html).toContain('data-purpose="form"'); + }); + + it("fullscreen widens the surface; standard is constrained", () => { + expect(render({ title: "T", child: "c", variant: "fullscreen" })).toContain("w-full"); + expect(render({ title: "T", child: "c", variant: "standard" })).toContain("max-w-lg"); + }); + + it("a titleless dialog omits the heading rather than drawing an empty one", () => { + const html = render({ child: "c" }); + expect(html).not.toContain("): string { const visibleText = (html: string) => html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim(); -/** Instances this design system draws (Dialog is the deliberate placeholder). */ +/** Instances this design system draws (now every catalog name, Dialog included). */ const renderable = (): EmittedInstance[] => emittedInstances().filter((i) => Boolean((shadcnRegistry.custom as Record)[i.component.component])); @@ -126,13 +126,22 @@ describe("emitted-prop vs consumed-prop parity", () => { expect(ignored).toEqual([]); }); - it("covers a corpus that actually exercises the registry", () => { + it("renders every component the corpus actually emits (no unimplemented instance)", () => { // A guard on the guard: if the corpus ever empties (a moved fixture // directory, a skipped contracts build) every check above passes vacuously. - const instances = renderable(); - expect(instances.length).toBeGreaterThan(100); - const covered = new Set(instances.map((i) => i.component.component)); - for (const name of Object.keys(shadcnRegistry.custom)) expect([...covered]).toContain(name); + // The correctness direction is emitted -> rendered: every instance the + // corpus produces must have a visual. The reverse (every renderer must be + // exercised by THIS corpus) is not a correctness property — a registry may + // legitimately cover catalog vocabulary a given corpus doesn't use. + // Measured 2026-08-08: the Astryx corpus emits 11 of the 12 catalog names; + // `Dialog` is declared vocabulary no worked example, scenario, or replay + // fixture emits, yet its renderer exists so a Dialog-bearing surface draws + // rather than falling back to the placeholder. + const all = emittedInstances(); + expect(all.length).toBeGreaterThan(100); + const emitted = new Set(all.map((i) => i.component.component)); + const rendererNames = Object.keys(shadcnRegistry.custom); + for (const name of emitted) expect(rendererNames).toContain(name); }); }); diff --git a/packages/shadcn-renderers/src/registry-parity.test.ts b/packages/shadcn-renderers/src/registry-parity.test.ts index a4395c7..f712160 100644 --- a/packages/shadcn-renderers/src/registry-parity.test.ts +++ b/packages/shadcn-renderers/src/registry-parity.test.ts @@ -17,12 +17,12 @@ const catalog = JSON.parse( const names = Object.keys(catalog.components); describe("shadcn registry parity (catalog owns vocabulary; registry owns pixels)", () => { - it("covers exactly the catalog names, with Dialog as the deliberate placeholder", () => { + it("covers exactly the catalog names, with none left unimplemented", () => { const plan = planRegistry(names, shadcnRegistry); expect([...plan.reuseBasic, ...plan.custom, ...plan.unimplemented].sort()).toEqual([...names].sort()); - expect(plan.unimplemented).toEqual(["Dialog"]); + expect(plan.unimplemented).toEqual([]); expect(plan.custom.sort()).toEqual( - ["AlertDialog", "Badge", "Button", "Card", "Column", "List", "MetadataList", "SelectableCard", "Table", "Text", "TextField"].sort(), + ["AlertDialog", "Badge", "Button", "Card", "Column", "Dialog", "List", "MetadataList", "SelectableCard", "Table", "Text", "TextField"].sort(), ); }); diff --git a/packages/shadcn-renderers/src/registry.tsx b/packages/shadcn-renderers/src/registry.tsx index 29d992e..7428e27 100644 --- a/packages/shadcn-renderers/src/registry.tsx +++ b/packages/shadcn-renderers/src/registry.tsx @@ -3,10 +3,11 @@ * each wrapped with the same data-a2ui-id provenance tagging as the Astryx * registry, so X-ray works identically under either design system. * - * Coverage is deliberately 11 of the catalog's 12 names: `Dialog` has no - * visual here and renders the a2ui-ingest `unimplemented` placeholder — - * the incremental-adoption mechanism docs/renderer-abstraction.md names as - * the intended migration path, exercised in production rather than claimed. + * Coverage is now 12 of the catalog's 12 names. `Dialog` was the last + * placeholder — the incremental-adoption mechanism docs/renderer-abstraction.md + * names — and is now a real shadcn visual (DialogRender), closing the one + * measured production renderer gap. The placeholder mechanism itself stays + * exercised by the parity suite, which proves the complement is now empty. */ import type { Registry } from "@dspack-studio/a2ui-ingest"; import { withProvenance } from "@dspack-studio/a2ui-ingest"; @@ -21,6 +22,7 @@ import { ColumnRender } from "./components/ColumnRender"; import { ListRender } from "./components/ListRender"; import { SelectableCardRender } from "./components/SelectableCardRender"; import { MetadataListRender } from "./components/MetadataListRender"; +import { DialogRender } from "./components/DialogRender"; const renders = { Text: TextRender, @@ -34,8 +36,7 @@ const renders = { List: ListRender, SelectableCard: SelectableCardRender, MetadataList: MetadataListRender, - // Dialog: deliberately absent — renders the visible unimplemented - // placeholder (legal vocabulary, missing pixels; the run is unaffected). + Dialog: DialogRender, }; export const shadcnRegistry: Registry = { From caa2d624e00b94e8efe87d31e7c9a604ccb9de6e Mon Sep 17 00:00:00 2001 From: Ryan Dombrowski Date: Sat, 8 Aug 2026 00:16:49 -0400 Subject: [PATCH 3/3] test(e2e)+docs: design-swap honesty note now asserts 12/12, not the placeholder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two design-swap honesty specs asserted the old '11 of 12' / 'unimplemented placeholder' copy — the note that advertised the Dialog gap. shadcn is now 12/12 (DialogRender), so the honest note reads 'All 12 catalog components render through vendored shadcn/ui visuals', and the specs assert that instead. The check still verifies the note reflects true coverage — the honesty property is preserved, its value updated. docs/renderer-abstraction.md updated: the swap covers all 12 names; the unimplemented FALLBACK mechanism remains (a registry may still leave a name unrendered) and is exercised by the parity suite rather than a shipped gap. Co-Authored-By: Claude Fable 5 --- docs/renderer-abstraction.md | 15 ++++++++++----- e2e/design-swap.spec.ts | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/renderer-abstraction.md b/docs/renderer-abstraction.md index e85204a..03f5d67 100644 --- a/docs/renderer-abstraction.md +++ b/docs/renderer-abstraction.md @@ -4,11 +4,16 @@ The studio's rendering stack is layered so the design system is a plug-in, not a foundation. This document states the boundaries as they exist in code today (verified by `packages/a2ui-ingest/src/registry-abstraction.test.ts`). Since the FM-10 groundwork the swap is real: `packages/shadcn-renderers` -supplies a second registry (11 of 12 catalog names; `Dialog` renders the -unimplemented placeholder by design), selected in the restyle view and -applied to every canvas. The e2e proof (`e2e/design-swap.spec.ts`) replays -one fixture under both design systems and asserts the receipt hash is -identical while the rendered DOM differs. +supplies a second registry covering all 12 catalog names (the `Dialog` +placeholder was the last, closed 2026-08-08 once measurement showed the +registry already rendered 100% of emitted instances — see +`packages/shadcn-renderers/src/dialog-render.test.tsx`). The registry is +selected in the restyle view and applied to every canvas. The +`unimplemented` fallback mechanism itself remains — a registry is still +free to leave a catalog name unrendered — and is exercised by the parity +suite rather than by a shipped gap. The e2e proof +(`e2e/design-swap.spec.ts`) replays one fixture under both design systems +and asserts the receipt hash is identical while the rendered DOM differs. ## The layers diff --git a/e2e/design-swap.spec.ts b/e2e/design-swap.spec.ts index 08b211d..3c65b86 100644 --- a/e2e/design-swap.spec.ts +++ b/e2e/design-swap.spec.ts @@ -30,7 +30,7 @@ test("honesty: the receipt hash is identical under both design systems; the pixe // Swap the design system in the restyle view (shell-level state). await page.getByTestId("view-canvas").click(); await page.getByTestId("design-system-shadcn").click(); - await expect(page.getByTestId("design-system-note")).toContainText("11 of 12"); + await expect(page.getByTestId("design-system-note")).toContainText("All 12 catalog components render"); // Back in replay, the same run renders through shadcn/ui. await page.getByTestId("view-replay").click(); @@ -71,7 +71,7 @@ test("the restyle view swaps systems honestly: note, caption, and the theme dial // shadcn: Astryx themes do not pretend to apply to another design system. await expect(page.getByRole("button", { name: "butter" })).toHaveCount(0); await expect(page.getByTestId("fm5-caption")).toContainText("Only the design system did"); - await expect(page.getByTestId("design-system-note")).toContainText("unimplemented placeholder"); + await expect(page.getByTestId("design-system-note")).toContainText("All 12 catalog components render"); await page.getByTestId("design-system-astryx").click(); await expect(page.getByRole("button", { name: "butter" })).toBeVisible(); await expect(page.getByTestId("fm5-caption")).toContainText("Only the design system's theme did");