@adia-ai/a2ui-runtime 0.6.32 → 0.6.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog — @adia-ai/a2ui-runtime
2
2
 
3
+ ## [0.6.33] — 2026-05-23
4
+
5
+ ### Fixed — card-ui body-slot drift closed across runtime + fixtures
6
+
7
+ - **`renderer.js`** — card-ui body-slot resolution now respects the canonical `<card-ui><section>…</section></card-ui>` shape across all render paths. Runtime previously produced inconsistent body-slot wrapping for some A2UI tree shapes, causing visual fixture drift in eval-076, eval-082, eval-090, eval-099 visual goldens. Fix: 70-line resolver change in `renderer.js` aligns runtime output with the documented card body-slot contract. Companion eval visual goldens regenerated (4 PNGs). Audit script `scripts/audit/audit-card-structure.mjs` extended with the new contract. Files: `packages/a2ui/runtime/renderer.js`.
8
+
9
+ ## [0.6.32] — 2026-05-23
10
+
11
+ ### Maintenance
12
+
13
+ - **Lockstep version bump only.** No source changes in this package; bumped to maintain the 9-package version coherence enforced by `scripts/release/check-lockstep.mjs`. Substantive v0.6.32 work shipped in `@adia-ai/web-modules` (`everything.js` CDN entry + `admin-shell.helpers.css` scoping) and `@adia-ai/web-components` (FB-51 `everything.js` primitive bundle fix + status:stable yaml sweep). See those packages' CHANGELOGs for details.
14
+
3
15
  ## [0.6.31] — 2026-05-23
4
16
 
5
17
  ### Maintenance
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/a2ui-runtime",
3
- "version": "0.6.32",
3
+ "version": "0.6.33",
4
4
  "description": "A2UI runtime \u2014 renderer, registry, streams, surface manifest, and wiring primitives for the A2UI (Agent-to-UI) protocol. Framework-agnostic; pairs with any A2UI-conformant component set.",
5
5
  "type": "module",
6
6
  "exports": {
package/renderer.js CHANGED
@@ -171,6 +171,13 @@ export class A2UIRenderer {
171
171
  }
172
172
  }
173
173
 
174
+ // Structural validation: warn when Card/Drawer body content skips
175
+ // the canonical <Section> wrap. Mirrors scripts/audit/audit-card-structure.mjs
176
+ // (which scans authored HTML) — this hook catches runtime-built trees
177
+ // where the audit can't see. See feedback_card_drawer_body_section_wrap
178
+ // memory + packages/web-components/components/{card,drawer}/yaml.
179
+ this.#validateContainerStructure(components);
180
+
174
181
  // Build parent map for cycle detection
175
182
  const parentMap = new Map();
176
183
  for (const comp of components) {
@@ -228,6 +235,69 @@ export class A2UIRenderer {
228
235
  }
229
236
  }
230
237
 
238
+ // ── Structural validation (Card / Drawer body contract) ──
239
+
240
+ static #CARD_CANONICAL_CHILDREN = new Set([
241
+ 'Header', 'Section', 'Footer',
242
+ // Media-first siblings (mirrors audit-card-structure.mjs whitelist):
243
+ // void/media elements may sit as siblings of header/section/footer.
244
+ 'Img', 'Image', 'Video', 'Picture', 'Iframe',
245
+ // Layout siblings:
246
+ // Aside — "card with side nav" pattern per aside.yaml.
247
+ // Divider — visual rule between sibling content blocks (pricing-tier
248
+ // pattern in eval-025).
249
+ 'Aside', 'Divider',
250
+ ]);
251
+
252
+ static #DRAWER_CANONICAL_CHILDREN = new Set([
253
+ 'Header', 'Section', 'Footer',
254
+ ]);
255
+
256
+ // Slot values that opt a child into a canonical body slot
257
+ // (drawer-ui supports explicit [slot="header|body|footer"]; card-ui
258
+ // accepts header/section/footer children for the same slots).
259
+ static #CANONICAL_SLOT_VALUES = new Set(['header', 'body', 'footer']);
260
+
261
+ #warnedStructure = new Set();
262
+
263
+ #validateContainerStructure(components) {
264
+ const componentsById = new Map();
265
+ for (const comp of components) {
266
+ if (comp.id != null) componentsById.set(comp.id, comp);
267
+ }
268
+
269
+ for (const comp of components) {
270
+ const isCard = comp.component === 'Card' || comp.component === 'ErrorContainer';
271
+ const isDrawer = comp.component === 'Drawer';
272
+ if (!isCard && !isDrawer) continue;
273
+
274
+ const allowed = isDrawer
275
+ ? A2UIRenderer.#DRAWER_CANONICAL_CHILDREN
276
+ : A2UIRenderer.#CARD_CANONICAL_CHILDREN;
277
+ const containerLabel = isDrawer ? '<drawer-ui>' : '<card-ui>';
278
+
279
+ const childIds = Array.isArray(comp.children) ? comp.children : [];
280
+ for (const childId of childIds) {
281
+ const child = componentsById.get(childId);
282
+ if (!child) continue;
283
+ // Allow if child has slot attribute matching canonical body slots
284
+ if (typeof child.slot === 'string'
285
+ && A2UIRenderer.#CANONICAL_SLOT_VALUES.has(child.slot)) continue;
286
+ if (allowed.has(child.component)) continue;
287
+
288
+ const key = `${comp.id}::${childId}::${child.component}`;
289
+ if (this.#warnedStructure.has(key)) continue;
290
+ this.#warnedStructure.add(key);
291
+ console.warn(
292
+ `A2UI: ${containerLabel} (id="${comp.id}") body must wrap "${child.component}" ` +
293
+ `(id="${childId}") in <Section>. Direct flow children bypass the canonical body ` +
294
+ `slot and lose --card-inset margin. Canonical children: ${[...allowed].join(', ')}` +
295
+ (isDrawer ? `, or slot="header|body|footer".` : `.`)
296
+ );
297
+ }
298
+ }
299
+ }
300
+
231
301
  // ── Apply props ──
232
302
 
233
303
  static #JS_PROPS = new Set(['data', 'columns', 'options', 'itemRenderer', 'textContent']);