{"_id":"@brad-frost-web/eddie-render","_rev":"6-28bc1e55cd47a101e8a5234e9454e379","name":"@brad-frost-web/eddie-render","dist-tags":{"latest":"0.70.0"},"versions":{"0.65.0":{"name":"@brad-frost-web/eddie-render","version":"0.65.0","license":"MIT","_id":"@brad-frost-web/eddie-render@0.65.0","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"3f97a517bb7664e63e1afa9ed658b471e3c69db6","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.65.0.tgz","fileCount":36,"integrity":"sha512-gXejlGMpHNlZLU6pEVAxG9mvzZ8WGze1GKlzMxC+C6iTFH2EPxlK+VVzkBpUs9qcog6NAKzF4mUDcSoQjcKEhw==","signatures":[{"sig":"MEQCICuS0M/+08QoaXCzhnFnvZfCap52kGeb10nndE8tqwBAAiBqf8Rt0R/vZF9EQTZPGQ/+p+ES2c32TElXHiZhjFdjFQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339459},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"e6bc369a4503c4f845cea621d9aae5055d5b990c","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"_npmUser":{"name":"brad_frost","email":"brad@bradfrost.com"},"repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"11.6.2","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"_nodeVersion":"24.13.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/eddie-render_0.65.0_1788960345263_0.5366913718232107","host":"s3://npm-registry-packages-npm-production"}},"0.66.0":{"name":"@brad-frost-web/eddie-render","version":"0.66.0","license":"MIT","_id":"@brad-frost-web/eddie-render@0.66.0","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"24721d44d50e23e370abb293a070bf62163a230d","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.66.0.tgz","fileCount":36,"integrity":"sha512-d3vVJQBYb9HpP5gre9/A5GkR3WUk5a0nZ2xGc8BP9j6lzX4thGylLR8FfBefD/wKQd9+JGVRoFCPtviBORnFBw==","signatures":[{"sig":"MEUCIQDSuMXDdNt4uFWZaf9ZilsMd51NF90467R67qCSv+4PPQIgfv/fS0SH/txu2klXx4iUeTwA5/o2jjmz5heEOsFxNPg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339459},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"29367a5f02df153dfcd76222aa796115efeb5181","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b027ebef-b110-4d69-9fd8-e78b14a128fb"}},"repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"12.0.2","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/eddie-render_0.66.0_1789103906157_0.08984728678703835","host":"s3://npm-registry-packages-npm-production"}},"0.67.0":{"name":"@brad-frost-web/eddie-render","version":"0.67.0","license":"MIT","_id":"@brad-frost-web/eddie-render@0.67.0","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"43edc938736b3c3efe73f9ded5e7fd3dcd94fd53","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.67.0.tgz","fileCount":36,"integrity":"sha512-qSwh4ykFhMnY7oD6Ydki4nI7ovQ4LIwHDGU8i/j/X/0iLi3WS+DJ/w97XcTaYIzbKY/4tWeLNVGb9O/mExIBqA==","signatures":[{"sig":"MEYCIQDkrpvHW0YzIVP9zzAMrU6q9m1GxgDddKOahc4nnBAtCwIhANYV8McqdYN0GqLr6YKRFZN7G+JKaWnvcKoQGAmnPt6Y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFc4ZE22R/ljwb6+TBIRZU7rjhRN+ihlD+FzWQ6JFrtcAiEA30rJ2oCA1CJhyRRqC0C8/hLnmp5rVU1gWot/Mmvq7m0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339459},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"c0cc3d93eec8320a0e6781c4dc072ff957f13f1a","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b027ebef-b110-4d69-9fd8-e78b14a128fb"}},"repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"12.0.2","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/eddie-render_0.67.0_1789809848429_0.6022139211297495","host":"s3://npm-registry-packages-npm-production"}},"0.68.0":{"name":"@brad-frost-web/eddie-render","version":"0.68.0","license":"MIT","_id":"@brad-frost-web/eddie-render@0.68.0","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"9d9183727241a48d5e7189f113a2291d893b105f","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.68.0.tgz","fileCount":36,"integrity":"sha512-x2b5wzYHNhIh3o2cMk4XI3iUidQJrjq7hfLH/4sygmVX20zuZsivf3vJYCLKhS9Exq7C1fJnP0vYcZD6rWk31A==","signatures":[{"sig":"MEQCIFMja5A3dutzIkbkxYIeEBIuyKO/81lHSvLDqOK4OK3CAiABCg6LM2hbTtxBpVk+OECzcTh7JhmlX6Du4yhMjbB2HQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDDhUHCrVyRlleV7ZArbohlkpw/Lm4Km/kd5lkv7OJaEwIgF94tsSTVdTW+SwL8LwSJuZEXXlV1W2VVUrUxtPZe/iQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":344476},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"81e5039d18d756327bc11e14f27c60cea12d639d","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b027ebef-b110-4d69-9fd8-e78b14a128fb"}},"repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"12.0.2","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/eddie-render_0.68.0_1790097233729_0.31175224112848454","host":"s3://npm-registry-packages-npm-production"}},"0.69.0":{"name":"@brad-frost-web/eddie-render","version":"0.69.0","license":"MIT","_id":"@brad-frost-web/eddie-render@0.69.0","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"e8b0578f7640fd06f05d9b7fe3c057d29ed43306","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.69.0.tgz","fileCount":36,"integrity":"sha512-6q35QXGfqQjDfYvvWa17gJrSbB+XaxpsRVLVOawHLhTT+uQzuYaxIepin3hG2mZssEKYT9WVQ80ehyWbKhOPpg==","signatures":[{"sig":"MEUCIQDluWnZaYmO3lUpm6okNTnA7sLfycIrGrtGYHi5I6NrwwIgVeYzh2dprjjVtchxLqXi/hWyXzE+etSOZCwnOWkRAMk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCWi50ar/CNxyO/xPu9CjQSmrresMhU9ZpbUczlg6ZHOAIhAO9vLaR0Px1PII/nnuzsMaMHSmm+YA0qKZQ3JD912gET","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":344476},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"f7d36522896fbed5449e4a3e7ae9eed1bb9061c9","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"b027ebef-b110-4d69-9fd8-e78b14a128fb"}},"repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"12.2.0","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"_nodeVersion":"24.21.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/eddie-render_0.69.0_1790796310713_0.05063214081460932","host":"s3://npm-registry-packages-npm-production"}},"0.70.0":{"_id":"@brad-frost-web/eddie-render@0.70.0","bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"dist":{"shasum":"9d81e5b6881db2172a41eedd237434980ad385c6","tarball":"https://registry.npmjs.org/@brad-frost-web/eddie-render/-/eddie-render-0.70.0.tgz","fileCount":36,"integrity":"sha512-WaadURCDSOXvIJhiVsXaa+F5JWAnrBSHG+m8mHezDVgRNTfW5YVDH7j7rhEBFMltt5syi0KBYr80QPrSt8W5kw==","signatures":[{"sig":"MEUCIQD09VpOnpOkDtxlgnv7ObcezXCI00PXwlg3Me8egJd45gIgGm0VdjS4rqXWYM6P1ih26jERqF2X2a94Xbw6QiS9lu0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDtAYf6TLcVuOa06i2bjzYp1DeBld1t0ikv8nn3k4xSmAIhANxO6m253FhvhN/q7Q0EQLJAo8WboUWGoS4Uj8AgvEw6"}],"unpackedSize":347907},"main":"dist/index.js","name":"@brad-frost-web/eddie-render","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./composer":{"types":"./dist/composer/index.d.ts","import":"./dist/composer/index.js"},"./validate":{"types":"./dist/validate/index.d.ts","import":"./dist/validate/index.js"},"./package.json":"./package.json","./cdn/eddie-render.js":"./cdn/eddie-render.js"},"gitHead":"605f4fe80385cda6d38200e01c070664b3af7ded","license":"MIT","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc && vite build --config vite.config.cdn.ts","test:watch":"vitest"},"version":"0.70.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"b027ebef-b110-4d69-9fd8-e78b14a128fb"}},"homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"_npmVersion":"12.2.0","description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","directories":{},"maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.1.7","vitest":"^3.2.4","playwright":"^1.56.0","typescript":"~5.9.3","@vitest/browser":"^3.2.4"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eddie-render_0.70.0_1790808746521_0.039457234363829974"}}},"time":{"created":"2026-09-09T13:25:44.796Z","modified":"2026-09-30T22:52:26.737Z","0.65.0":"2026-09-09T13:25:45.449Z","0.66.0":"2026-09-11T05:18:26.307Z","0.67.0":"2026-09-19T09:24:08.513Z","0.68.0":"2026-09-22T17:13:53.875Z","0.69.0":"2026-09-30T19:25:10.798Z","0.70.0":"2026-09-30T22:52:26.600Z"},"bugs":{"url":"https://github.com/Brad-Frost-Web/eddie-design-system/issues"},"license":"MIT","homepage":"https://github.com/Brad-Frost-Web/eddie-design-system#readme","repository":{"url":"git+https://github.com/Brad-Frost-Web/eddie-design-system.git","type":"git","directory":"packages/eddie-render"},"description":"Eddie's generative-UI layer: a surface host that renders a2ui-eddie/1.0 messages and SpecStream patches into Eddie DOM, the spec validator it shares with the Brain, and the composer kit that drives a model against a catalog profile.","maintainers":[{"name":"brad_frost","email":"brad@bradfrost.com"},{"name":"inf5000","email":"inf5000@gmail.com"}],"readme":"# @brad-frost-web/eddie-render\n\n> The browser half of Eddie's generative-UI layer: a **surface host** that\n> turns `a2ui-eddie/1.0` messages and SpecStream patches into Eddie DOM, a\n> **validator** that refuses what the catalog does not allow, and a\n> **composer kit** that streams a model's patches through that validator\n> before anything reaches a page. Zero runtime dependencies.\n\n## Why this exists\n\nA model asked to write a page writes HTML, and HTML has no rails: the\nrealtime-ui pilot's dashboard opened with a hero, invented slot names rendered\nnothing, and the model's own narration (\"I don't have enough context…\") landed\nin the DOM as prose. Every one of those is a *composition* error that the\ndesign system already knows how to refuse, if the vocabulary is the catalog\nrather than the alphabet.\n\nSo the model never writes markup. It emits **patches to a spec** whose nodes\nare the catalog's (`DashboardPage`, `StatCard`, `Text`), a validator checks the\nspec against the catalog's containment, props, slots, and anti-patterns, and\nthe host paints Eddie components by node id. What the catalog forbids cannot be\nexpressed; what it allows renders as the system intended. The strategy is\n`docs/GENERATIVE-UI-STRATEGY.md`; the wire format is `docs/A2UI-EDDIE.md`.\n\n## Three entry points\n\n| Import | Runs in | What it is |\n|---|---|---|\n| `@brad-frost-web/eddie-render` | browser | `createSurfaceHost` plus the spec, patch, and serializer helpers |\n| `@brad-frost-web/eddie-render/validate` | anywhere | `validateSpec`, `toA2uiErrors`, the anti-pattern selector core |\n| `@brad-frost-web/eddie-render/composer` | server | `createComposer`, `buildDigest` — a Messages API client that streams SpecStream lines through the validator |\n\nThe CDN build `cdn/eddie-render.js` carries the first entry point for\nno-build pages.\n\n## The surface host\n\n```js\nimport { createSurfaceHost } from '@brad-frost-web/eddie-render';\n\nconst host = createSurfaceHost(document.getElementById('surface'), {\n  catalog: 'https://ds.bradfrost.com/catalog.json?profile=realtime',\n  scripts: false, // the page already loads Eddie\n  bind: (path) => clientState[path], // resolves { bind: \"client\" } data-model values\n});\nawait host.ready;\n\n// One turn: validate strictly, then commit or refuse.\nconst result = host.apply({\n  version: 'v1.0',\n  createSurface: { surfaceId: 'main', components: [{ id: 'page', component: 'DashboardPage', heading: 'Castle P&L', children: [] }] },\n});\nresult.outcome; // 'committed' | 'refused'\n\n// A streamed turn: paint provisionally as lines land, decide at the end.\nconst turn = host.beginTurn();\nturn.push('{\"op\":\"replace\",\"path\":\"/elements/page/heading\",\"value\":\"Castle P&L, YTD\"}');\nturn.end();\n\nhost.addEventListener('action', (e) => console.log(e.detail)); // A2UI action events\nhost.addEventListener('refusal', (e) => console.log(e.detail.issues));\n```\n\nWhat the host guarantees:\n\n- **Refusal is an outcome, not an exception.** A turn that fails strict\n  validation reverts to the previous spec, keeps the previous DOM, renders the\n  reasons in an `ed-alert` in the refusal region, and emits a `refusal` event.\n- **Untouched nodes keep their element** across updates: scroll position,\n  open accordions, focus. Reconciliation is keyed by node id and resolved\n  props.\n- **A streamed turn paints provisionally** (`data-eddie-provisional` on the\n  host element, hidden placeholders for children that have not arrived) and\n  produces the same DOM one `createSurface` would.\n- **Composition nodes expand** through the catalog's `eddie_expansion`\n  template; primitives render their `eddie_tag` with scalar props as\n  attributes, objects as properties, `accessibility` as ARIA, `action` as an\n  A2UI action.\n- **v0.8 messages still apply** (`surfaceUpdate`, `beginRendering`, the\n  `{ Name: { props } }` component shape), so the hub and Chameleon can migrate\n  on their own schedule.\n\n## The validator\n\n```js\nimport { validateSpec } from '@brad-frost-web/eddie-render/validate';\n\nconst { ok, issues, fixed } = validateSpec(spec, catalog, { autoFix: true, streaming: false });\n```\n\nErrors refuse; warnings render. Codes: `MISSING_ROOT`, `UNKNOWN_COMPONENT`,\n`VALIDATION_FAILED` (required / enum / type; a shape whose schema requires\n`children` and has none is refused outside `streaming`), `UNKNOWN_PROP` (warning; dropped\nunder `autoFix`), `UNKNOWN_SLOT`, `DANGLING_CHILD` (pending while `streaming`),\n`CYCLE`, `DUPLICATE_REFERENCE` (one id placed twice: in `children` and a slot,\nunder two parents, or twice in one list), `UNALLOWED_PARENT`, `UNALLOWED_CHILD`,\n`ORPHAN` (warning),\n`ANTI_PATTERN` (the graph's `@antipattern` rules evaluated on the expanded\ntree), `A11Y` (heading order, one h1, labelled fields). `toA2uiErrors` maps\nissues to A2UI's `error` message. The same function backs the Brain's\n`eddie_validate_spec` MCP tool, and the Brain imports the selector core from\nhere so the two never drift.\n\n## The composer kit\n\n```js\nimport { createComposer } from '@brad-frost-web/eddie-render/composer';\n\nconst composer = createComposer({ catalog, apiKey, model: 'claude-haiku-4-5-20251001' });\nfor await (const ev of composer.compose({ spec, transcript })) {\n  // ev.type: 'patch' | 'reset' | 'refusal' | 'done'\n}\n```\n\nThe digest of the catalog is sent as a cached system block, so an update pays\nfor the transcript and the spec, not the vocabulary. Prose is dropped, a\ntruncated final line is healed, a batch the validator refuses is re-prompted\nonce with the errors, and a turn that still fails leaves the spec untouched and\nreports `mode: 'refused'`. `done` carries the spec, the mode\n(`compose | update | noop | refused`), usage with cache tokens, and the issues.\n\n## Testing\n\n```bash\nnpm test   # Node: spec, validator, composer; Chromium: the surface host\n```\n\nThe validator fixtures are realtime-ui's on-camera failures against the real\n`realtime` catalog, so a catalog change that would let one of them through\nfails here first.\n","readmeFilename":"README.md"}