@adia-ai/adia-ui-forge 0.8.41 → 0.8.42

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adia-ui-kit-forge",
3
- "version": "0.8.41",
3
+ "version": "0.8.42",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "author": {
6
6
  "name": "Kim",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog — adia-ui-kit-forge
2
2
 
3
+ ## [0.8.42] — 2026-08-17
4
+
5
+ ### Maintenance
6
+ - Knowledge packs harvest the ADR-0061..0070 ratifications (PR #1564: gen-ui-wiring + wave-coordination corpora); rename-wave W2 doc migration (PR #1567).
7
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
8
+ - **`skills/` touched in this release window** (7 file(s), e.g. `a2ui-maintenance/SKILL.md`) — carried by the entries above.
9
+
3
10
  ## [0.8.41] — 2026-08-17
4
11
 
5
12
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-forge",
3
- "version": "0.8.41",
3
+ "version": "0.8.42",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "keywords": [
6
6
  "adia-ui",
@@ -41,6 +41,22 @@ surface `catalogId` → error, no registry default). The producer's
41
41
  dialect-shaped; the bridge owns the translation — never hand-write Candidate
42
42
  envelopes from this skill's surfaces.
43
43
 
44
+ site-a2ui (the build-time HTML→A2UI docs-site transpile) is RULED fit as the
45
+ **dialect side's regression corpus**, not a v1.0 conformance bed (ADR-0068):
46
+ it exercises the dialect renderer, the ADR-0061 lifecycle path, and the
47
+ engine transpiler at real-content scale in production, but never touches the
48
+ producer, the bridge, or the `wireFormat` flag — so it neither blocks the
49
+ v1.0 migration nor gets re-pointed at the v1 wire. **Named expiry:** that
50
+ ruling is load-bearing on `wireFormat` defaulting to `'dialect'`; the flag-flip
51
+ ADR that makes `'v1'` the shipping default MUST re-rule site-a2ui's fitness
52
+ (re-point vs retirement-by-attrition) — the fitness verdict expires with the
53
+ `'dialect'` default. Expanding site-a2ui — new message kinds, new consumers,
54
+ or a promotion PROGRAM toward all routes — also invalidates the ruling's
55
+ basis and needs a new decision; burn-down of existing
56
+ `visual-drift`/`blocked-format-gap` rows (including a route thereby becoming
57
+ parity-promoted) is ordinary maintenance and stays permitted (ADR-0068
58
+ Decision 5).
59
+
44
60
  ## Route by task shape
45
61
 
46
62
  | Task shape | Load |
@@ -55,6 +71,7 @@ envelopes from this skill's surfaces.
55
71
  | Add or change an MCP tool | [mcp-tool-reference](references/mcp-tool-reference.md) |
56
72
  | Tune the anti-pattern catalogue | [anti-patterns](references/anti-patterns.md) |
57
73
  | A component's contract can't express a content shape — decide how to extend it | [format-extension-decisions](references/format-extension-decisions.md) |
74
+ | Surface regeneration, pending/stale rendering, the `doc`-setter replace bracket | [surface-lifecycle](references/surface-lifecycle.md) (ADR-0061) |
58
75
 
59
76
  Unmatched work defaults to pipeline-overview and re-classifies from there.
60
77
 
@@ -0,0 +1,73 @@
1
+ # Surface lifecycle — the runtime pending/stale contract (ADR-0061)
2
+
3
+ The renderer runtime (`packages/gen-ui/a2ui/`) owns a per-surface lifecycle
4
+ state machine, ratified by ADR-0061
5
+ (`docs/ops/adr/adr-0061-surface-lifecycle-pending-stale.md`; requirements and
6
+ build order in `docs/ops/spec/spec-a2ui-surface-lifecycle.md`). Load this file
7
+ when a change touches surface regeneration, `<a2ui-root>`'s `doc` setter,
8
+ pending/stale rendering, or a host's update bracketing.
9
+
10
+ ## The state machine
11
+
12
+ ```text
13
+ empty → pending-first → live → pending-stale → live
14
+ └→ error-empty └→ error-stale
15
+ (both error-* heal on the next successful commit)
16
+ ```
17
+
18
+ - **Pending is per-surface, never global.** Each renderer surface record
19
+ carries its own machine; one surface regenerating never dims another.
20
+ - **Latest-generation-wins arbitration.** When two update brackets race on
21
+ one surface, the newest generation's commit wins; a superseded bracket's
22
+ messages are discarded, not interleaved.
23
+ - **Stale content stays visible.** In `pending-stale` and `error-stale` the
24
+ previous answer keeps rendering — the blank-flash reset+replay shape is
25
+ what this contract retired. Error state heals: the next successful commit
26
+ clears `error-*`.
27
+
28
+ ## The host API
29
+
30
+ Four public runtime methods drive the machine — `beginSurfaceUpdate` /
31
+ `applyTo` / `commitSurfaceUpdate` / `abortSurfaceUpdate`. Messages arriving
32
+ inside a bracket buffer and apply atomically at commit. A `replace`-mode
33
+ commit sweeps components the new answer no longer declares — the ONLY place
34
+ removal semantics exist; outside a bracket, `updateComponents` upserts
35
+ exactly as before, so unbracketed streams and hosts are behavior-identical
36
+ to the pre-lifecycle runtime (strictly additive, ADR-0061 Decision 4).
37
+ `<a2ui-root>`'s `doc` setter routes through this replace bracket
38
+ (`replaceDoc`) rather than reset+replay — a deliberate, ratified behavior
39
+ change for doc-setting hosts (ADR-0061 OD-2).
40
+
41
+ ## The DOM contract
42
+
43
+ Staleness is exposed as one attribute plus three events, never styling:
44
+
45
+ - **`data-a2ui-lifecycle`** — a single enum attribute on the surface root
46
+ reflecting the current state. This is the `data-a2ui-*` prefix's FIRST
47
+ ratification (the pre-existing `data-a2ui-surface` stamp was accidental,
48
+ now ratified alongside it) — the runtime-owned `data-*` tier, sibling to
49
+ ADR-0060's trait tier.
50
+ - **Three bubbling CustomEvents** mark the transitions.
51
+ - Hosts and primitives style off the attribute with semantic tokens: stale
52
+ content dims; skeletons (the existing `skeleton` primitive) appear only in
53
+ `pending-first`. `@adia-ai/a2ui` ships state, never styling, and stays
54
+ zero-dependency.
55
+
56
+ ## Layer boundary (ADR-0059)
57
+
58
+ The lifecycle is renderer-runtime work on gen-ui-kit's side of the ADR-0059
59
+ line. The three wire envelope kinds (`beginSurfaceUpdate` /
60
+ `commitSurfaceUpdate` / `abortSurfaceUpdate` as v1.0 server kinds) are a
61
+ genui-system standard PROPOSAL, not dialect schema — `a2ui.schema.json`
62
+ gains nothing, the dialect wire format is byte-identical, and stream-driven
63
+ regeneration waits on the upstream standard (the dialect escape hatch was
64
+ explicitly denied at ratification). Never hand-write lifecycle envelopes
65
+ from this skill's surfaces; the Bridge owns the mapping when the standard
66
+ lands.
67
+
68
+ ## Interlock worth knowing
69
+
70
+ The v1.0 conformance program's duplicate-`surfaceId` error (REQ-002)
71
+ sequences AFTER this API — the silent `createSurface` no-op it removes was
72
+ previously the only wire-visible re-target path, and the lifecycle bracket
73
+ is its sanctioned replacement.
@@ -21,7 +21,7 @@ the live admin-dashboard example.
21
21
  a bare `<nav-ui>` direct child overflows long lists
22
22
  5. Sidebar `<admin-statusbar slot="footer">` with `<select-ui avatar="…">`
23
23
  (user menu) — ★ commonly missing
24
- 6. Sidebar `<div data-resize></div>` — REQUIRED when `resizable` is on
24
+ 6. Sidebar `<div data-sidebar-resize></div>` — REQUIRED when `resizable` is on
25
25
  7. `<admin-content>` inner `<admin-topbar>` containing
26
26
  `<button-ui data-sidebar-toggle="leading" icon="sidebar">` +
27
27
  `<breadcrumb-ui>` + `<span data-spacer>` + `<div data-actions>` —
@@ -234,29 +234,34 @@ correctness rather than just aesthetics), set `shape-rendering: crispEdges`
234
234
  explicitly** — the browser default (`auto`, effectively anti-aliased) is
235
235
  correct for everything else and should stay the default.
236
236
 
237
- ## 8. Attribute-shadowing on SVG-adjacent primitives (ADR-0053/0054)
237
+ ## 8. Attribute-shadowing on SVG-adjacent primitives (ADR-0053/0054/0070)
238
238
 
239
- Two of the pre-existing global-attribute-grammar collisions gh#1335 surfaced
240
- are specifically SVG-rendered primitives, and both cite the SVG-specific
241
- reasoning for their proposed resolution rather than the generic
242
- rename/converge path:
239
+ Two of the global-attribute-grammar collisions gh#1335 surfaced are
240
+ specifically SVG-rendered primitives; both exemptions are **GRANTED**
241
+ (ADR-0070, ratified 2026-08-17), closing the last 2 of gh#1335's 17 and
242
+ emptying `check-attribute-shadowing.mjs`'s `KNOWN_FINDINGS` — the gate now
243
+ enforces via `attribute-api-system.md`'s ratified §11 table alone:
243
244
 
244
245
  - **`qr-code-ui[color]`** — a free-form CSS color string (drives the raw
245
246
  `fill` baked into the generated matrix SVG, §5 above), structurally
246
- identical to the already-ratified `swatch-ui`/`noodles-ui[color]` §11
247
- exemptions ("the component's entire subject is a color") proposed for
248
- the same exemption rather than a rename.
249
- - **`icon-ui[weight]`**Phosphor's icon-rendering weight vocabulary
247
+ identical to the ratified `swatch-ui`/`noodles-ui[color]` §11 exemptions
248
+ ("the component's entire subject is a color"). The exemption covers the
249
+ free-form value space AND the hardcoded `#000000` scanability fallback
250
+ (deliberately never theme-derivedlight-on-dark won't scan), plus its
251
+ contract pairing with `[background]`.
252
+ - **`icon-ui[weight]`** — Phosphor's own glyph-variant vocabulary
250
253
  (`thin/light/regular/bold/fill/duotone`, selecting which pre-rendered SVG
251
- asset variant `getIcon()` loads) is a DIFFERENT CONCEPT from CSS
252
- `font-weight` (`thin/light/normal/medium/semibold/bold`) despite the
253
- shared attribute name gh#1335 names it "the strongest candidate for a
254
- ratified §11 exemption rather than a rename," the same reasoning as
255
- `swatch-ui[color]`.
256
-
257
- Neither is resolved yet (both remain in `check-attribute-shadowing.mjs`'s
258
- `KNOWN_FINDINGS` list per gh#1335) cite this section, not a fresh
259
- investigation, if either surfaces again in a yaml audit.
254
+ set `getIcon()` loads) is a DIFFERENT CONCEPT from CSS `font-weight`
255
+ despite the shared name; the global utility's `font-weight` is inert on
256
+ the inline SVG, so the collision has no cascade effect.
257
+
258
+ Known residual (documented in the §11 justification, accepted not fixed):
259
+ global-only `weight` values (`normal|medium|semibold`) select no Phosphor
260
+ set and fall back to `regular`; a semantic-enum value on `qr-code-ui[color]`
261
+ (`color="danger"`) passes to the SVG fill verbatim, unresolved through
262
+ tokens. Cite this section ADR-0070 — not a fresh investigation, if either
263
+ attribute surfaces again in a yaml audit; the next colliding
264
+ `color`/`weight` on any OTHER component still needs its own ADR.
260
265
 
261
266
  ## When to load this file
262
267
 
@@ -138,7 +138,52 @@ mechanics; never work from this summary alone):
138
138
  the global name always means the global thing. Before minting any attribute
139
139
  in a component yaml, check it against the spec's attribute inventory; the
140
140
  only sanctioned collisions live in the spec's §11 Global-Attribute Exemption
141
- List (first entries: `swatch-ui[color]` / `noodles-ui[color]`, ADR-0054).
141
+ List (first entries: `swatch-ui[color]` / `noodles-ui[color]`, ADR-0054;
142
+ granted since: `qr-code-ui[color]` / `icon-ui[weight]`, ADR-0070).
143
+
144
+ Beyond the global grammar, ADR-0063
145
+ (`docs/ops/adr/adr-0063-attribute-grammar-addendum.md`) ratifies six
146
+ CROSS-SIBLING conventions for component-local attribute naming — the axis
147
+ ADR-0053/0054 don't cover. Any new attribute follows these:
148
+
149
+ - **`no-*` is the canonical negation prefix** — `hide-*` retires
150
+ (`chart[hideAverage|hideGrid|hideValues]` → `no*`, `stream[hide-cursor]`
151
+ → `[no-cursor]`).
152
+ - **Interactivity is opt-in by a positively-named boolean, default `false`**
153
+ (the `stepper-item[interactive]` / `swatch[selectable]` shape) — never
154
+ opt-out. `chart-legend[static]` retires to `[interactive]` (inverted
155
+ default). Applies to single-purpose toggles only — `noodles`'s
156
+ `editable`/`readonly` pair is two orthogonal booleans and stays.
157
+ - **Two sanctioned multi-value encodings, never a hand-rolled delimited
158
+ string:** (a) `multiple` boolean + a structured option model (`select`'s
159
+ `options`/`<option>` shape); (b) a native array-typed JS property,
160
+ JSON-serialized for attribute/form participation (`tags-input`'s
161
+ `.value`). One explicit, operator-ratified EXCEPTION for existing
162
+ components (recorded on gh#1563, 2026-08-17): `segmented-ui[multiple]`'s
163
+ comma-separated value IS accepted as the sanctioned multiple+options
164
+ encoding, and toggle-group's comma-string resolves under that same ruling
165
+ rather than being re-ticketed. This is a ruling on those two existing
166
+ components, not a loophole — a NEW component's multi-value attribute still
167
+ uses form (a) or (b) above, never a delimited string, unless a separate
168
+ ruling says otherwise.
169
+ - **Cross-sibling naming convergence:** `pane[side]` → `pane[edge]`
170
+ (drawer keeps physical `side`); `menu-item[subtitle]` →
171
+ `menu-item[description]` (the ~20-component majority word); `placement`
172
+ ratified as-is for anchored popovers. Documented exception:
173
+ `input[maxlength]` — a primitive wrapping a genuine native `<input>`
174
+ keeps the native attribute's exact casing (ADR-0025/0055 conformance);
175
+ new non-native length constraints use the framework's
176
+ camelCase-property/kebab-attribute pair.
177
+ - **`completed` is the stage-terminal word** for a `status` lifecycle enum
178
+ (`agent-reasoning[status]`'s `done` converges).
179
+ - **`-picker` is reserved for the outer trigger+popover form-associated
180
+ composite** — never the inline substrate it composes. `color-picker-ui`
181
+ (the inline substrate) renames to `color-area-ui`.
182
+
183
+ The renames above are follow-on BUILD work tracked as gh#1563, not yet
184
+ landed in code (compat shims in 0.8.42; breaking cut rides 0.9.0) — when a
185
+ yaml still shows an old name, the ADR is ratified and the code is behind,
186
+ not the other way around.
142
187
 
143
188
  ## When to update this reference
144
189
 
@@ -177,6 +177,79 @@ have no v1.0 sidecar.
177
177
 
178
178
  ---
179
179
 
180
+ ## Semantic color-family axis — two role-classes, two names (ADR-0044, ADR-0064)
181
+
182
+ Every component carries at most one STYLE axis and one FAMILY axis (the
183
+ semantic color family: `default | info | success | warning | danger`,
184
+ `+primary` where the role-class already carries brand emphasis), and every
185
+ enum value belongs to exactly one axis. The family axis's ATTRIBUTE NAME is
186
+ decided by role-class — never one universal name (a same-name meaning-flip
187
+ is a silent-failure migration and poisons the trained corpus, per ADR-0044
188
+ LLD §3):
189
+
190
+ - **Role-class A — `variant` is unclaimed:** the family axis is named
191
+ `variant`. Badge/tag's ratified shape (ADR-0044), plus `rating-ui` and the
192
+ `variant`-only siblings (inline-message, feed-item, empty-state, menu-item,
193
+ progress-row).
194
+ - **Role-class B — an existing identity/style axis already claims the
195
+ selector slot:** the family axis is named `color`. Button's shape
196
+ (`variant`=style, `color`=family), extended by ADR-0064 to `text-ui`
197
+ (`variant`=typography role), `chart-ui`/`heatmap-ui` (`type`=kind),
198
+ `icon-ui` (`weight`=glyph style), `spinner-ui` (`variant`=animation), and
199
+ `toggle-scheme-ui`. Renames owed by this ruling (follow-on build, gh#1376
200
+ — not yet landed): `icon-ui[tone]` → `[color]`, `heatmap-ui[colorScheme]`
201
+ → `[color]`, `spinner-ui[tone]` → `[color]`.
202
+
203
+ `accent` is RETIRED from the family enum everywhere — ADR-0044 removed it
204
+ from badge/tag/button; ADR-0064 removes it from the seven stragglers
205
+ (text, chart, icon, heatmap, rating, spinner, toggle-scheme) with no
206
+ replacement value. Never mint `accent` in a new enum.
207
+
208
+ Two ratified non-family exceptions — the name without the semantics:
209
+
210
+ - `swatch-ui[color]` / `noodles-ui[color]` — an arbitrary CSS color string,
211
+ not a semantic enum (ADR-0054 §11 exemption, unchanged).
212
+ - `spinner-ui[color]` (post-rename) — a closed contrast-mode enum
213
+ (`current | subtle | inverse`), NOT the family vocabulary; never assume it
214
+ accepts `info`/`success`/`warning`/`danger` by analogy.
215
+
216
+ ---
217
+
218
+ ## Catalog tiers — L0–L4, `origin`, and the promotion rule (ADR-0050, ADR-0066)
219
+
220
+ ADR-0050's L0–L4 ladder is the ONLY tier grammar — never mint a second
221
+ manifest format. ADR-0066 refines it three ways:
222
+
223
+ - **`origin: primitive | module` on every L0 entry** — both YAML source
224
+ roots (web-components primitives AND web-modules composites) compile into
225
+ the same `catalog-a2ui_0_9.json` through one shared contract;
226
+ `derive-catalog-tiers.mjs` stamps which root an entry came from onto
227
+ `tier-index.json`. A module is legitimately a member of TWO rungs at two
228
+ grains: its component API (props/events/slots) is L0, its assembled shell
229
+ composition is L3 — ruled correct, not a modeling defect.
230
+ - **The promotion rule, stated once:** patterns/zettel compositions are the
231
+ SOLE promotion source, and they enter the ladder at exactly one point —
232
+ pattern → L1 widget, through `curate-l1-widgets.mjs`'s gates (which writes
233
+ only `l1-widgets.json`). The higher rungs (L1 → L2 → L3 → L4) are AUTHORED
234
+ edges — hand-written `tiers/l*-*.json` manifests whose `composes` reference
235
+ the rung below, reserved/unblocked per ADR-0050's own phasing; a module's
236
+ L3 membership comes from an authored L3 manifest, never from its yaml
237
+ (which contributes only the L0 entry + `origin`). There is no
238
+ patterns↔module edge, primitives and modules never "promote" into each
239
+ other, and nothing promotes automatically or in reverse — curation is the
240
+ one-way valve (ADR-0050: "corpus derives from catalogs, never the
241
+ reverse").
242
+ - **The two pattern-facing outputs stay separate by design:**
243
+ `site/patterns-index.json` / `pattern-index.md` are a generated,
244
+ developer-facing index over the FULL pattern/template census, intentionally
245
+ independent of the L0–L4 machine-validated schema — a different audience,
246
+ never a convergence gap to "fix".
247
+
248
+ (`status:` above is orthogonal to the tier ladder — tier = what an entry is
249
+ composed of; status = how much to trust its contract today.)
250
+
251
+ ---
252
+
180
253
  ## `props:` field — prop schemas
181
254
 
182
255
  Each prop is a top-level key inside `props:`. The full prop schema:
@@ -266,7 +339,7 @@ string-list schema is the exact silent-mismatch shape.
266
339
  | --- | --- | --- |
267
340
  | `[data-col]` | `display: flex; flex-direction: column; gap: var(--page-grid-gap)` | column layout helper |
268
341
  | `[data-row]` | `display: flex; align-items: center; gap: var(--page-grid-gap)` | row layout helper |
269
- | `[data-grid]` | `display: grid; grid-template-columns: 1fr 1fr` (or `1fr 1fr 1fr` for `data-grid="3"`) | 2- or 3-col grid helper |
342
+ | `[data-layout-grid]` | `display: grid; grid-template-columns: 1fr 1fr` (or `1fr 1fr 1fr` for `data-layout-grid="3"`) | 2- or 3-col grid helper |
270
343
  | `[data-actions]` | `display: flex; align-items: center; gap: var(--page-actions-gap)` | action button cluster |
271
344
  | `[data-spacer]` | `flex: 1` | flex spacer for pushing content to edges |
272
345
 
@@ -139,10 +139,18 @@ itself is unavailable.
139
139
  - **`build:site` copies packages but does NOT rebuild their dist bundles** — after
140
140
  component `.css`/`.js` source changes, rebuild first (`npm run build -w
141
141
  @adia-ai/llm`, then `npm run build:bundles`) or the deployed bundles are stale.
142
- - **`scripts/build/site.mjs` is per-package (`copyX()` functions), not glob-based** —
143
- every new or renamed package needs its own copy fn or `dist/` silently omits it
144
- (local Vite works, prod 404s; caused the v0.3.0 `@adia-ai/llm` + `a2ui-runtime`
145
- deploy gaps). After any package add/rename, check `site.mjs` before deploying.
142
+ - **Package registration is one manifest, `scripts/build/site-package-registry.mjs`
143
+ (ADR-0062)** every `@adia-ai/*` package the site ships is one registry entry, from
144
+ which the dist copy, BOTH importmaps (one shared `renderImportMapBlock()` the
145
+ `site/index.html` copy is a generated artifact, `npm run build:site-importmap`),
146
+ the `dist/node_modules` symlinks, and the CI build order all derive. The old
147
+ failure class (per-package `copyX()` hand-edits; local Vite works, prod 404s —
148
+ v0.3.0 llm/a2ui-runtime, v0.8.27 persona+agent) is gated mechanically:
149
+ `check:site-packages-registered` scans every shipped source root for an
150
+ unregistered bare `@adia-ai/*` import and fails naming file:line, alongside
151
+ `check:site-importmap-fresh` and `check:deploy-workflow-build-order` — all three
152
+ in `npm run check` and early in `deploy-site.yml`. After any package add/rename,
153
+ add the registry entry; the gates say the rest.
146
154
  2. **Dry-run first, and adjudicate every delete — BEFORE the real rsync, never after:**
147
155
  ```sh
148
156
  rsync -azni --delete --exclude='packages/gen-ui/a2ui/corpus/feedback/' \