@adia-ai/adia-ui-forge 0.8.57 → 0.8.58

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.
@@ -65,7 +65,7 @@ has no standing replacement — see ADR-0072 Decision 2 / gh#2410 for the
65
65
  closure record.
66
66
 
67
67
  All paths repo-relative. Specs worth reading before structural changes:
68
- `.claude/docs/specs/a2ui-v0.9-catalog-guide.md` (protocol + catalog format),
68
+ `.claude/docs/specs/a2ui-v1.0-catalog-guide.md` (protocol + catalog format),
69
69
  `.claude/docs/specs/genui-multiturn-architecture.md` (state cache, refiner,
70
70
  op format), `.claude/docs/specs/genui-chunk-marker.md` (chunk attributes),
71
71
  `.claude/docs/conventions/gen-ui-pipeline.md` (harvester wiring + embedding
@@ -30,7 +30,15 @@ the live admin-dashboard example.
30
30
  (there is no `<theme-picker-ui>`)
31
31
  9. `<admin-scroll>` wrapping optional `<aside data-subnav hidden>` +
32
32
  `<router-ui>` (or `<admin-page>` directly for non-routed)
33
+ **[deprecated 2026-09-01, ADR-0098]** `admin-scroll` is a wholesale
34
+ rename to `page-scroll` (both modes carried over); `admin-scroll` stays
35
+ as a working compat alias for the deprecation window only.
33
36
  10. `<admin-page>` with `<admin-page-header>` + `<admin-page-body>`
37
+ **[deprecated 2026-09-01, ADR-0098]** The `admin-page` family is
38
+ retired deprecate-then-delete in favor of `page-ui[band]` — `page-ui`
39
+ is now the one canonical page-chrome primitive; this anatomy still
40
+ describes the pre-migration shape for auditing legacy surfaces during
41
+ the deprecation window.
34
42
  11. `<admin-statusbar>` at content footer (version strip) — ★ commonly missing
35
43
  12. Second `<admin-sidebar slot="trailing">` (inspector rail, hidden by
36
44
  default) — strongly recommended
@@ -56,7 +64,7 @@ the live admin-dashboard example.
56
64
  | content topbar missing `[data-spacer]` / `[data-actions]` | warning — part 7 |
57
65
  | content missing trailing `<admin-statusbar>` | warning — part 11 |
58
66
  | sidebar topbar contains only plain text | warning — part 3 context switcher |
59
- | `<admin-scroll>` missing around `<admin-page>` | critical — part 9 (the enforcing script `audit-shell-composition.mjs` tiers this critical: without the scroll+page wrapper the content renders flush with the topbar, no margins) |
67
+ | `<admin-scroll>` missing around `<admin-page>` | critical — part 9 (the enforcing script `audit-shell-composition.mjs` tiers this critical: without the scroll+page wrapper the content renders flush with the topbar, no margins) — **[deprecated 2026-09-01, ADR-0098]** `admin-scroll`/`admin-page` describe the pre-migration shape; the successor is `page-scroll` wrapping `page-ui[band]` |
60
68
 
61
69
  ## Opt-out contract
62
70
 
@@ -20,7 +20,7 @@ may stall — wait 30s, re-run.
20
20
  | 4 | Top-level `await` without async setup wrap | `[setup-failed]` console error | `export default async function setup(host) { … }` |
21
21
  | 5 | Vite import-analysis 500 on dynamic import | `[network-4xx] 500` for `./<name>.contents.js` | add `/* @vite-ignore */` to the dynamic import |
22
22
  | 6 | icon-ui not imported despite `<icon-ui>` / `[icon=…]` / icon-rendering composites | `[icon-ui-missing]` | `import "/packages/web-components/components/icon/icon.js"` |
23
- | 7 | `<admin-page-body>` emitted without its `<admin-page>` ancestor (gh#981) | *(no audit-app-shells.mjs tag — apps/-only script, doesn't sweep this surface)* | wrap in `<admin-page>` — `admin-page > admin-page-body { flex:1; … }` (`admin-shell.bespoke.css:144`) is a direct-child selector; without that literal parent, `admin-page-body` falls back to UA `display:inline` |
23
+ | 7 | `<admin-page-body>` emitted without its `<admin-page>` ancestor (gh#981) | *(no audit-app-shells.mjs tag — apps/-only script, doesn't sweep this surface)* | wrap in `<admin-page>` — `admin-page > admin-page-body { flex:1; … }` (`admin-shell.bespoke.css:144`) is a direct-child selector; without that literal parent, `admin-page-body` falls back to UA `display:inline` — **[deprecated 2026-09-01, ADR-0098]** `admin-page`/`admin-page-body` are retired deprecate-then-delete; author new surfaces with `page-ui[band]` instead |
24
24
 
25
25
  Secondary signals: `[collapsed-element]` (registered but 0px tall —
26
26
  `audit-app-shells.mjs`'s own threshold is <4px, so a shallower-but-still-broken
@@ -137,6 +137,9 @@ node scripts/release/check-estate-split-latch.mjs # 29 no lockstep cut
137
137
  npm run check:catalog-tiers # 30 tier-index.json vs committed catalog (gh#1494 — ADR-0069 moved its PR-blocking half to derived-resync; the pre-cut roster re-asserts Class-R freshness before a tag. Gate 13 can't catch this: the harvester hashes tier-index.json as a SOURCE)
138
138
  npm run check:codex-manifests-fresh # 31 Codex plugin.json + openai.yaml vs .claude-plugin/plugin.json SoT (gh#1888)
139
139
  npm run check:harness-manifests-fresh # 32 Hermes/Pi plugin.yaml + __init__.py + prompts vs .claude-plugin/plugin.json + commands SoT (gh#1954)
140
+ npm run verify:patterns-index # 33 pattern-index.md (mcp + adia-ui-factory) vs corpus source
141
+ node scripts/release/check-yaml-events-vs-runtime.mjs --strict --strict-details # 34 yaml events: blocks vs runtime dispatch — no phantom/missing events (gh#2829)
142
+ node scripts/release/check-yaml-impl-coverage.mjs --strict # 35 yaml schema fields vs implementation coverage (gh#2829)
140
143
  ```
141
144
 
142
145
  **Gate 29 was the ADR-0048 latch; since P5 it is a permanent invariant.** Between P1 and P5 the repo was correct in-repo but deliberately **not publishable** (old-name stubs marked `private: true` that the roster still mapped, plus dependency edges onto workspace packages no cut published), and a cut in that window would have shipped broken packages that npm cannot unpublish. **P5 cleared it by landing the real thing** — the six stubs became publishable shims and `PACKAGE_ROSTER` gained the three remaining new names, at which point all 9 offending edges resolved and the gate went green on its own. No gate logic was changed.
@@ -437,6 +440,28 @@ Deploy discipline (the release tenant of the demo-site host; VM/service ops belo
437
440
 
438
441
  - Any docs **route** cited to the operator or in notes must exist in `site/sitemap.json` (`grep '"path":'`) — a plausible-looking route that isn't in the sitemap renders blank.
439
442
 
443
+ **Milestone close (ADR-0103, gh#2729, dated addendum 2026-09-01).** Every
444
+ lockstep cut has an open GitHub Milestone named `vX.Y.Z` (one per cut,
445
+ created ahead of time or by the first PR scheduled into it). Close it here,
446
+ after the GH releases above and before release notes:
447
+
448
+ ```bash
449
+ number=$(gh api repos/adiahealth/gen-ui-kit/milestones --jq \
450
+ '.[] | select(.title == "vX.Y.Z") | .number')
451
+ gh api -X PATCH "repos/adiahealth/gen-ui-kit/milestones/$number" -f state=closed
452
+ ```
453
+
454
+ Any issue still open in that milestone at close time either ships anyway
455
+ (re-tag it into the milestone that actually shipped it — never leave an
456
+ already-shipped issue's milestone wrong) or slips to the next milestone
457
+ (re-tag now, don't leave the closed milestone showing open issues). Create
458
+ the NEXT cut's milestone here too, so scheduling work for it doesn't wait on
459
+ this cut's tag:
460
+
461
+ ```bash
462
+ gh api repos/adiahealth/gen-ui-kit/milestones -f title="vNEXT.Y.Z" -f state=open
463
+ ```
464
+
440
465
  Any Step-2 stashes: `git stash pop`; flag conflicts to the operator.
441
466
 
442
467
  ## §Step 11 — Author release notes (default)
@@ -155,6 +155,14 @@ export const GATE_ROSTER = [
155
155
  // manifest trees. Appended, not inserted — same numbering discipline as
156
156
  // gate 30/31/32.
157
157
  { n: 33, cmd: 'npm run verify:patterns-index', what: 'pattern-index.md (mcp + adia-ui-factory) vs corpus source' },
158
+ // gh#2829: gh#2808/PR #2815 (ADR-0108 ticket 3) promoted both yaml gates
159
+ // below into `npm run check` but deliberately left this pre-cut roster
160
+ // untouched — a cut could still ship a yaml `events:` block that phantoms
161
+ // or misses a runtime dispatch, or a schema field with no implementation
162
+ // coverage, without either failing the pre-flight. Appended, not
163
+ // inserted — same numbering discipline as gate 30/31/32/33.
164
+ { n: 34, cmd: 'node scripts/release/check-yaml-events-vs-runtime.mjs --strict --strict-details', what: 'yaml events: blocks vs runtime dispatch (no phantom/missing events)' },
165
+ { n: 35, cmd: 'node scripts/release/check-yaml-impl-coverage.mjs --strict', what: 'yaml schema fields vs implementation coverage' },
158
166
  ];
159
167
 
160
168
  // -- CLI ------------------------------------------------------------------
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: primitive-authoring
3
3
  description: >-
4
- Author or modify AdiaUI framework source inside the monorepo — primitives
4
+ Author or modify AdiaUI framework source inside the monorepo — components
5
5
  (packages/web-components), shells/composites (packages/web-modules), yaml
6
- SoTs, demos. Use to add a new primitive, fix a prop/slot/attribute/CSS
6
+ SoTs, demos. Use to add a new component, fix a prop/slot/attribute/CSS
7
7
  variant, update a yaml, build or fix a shell (chat-shell, admin-shell,
8
8
  editor-shell — sidebar/pane/bespoke-tier composition), promote repeated
9
9
  inline content into a shared module, audit a component's four-axis
@@ -100,5 +100,8 @@ then the full sequence — never suppress.
100
100
  [authoring-cycle.md](references/authoring-cycle.md) Step 3 are fixed
101
101
  immediately; contract-neutral pattern drift is proposed in review, not
102
102
  blocked on.
103
+ - **SoT-change / component.md check**: new or changed states or aria
104
+ behavior on a yaml with a `component.md` sibling → component-md-authoring's
105
+ authored `screenReader`/`behavioral` sections may need a pass.
103
106
  - A one-line bug that touches no props, CSS contract, or lifecycle doesn't
104
107
  need this skill's overhead — just read the code and edit.
@@ -1,3 +1,3 @@
1
1
  interface:
2
2
  display_name: "Primitive Authoring"
3
- short_description: "Author or modify AdiaUI framework source inside the monorepo — primitives (packages/web-components), shells/composites (packages/web-modules), yaml SoTs, demos."
3
+ short_description: "Author or modify AdiaUI framework source inside the monorepo — components (packages/web-components), shells/composites (packages/web-modules), yaml SoTs, demos."
@@ -646,6 +646,46 @@ If you author a primitive that programmatically creates another (`document.creat
646
646
 
647
647
  Source: ADR-0027.
648
648
 
649
+ ### AP-R2 · Folding two visually-converging widgets into a shared module (ADR-0101)
650
+
651
+ Two widgets can converge visually — same tab-strip chrome, same header
652
+ band, same "looks like the same component" impression on the catalog page
653
+ — while carrying fundamentally different content models underneath. That
654
+ visual overlap alone is not sufficient reason to extract a shared module
655
+ or fold one into the other.
656
+
657
+ `inspector-ui` (a live devtools pane: four fixed panes, content pushed in
658
+ imperatively and repeatedly after connect via `update()`/`setHTML()`) and
659
+ `preview-ui` (static docs demo chrome: content captured once on connect,
660
+ shown two fixed ways) look like the same tabbed-view widget. They aren't:
661
+ folding one into the other would force the static-capture component to
662
+ grow a second, incompatible imperative-update mode it doesn't need for the
663
+ job it already does correctly everywhere it's used — added surface, not
664
+ removed surface. Extracting a shared tab-view module was evaluated and
665
+ rejected for the same reason: no common substrate exists beneath the
666
+ visual layer that both widgets could share without also merging their
667
+ different content models (`tabs-ui`'s synthesized strip vs. a hand-rolled
668
+ `role="tablist"` div built for single-panel content-swap semantics).
669
+
670
+ **The resolution is a mirror, not a merge:** keep both components on their
671
+ own contracts; restyle the trailing one to match the leading one's chrome
672
+ via scoped CSS only (`@scope (inspector-ui)` overrides copying
673
+ `preview-ui`'s header-tab anatomy, tokens, and typography) — no shared
674
+ component, no deprecation. The tradeoff this accepts: because the
675
+ mirroring is duplicated CSS, not a shared module, a future visual change
676
+ to the pattern's source component doesn't automatically propagate: check
677
+ the mirrored block for parallel drift when you next touch the pattern
678
+ that's being mirrored — the same "primitives that compose primitives
679
+ don't auto-import" discipline ADR-0027 already requires (AP-R1, above),
680
+ now applied to a duplicated CSS block instead of a duplicated import.
681
+
682
+ Before extracting a shared module for two things that "look the same,"
683
+ verify they'd actually share the extracted contract (props, update
684
+ semantics, lifecycle) — not just its rendered chrome. If they wouldn't,
685
+ mirror the chrome and keep both components separate.
686
+
687
+ Source: ADR-0101.
688
+
649
689
  ---
650
690
 
651
691
  ## Rapid-fire anti-patterns (mined from incident history)
@@ -62,6 +62,18 @@ Every component CSS file has exactly this shape:
62
62
 
63
63
  When a parent tries to override `--component-bg`, specificity beats them. The zero-specificity layer is the contract.
64
64
 
65
+ ## Region elements never self-style (2026-09-01, ADR-0105)
66
+
67
+ Native `<header>`/`<section>`/`<footer>` and `<header-ui>`/`<section-ui>`/`<footer-ui>` (a CSS-only slot-routing anatomy stub — no JS, no events, no `.css` file of its own) are **region elements**, not components in their own right. They carry zero layout CSS. Every grid, gap, sticky rule, and slot-vocabulary variant a region renders is written in the **closest host pattern's** `@scope (host-name)` block — `page-ui`, `card-ui`, `drawer-ui`, `modal-ui`, `anchor-bar`, the shells — matching the region by tag + attribute selector (`:scope > :where(header, header-ui)`, `:has(> [slot="action"])`, etc.), never in a region-owned stylesheet.
68
+
69
+ **If you're authoring a new host pattern that accepts region children, you MUST ship its `@scope` treatment for every region shape it accepts before it ships.** A host that accepts `<header-ui>` without a matching grid/sticky/slot-vocabulary block is not a lesser-but-valid host — the region element structurally cannot supply the missing layout itself, so the host renders wrong (usually unstyled block flow, or — the observed failure mode — a stale layout that packs content into the wrong shape). gh#2760 is the live example: `page-ui`'s header-band `@scope` block didn't reproduce the retired `admin-page-header`'s action-cluster grid for a multi-item `[slot="action"]` containing a block-level `<tabs-ui>`, so tabs overlapped buttons instead of getting their own row — same markup, incomplete host coverage.
70
+
71
+ **Bare `<header>` vs `<header-ui>`** — both reach a host's tag-matched rules identically (`:where(header, header-ui, …)` gives them equal zero specificity). They diverge only on rules keyed off a named-slot attribute selector (`:has(> [slot="icon"])`, etc.) — and there the divergence isn't mechanical (`slot=` is decorative everywhere, ADR-0033), it's documentation: `header-ui`'s own yaml is the only place the icon/heading/description/action vocabulary is written down and steered toward by `a2ui.rules`. Use bare `<header>`/`<section>`/`<footer>` only for unstructured default-slot content; use the `-ui` stub whenever content decomposes into the slot vocabulary — that's the only path an author or the A2UI generator discovers it exists.
72
+
73
+ A region element acquiring its own `.css` file (layout rules scoped to `header-ui` itself, not the host) is the anti-pattern this section exists to name — see ADR-0105 for the full rationale and the corollary above.
74
+
75
+ Source: [ADR-0105](../../../../../../docs/ops/adr/adr-0105-region-elements-never-self-style.md).
76
+
65
77
  ## Variants vs modes — the decision tree
66
78
 
67
79
  The rule: **variants change tokens; modes change layout.**
@@ -31,6 +31,16 @@ Decision Class 1 removes the 20ch-class field-width floor for
31
31
  floor, generalizing the `button-ui` keep-square pattern already named below
32
32
  to the field-width components.
33
33
 
34
+ **[amended 2026-08-31, gh#2534, ADR-0095]** The square-minimum rule governs
35
+ a primitive's own OUTER inline-size floor against its own block-size only —
36
+ it does not reach a component's INTERNAL grid-column sizing. A token like
37
+ `field-ui[inline]`'s `--field-label-inline-min: 10ch` floors the label
38
+ *column* inside the component's internal grid, to keep sibling rows
39
+ aligned — not to prevent the host itself from collapsing — so it is not
40
+ "a `--*-min-width: 20ch`-class floor" in ADR-0095's sense and is not
41
+ retired by the Decision above. Don't apply the square-minimum rule to an
42
+ internal grid-column token by analogy to the field-width class.
43
+
34
44
  *(Historical, pre-ADR-0095 rule — superseded by the retirement above, kept
35
45
  only for context on what the old convention was.)* A
36
46
  `--*-min-width: 20ch`-class floor (the gh#781/gh#1633 pattern on
@@ -448,6 +448,13 @@ Consumers (CodeMirror layout, canvas redraw, dependent UI) listen on the shell o
448
448
 
449
449
  ### admin cluster (canonical reference)
450
450
 
451
+ **[deprecated 2026-09-01, ADR-0098]** `admin-page`/`admin-page-header`/
452
+ `admin-page-body` are retired deprecate-then-delete; `admin-scroll` is
453
+ renamed wholesale to `page-scroll`. `page-ui[band]` + `page-scroll` are
454
+ now the canonical page-chrome pair — this cluster still describes
455
+ `admin-shell`'s pre-migration internal composition, valid during the
456
+ deprecation window.
457
+
451
458
  - **3 JS-bearing children** — `<admin-shell>` (host coordinator), `<admin-sidebar>` (resize+collapse+persist), `<admin-command>` (Cmd+K palette)
452
459
  - **7 CSS-only structural children** — `<admin-content>`, `<admin-topbar>`, `<admin-statusbar>`, `<admin-scroll>`, `<admin-page>`, `<admin-page-header>`, `<admin-page-body>`
453
460
  - **CSS bridge** — `packages/web-modules/shell/admin-shell/css/admin-shell.bespoke.css` (~240 LOC)
@@ -547,7 +554,7 @@ When you encounter a legacy reference in old documentation or commit history, th
547
554
 
548
555
  - [authoring-cycle.md](authoring-cycle.md) — general 5-step authoring procedure; shell-specific rules layer on top
549
556
  - [api-contract.md](api-contract.md) — prop naming, reflection policy
550
- - [css-patterns.md](css-patterns.md) — two-block `@scope`, variants vs modes
557
+ - [css-patterns.md](css-patterns.md) — two-block `@scope`, variants vs modes; §Region elements never self-style (ADR-0105) — a shell that hosts `<header-ui>`/`<section-ui>`/`<footer-ui>` region children (e.g. a bespoke `<X-header>` wrapping one) owns their `@scope` layout the same way `page-ui`/`card-ui`/`drawer-ui`/`modal-ui` do
551
558
  - [lifecycle-patterns.md](lifecycle-patterns.md) — teardown patterns; the cleanup-closure pile and document-listener rules above layer on top
552
559
  - [token-contract.md](token-contract.md) — zero-raw-color + L3 alias rules apply identically to shells
553
560
  - [module-promotion.md](module-promotion.md) — the _different_ activity of lifting a cross-cluster reusable element (theme panel, command palette) into a shared module
@@ -36,6 +36,23 @@ Every component's `.css` file must follow the **two-block @scope** pattern:
36
36
  }
37
37
  ```
38
38
 
39
+ ### `@scope` donor selectors must be tag-independent when a component can swap its own rendered tag (ADR-0102, 2026-09-01)
40
+
41
+ A `@scope (my-component-ui)` donor selector matches by **literal tag
42
+ name**. That's a live gap for any component whose own contract lets it
43
+ render as a different tag than its own custom-element name — `text-ui`
44
+ already did this coincidentally (`variant="body"` → `<p>`,
45
+ `variant="caption"` → `<small>`), relying on ambient/bare-tag styling
46
+ rather than the component's own `[variant]` rules. ADR-0102 (`text-ui`'s
47
+ `level` prop, promoting the element to a real `<h1>`-`<h6>`) made this a
48
+ first-class case, requiring the donor selector to stay tag-independent —
49
+ e.g. `@scope (text-ui, [data-text])` with the renderer stamping a stable
50
+ marker attribute on every such element regardless of the resolved tag —
51
+ so a promoted `<h2 level="2" variant="heading">` keeps its component
52
+ styling instead of silently falling back to bare-tag `:where(hN)`
53
+ defaults elsewhere in the cascade. Any component that can render under a
54
+ tag other than its own name needs the same tag-independent scope check.
55
+
39
56
  ## Hard rules
40
57
 
41
58
  1. **Zero raw color values** anywhere in component CSS
@@ -139,7 +156,8 @@ mechanics; never work from this summary alone):
139
156
  in a component yaml, check it against the spec's attribute inventory; the
140
157
  only sanctioned collisions live in the spec's §11 Global-Attribute Exemption
141
158
  List (first entries: `swatch-ui[color]` / `noodles-ui[color]`, ADR-0054;
142
- granted since: `qr-code-ui[color]` / `icon-ui[weight]`, ADR-0070).
159
+ granted since: `qr-code-ui[color]` / `icon-ui[weight]`, ADR-0070;
160
+ `badge-ui[weight]` → `icon-ui[weight]`, ADR-0100).
143
161
 
144
162
  Beyond the global grammar, ADR-0063
145
163
  (`docs/ops/adr/adr-0063-attribute-grammar-addendum.md`) ratifies seven
@@ -401,6 +401,22 @@ already has). As of this writing `deriveProps()` still synthesizes only the
401
401
  three props above and `catalog-validator.js` has no trait-name check —
402
402
  gh#2513 tracks the build.
403
403
 
404
+ ### Sentinel-0 defaults and tag-promoting props (ADR-0102, 2026-09-01)
405
+
406
+ Not every escape hatch belongs on `CatalogComponentCommon` — a prop scoped
407
+ to one component's own semantics stays on that component's own yaml, even
408
+ when it changes the rendered tag. `text-ui`'s `level` (integer 0-6,
409
+ default `0`) is the worked example: `0` is the sentinel for "no
410
+ promotion, current behavior" — the same `0 = off` convention `text-ui`'s
411
+ own `lines` prop already used (`lines: 0` = no clamp) — and `1`-`6`
412
+ promotes the rendered element to a real native `<h1>`-`<h6>`, independent
413
+ of `variant` (which stays presentational-only: typography tokens, never a
414
+ tag). `deriveProps()` needs no change for this — a per-sidecar prop like
415
+ `level` already flows into the generated catalog schema generically; only
416
+ a `CatalogComponentCommon` universal (`slot`/`hidden`/`ariaLive`/`traits`,
417
+ above) needs a wire-schema edit. See ADR-0102 for the full contract
418
+ (renderer branch, dead-code removal, non-goals).
419
+
404
420
  ### `required: true` field
405
421
 
406
422
  **When to use**: only for props where omitting them makes the component meaningless or inaccessible.