@adia-ai/adia-ui-forge 0.8.54 → 0.8.56

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.54",
3
+ "version": "0.8.56",
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-ui-kit-factory (the consumer/app-author plugin).",
5
5
  "author": {
6
6
  "name": "Kim",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adia-ui-kit-forge",
3
- "version": "0.8.54",
3
+ "version": "0.8.56",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself — 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-ui-kit-factory (the consumer/app-author plugin).",
5
5
  "author": {
6
6
  "name": "Kim",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog — adia-ui-kit-forge
2
2
 
3
+ ## [0.8.56] — 2026-08-31
4
+
5
+ ### Added
6
+ - **New `component-md-authoring` skill (gh#2615).** Authors the two judgment sections of a component's `component.md` — Screen-reader spec and Behavioral spec — typed directly into the yaml's new `screenReader:`/`behavioral:` fields (component.md itself is a generated shell, never hand-edited). Sits next to `primitive-authoring` in `packages/plugins/adia-ui-forge/skills/`; Codex (`agents/openai.yaml`) and Hermes/Pi (`__init__.py`) manifests regenerated to register it.
7
+ - **`primitive-authoring`'s `yaml-contract.md` gains a semantic-id grammar for `examples[].a2ui` component ids (gh#2492 Phase 1).** The `.claude/docs/specs/a2ui-editor.md:170` "free-form" id convention was written for editor-generated ids only, not authored yaml examples — reading it as license for both produced a corpus-wide drift toward cryptic, positional ids (`q`, `k1`, `k1v`) reported against `blockquote.yaml`, `badge.yaml`, `aside.yaml`, `alert.yaml`, and `anchor-bar.yaml`. New `## examples: field` section documents the grammar (kebab-case, role-descriptive, unique per example, a short-real-word root/wrapper exception) with before/after examples; `a2ui-editor.md:170` amended to scope its own claim to editor-generated ids and cross-reference the new grammar. Phase 2 (a separate dispatch) sweeps the corpus to match.
8
+ - **Phase 2 (gh#2492): the corpus-wide sweep landed and `check-example-ids.mjs` flips from advisory to `npm run check:example-ids:strict` in the `npm run check` chain.** 526 violations across 48 yamls (`packages/web-components`, `packages/web-modules`) renamed to the Phase 1 grammar — see `packages/web-components/CHANGELOG.md` and `packages/web-modules/CHANGELOG.md` for the file list. `yaml-contract.md`'s `## examples: field` section updated to describe the gate as enforced, plus a noted known gap (the checker's positional regex doesn't catch a `letter-digit-letter-digit` chain like `g1i1`, out of scope for this sweep since nothing flagged it). `check-example-ids.mjs` itself gained an entrypoint guard (`if (import.meta.url === ...)`) — the CLI's `main()` was running as a side effect of importing `checkExampleIds` as a library function, which the sweep tooling does.
9
+
10
+ ### Fixed
11
+ - **`package-release`'s Step 5 staging allowlist was missing the factory README's own prose echo of the generation-MCP pin — bump.mjs's `A2UI_MCP_PIN` rewrites both `adia-ui-factory/.mcp.json` and its README, but Step 5 only ever staged `.mcp.json`, so the README edit rode uncommitted through every cut (gh#2473).** `release-pack.mjs`'s Step 5 now also stages `packages/plugins/adia-ui-factory/README.md`. Added a new Step 5.6 unstaged-tracked-files guard right after staging (numbered 5.6, not 5.5 — `cut-procedure.md`'s own §Step 5.5 already names a different, pre-existing manual freshness trip-wire): it fails the cut loudly if any tracked file bump.mjs or a cut-hygiene step touched is still modified-in-the-worktree after Step 5's allowlist ran, so the next allowlist gap is caught at cut time instead of discovered by hand later. `selftest` extended with a direct unit test of the new `unstagedTrackedLeftovers()` parser (plain modifies/deletes, staged-only and untracked exclusions, C-quoted paths, rename/copy new-side reporting) plus a marker asserting the guard's `--dry` code path runs.
12
+
13
+ ### Changed
14
+ - **`package-release`: gate 4 retries once on host-contention timeout (Mode A, gh#2195, #2362)**; `cut-procedure.md` fails fast on a pnpm-shaped `node_modules` in Step 1 and adds Step 12 (restore the pnpm dev layout after a cut) (#2197, #2202); `gates-catalog.md` follows.
15
+ - **`a2ui-maintenance` references follow the A2UI runtime.** `data-model-reactivity.md`, `surface-lifecycle.md`, and `pipeline-overview.md` describe the vendored v1 data model after ADR-0078 P3/P4 (walker retirement, #2271), the `v0_9`→`v1_0` dialect rename (gh#2212, #2241), and the five opt-out-scoped catalogs (gh#2211, #2233, #2216).
16
+ - **`primitive-authoring` references absorb the ADR-drift harvest (#2441) and ADR-0063 wave 2 (#2443)**: `anti-patterns.md`, `api-contract.md`, `authoring-cycle.md`, `code-style.md`, `form-control-sizing.md`, `token-contract.md`, and `yaml-contract.md` now state the ratified spellings (`no-*` negation prefix, `closable`, `outlined`, `status=completed`) and the amended ADR-0047/0056/0059/0061 rulings inline.
17
+ - **`HARNESS-NOTES.md`** pointer for non-Claude harnesses (gh#2449).
18
+
19
+ ### Fixed
20
+ - **`generate-release-notes.mjs` (gh#2474): two bugs found and hand-fixed live during the v0.8.56 cut, now fixed at the source.** (1) When a CHANGELOG `[X.Y.Z]` section carries two same-named `### Changed`/`### Fixed` blocks (one at cut time, another added by a later hand-fix), the generator now merges them into one heading in first-occurrence order before demoting to `####` — the duplicate `####` heading that tripped CodeRabbit's MD024 (db13eaebb) can't recur. (2) The Slack post's per-package headline now prefers a bullet starting with `- **BREAKING` over document order, falling back to the first bullet only when none is BREAKING (b378b5fd9). Added `mergeDuplicateHeadings()`, unit coverage in `scripts/release/generate-release-notes.test.js`, and `selftest` regression cases for both. `scripts/release/generate-release-notes.mjs`.
21
+
22
+ ### Maintenance
23
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
24
+ - **`.codex-plugin/` touched in this release window** (1 file(s), e.g. `.codex-plugin/plugin.json`) — carried by the entries above.
25
+ - **`skills/` touched in this release window** (14 file(s), e.g. `a2ui-maintenance/SKILL.md`) — carried by the entries above.
26
+
27
+ ## [0.8.55] — 2026-08-28
28
+
29
+ ### Changed
30
+ - **`.codex-plugin/` regenerated for the release window** — `.codex-plugin/plugin.json`'s embedded `version` moves with the lockstep bump (derived from `.claude-plugin/plugin.json`, not an independent edit).
31
+
32
+ ### Maintenance
33
+ - **Lockstep version bump only.** No source changes in this package; bumped to maintain the lockstep version coherence enforced by `scripts/release/check-lockstep.mjs`. Substantive v0.8.55 work shipped in button-ui flex-shrink:0 default fix (gh#2180/gh#2181). See `packages/web-components/CHANGELOG.md#0855--2026-08-28` for details.
34
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
35
+
3
36
  ## [0.8.54] — 2026-08-27
4
37
 
5
38
  ### Fixed
package/__init__.py CHANGED
@@ -11,6 +11,11 @@ def register(ctx):
11
11
  path=Path(os.path.join(_HERE, "skills", "a2ui-maintenance", "SKILL.md")),
12
12
  description="Maintains the A2UI pipeline (packages/gen-ui/a2ui/): the chunk corpus, compose strategies (zettel, chunk-zettel, free-form, monolithic), retrieval, validator, calibration, evals, the a2ui MCP server. Use to author/harvest/fix chunks, tune STRONG_MATCH or zettel thresholds, validate an A2UI document, diagnose an eval gap/regression or lift a semantic fail, change MCP tools (generate_ui, compose_from_chunks, check_anti_patterns, refine_composition), scan anti-patterns, run pipeline ops, or when a contract can't express a shape. NOT for app screens (screen-composition), runtime gen-UI features (gen-ui-wiring), primitive authoring (primitive-authoring), or gallery scoring (gen-ui-review).",
13
13
  )
14
+ ctx.register_skill(
15
+ name="component-md-authoring",
16
+ path=Path(os.path.join(_HERE, "skills", "component-md-authoring", "SKILL.md")),
17
+ description="Author the two judgment sections of a component's `component.md` — Screen-reader spec and Behavioral spec — and keep it PR-fresh. Use when a component's states, composed children, aria behavior, or error/empty/ loading handling changes and it already has (or should grow) a `component.md`, or when asked to \"add component.md for X\" / \"write the screen-reader spec for X\" / \"why did check:component-md-fresh fail\". NOT the yaml prop/slot/event/token contract itself (primitive-authoring owns that — this skill only owns the two authored yaml fields, `screenReader`/`behavioral`, plus the optional `intent` field); NOT gen-ui corpus/retrieval wiring (a2ui-maintenance); NOT a component's CSS token audit (component-token-audit).",
18
+ )
14
19
  ctx.register_skill(
15
20
  name="cross-harness-authoring-standards",
16
21
  path=Path(os.path.join(_HERE, "skills", "cross-harness-authoring-standards", "SKILL.md")),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-forge",
3
- "version": "0.8.54",
3
+ "version": "0.8.56",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself — 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",
package/plugin.yaml CHANGED
@@ -1,4 +1,4 @@
1
1
  name: "adia-ui-kit-forge"
2
- version: "0.8.54"
2
+ version: "0.8.56"
3
3
  description: "Maintain the adia-ui (@adia-ai) framework itself — 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-ui-kit-factory (the consumer/app-author plugin)."
4
4
  manifest_version: 1
@@ -47,7 +47,7 @@ Unmatched work defaults to pipeline-overview and re-classifies from there.
47
47
  | Tune the anti-pattern catalogue | [anti-patterns](references/anti-patterns.md) |
48
48
  | A contract can't express a content shape — decide how to extend it | [format-extension-decisions](references/format-extension-decisions.md) |
49
49
  | Surface regeneration, pending/stale rendering, the `doc`-setter bracket | [surface-lifecycle](references/surface-lifecycle.md) (ADR-0061) |
50
- | Data-model internals — `Cell`/`Derived`, RFC-6901 pointers, `path-pointer.js` call-site migration, watch semantics | [data-model-reactivity](references/data-model-reactivity.md) (ADR-0078) |
50
+ | Data-model internals — `Cell`/`Derived`, RFC-6901 pointers, watch semantics (shipped) | [data-model-reactivity](references/data-model-reactivity.md) (ADR-0078) |
51
51
 
52
52
  ## Contracts that gate every change
53
53
 
@@ -1,14 +1,16 @@
1
1
  # v1 data-model reactivity — Cell/Derived, RFC-6901 pointers, value-identity cutoff
2
2
 
3
3
  Source of truth: [ADR-0078](../../../../../../docs/ops/adr/adr-0078-a2ui-runtime-adopts-v1-data-model.md)
4
- (ratified 2026-08-20, gh#1762; phased plan tracked in gh#1784). Read the ADR
5
- before touching `packages/gen-ui/a2ui`'s data-model internals, `path-pointer.js`
6
- call sites, or `surface.js`/`renderer.js` watch semantics — this file is the
7
- routing pointer + the shape of the adopted contract, not a restatement of the
8
- ruling, and NOT a claim that any phase has shipped (check gh#1784's own state
9
- before citing this as already-live behavior).
4
+ (ratified 2026-08-20, gh#1762; phased plan tracked in gh#1784, **closed
5
+ 2026-08-28 all four phases P1-P4 shipped**). Read the ADR before touching
6
+ `packages/gen-ui/a2ui`'s data-model internals or `surface.js`/`renderer.js`
7
+ watch semantics this file is the routing pointer + the shape of the
8
+ adopted contract, not a restatement of the ruling. `path-pointer.js` (the
9
+ transitional three-walker shim gh#1763 staged) is deleted as of P4; every
10
+ call site now uses the vendored `resolvePointer`/`setPointer`/`deletePointer`/
11
+ `createDataModel` primitives directly.
10
12
 
11
- ## What's decided (direction, not yet fully built)
13
+ ## What's decided (shipped ADR-0078 P1-P4 complete, gh#1784 closed)
12
14
 
13
15
  The in-repo A2UI runtime (`packages/gen-ui/a2ui`, the 0.9 dialect) **adopts**
14
16
  the vendored `packages/genui` v1.0 data model internally — `Cell`/`Derived`
@@ -19,8 +21,11 @@ data model. This is an internal implementation swap, not a consumer
19
21
  migration or a wire-grammar change: the dialect's eight message kinds, the
20
22
  `{path}` binding-prop shape, `updateDataModel`, `HandlerContext.updateModel/
21
23
  setModel`, `registerController/Handler/Resolver`, and the `<a2ui-root>`
22
- element API are all unchanged (ADR-0078 Decision item 2 — falsified if any
23
- consumer needs a code change, or if `dialect-schema.source.mjs` diffs).
24
+ element API are all unchanged. **[amended 2026-08-28, gh#2268/lld-0005,
25
+ gh#2212]** Decision item 2's falsifier is narrowed to wire-GRAMMAR diffs
26
+ only: it is falsified if any consumer needs a code change, or if
27
+ `dialect-schema.source.mjs`'s wire grammar diffs — a bare `$id`/filename
28
+ identifier rename in `dialect-schema.source.mjs` no longer falsifies it.
24
29
  Phased across future cuts, plan/LLD to follow — nothing rides in the cut
25
30
  this ADR itself was ratified for (item 6).
26
31
 
@@ -49,19 +54,25 @@ this ADR itself was ratified for (item 6).
49
54
  same identity-cutoff rule as R-R10). This supersedes `surface.js`'s
50
55
  prefix-descend rule and `renderer.js`'s re-apply-all-bindings behavior.
51
56
 
52
- ## What's converging, and what it changes
57
+ ## What converged (P1-P4, complete)
53
58
 
54
- `path-pointer.js` (gh#1763) currently preserves three divergent legacy
55
- walkers (`getByPath`/`setByPath`, `getPath`/`setPath`, `getModelValue`) on
56
- purpose, as a staging step each call site migrates to the vendored
57
- semantics above and retires when its last call site migrates. Every
58
- migration phase must name its own behavior deltas rather than changing
59
- silently (ADR-0078 item 4 is falsified by an unnamed semantics change) —
60
- known deltas already called out: `/a//b/` stops resolving forgivingly,
61
- `/name/length` on a string stops leaking the primitive's own property,
62
- and a2ui's own read/write asymmetry (today: `getByPath`/`getPath` treat
63
- absent-path/`""`/`"/"` alike, but `setByPath`/`setPath` no-op on root
64
- instead of replacing it) converges on the read/write split named above.
59
+ `path-pointer.js` (gh#1763) preserved three divergent legacy walkers
60
+ (`getByPath`/`setByPath`, `getPath`/`setPath`, `getModelValue`) as a
61
+ deliberate staging step; each call site migrated to the vendored semantics
62
+ above in turn (P2: `renderer.js`; P3: `surface.js`/`wiring-registry.js`),
63
+ and P4 deleted the module once its last call site migrated no divergent
64
+ walker survives (Decision 4). Every migration phase named its own behavior
65
+ deltas rather than changing silently (ADR-0078 item 4's falsifier): `/a//b/`
66
+ stopped resolving forgivingly, `/name/length` on a string stopped leaking
67
+ the primitive's own property, `~0`/`~1` escaping is now honored, and a2ui's
68
+ own read/write asymmetry (previously: `getByPath`/`getPath` treated
69
+ absent-path/`""`/`"/"` alike, but `setByPath`/`setPath` no-op'd on root
70
+ instead of replacing it) converged on the read/write split named above. The
71
+ full Δ1-Δ10 delta table lives in
72
+ [lld-0001-a2ui-data-model-consumption §Data](../../../../../../docs/ops/lld/lld-0001-a2ui-data-model-consumption.md#data);
73
+ the surviving regression proof for the pointer-only deltas is
74
+ `packages/gen-ui/a2ui/data-model-pointer-semantics.test.js` (migrated from
75
+ `path-pointer.test.js` in P4).
65
76
 
66
77
  ## What stays fixed (don't "fix" these under this ADR)
67
78
 
@@ -76,15 +87,24 @@ instead of replacing it) converges on the read/write split named above.
76
87
  - `record.js`'s bidirectional-overlap store — app-layer, outside this
77
88
  package, rides a separate review track (R2), not this ADR.
78
89
 
79
- ## Consumption mechanism — open, LLD decides
90
+ ## Consumption mechanism — decided (build-time copy)
80
91
 
81
- `@adia-ai/a2ui` is a zero-runtime-deps package (ADR-0048 posture);
82
- `packages/genui` is a vendored, never-edited-in-place artifact (ADR-0059).
83
- Whether the adopted primitives land via a build-time vendor-copy (with a
84
- provenance stamp) or a workspace-internal import is NOT decided by
85
- ADR-0078whichever the LLD picks must either preserve the zero-deps
86
- posture or explicitly re-rule it. Check the LLD (once authored, per gh#1784)
87
- before assuming either mechanism.
92
+ `@adia-ai/a2ui` is a zero-runtime-deps package (ADR-0048 posture).
93
+ **[amended 2026-08-29, ADR-0096, gh#2373 — recorded in ADR-0078's own
94
+ 2026-08-29 amendment]**
95
+ `packages/genui` is absorbed first-party in-repo source, not a vendored
96
+ artifact`packages/genui/VENDOR.json` and the vendor-and-sync mechanism
97
+ are gone (gh#2372 closed; `VENDOR.json` confirmed absent from origin/main).
98
+ [lld-0001](../../../../../../docs/ops/lld/lld-0001-a2ui-data-model-consumption.md)
99
+ decided a build-time byte-identical copy of
100
+ `packages/genui/renderer/dist/data-model.js` (+`.d.ts`) into
101
+ `packages/gen-ui/a2ui/`, with a `data-model.provenance.json` sidecar and a
102
+ freshness gate in `npm run check` — preserving the zero-deps posture (no new
103
+ package dependency, no covert workspace-import). The provenance sidecar now
104
+ points at the in-repo source path instead of a `VENDOR.json` sha: it stamps
105
+ `source.js`/`source.dts` + `syncedAt` + `contentHash` only —
106
+ `packages/genui/renderer/dist/data-model.js` — with no vendor-sha field at
107
+ all.
88
108
 
89
109
  ## Eval-floor risk
90
110
 
@@ -4,34 +4,63 @@
4
4
 
5
5
  Two protocol layers coexist (ADR-0059, `docs/ops/spec/spec-a2ui-v1-conformance.md`):
6
6
  the shipping dialect this pipeline emits (Layer A, `packages/gen-ui/a2ui/`) and
7
- the vendored A2UI v1.0 Candidate stack (Layer B, `packages/genui/`) reached
8
- through `packages/genui/wire-bridge/`. Candidate terminology is
7
+ the A2UI v1.0 Candidate stack (Layer B, `packages/genui/`) reached
8
+ through `packages/genui/wire-bridge/`. **[amended 2026-08-29, ADR-0096]**
9
+ `adiahealth/gen-ui-system` is absorbed first-party under `packages/genui/`
10
+ and the standalone repo is archived — Layer B is in-repo source, not a
11
+ vendored dependency; `VENDOR.json` and the sync mechanism are gone (see
12
+ this same note on siblings `data-model-reactivity.md` and
13
+ `surface-lifecycle.md`). Candidate terminology is
9
14
  **renderer/agent** — never client/server: `callableFrom` values are
10
15
  `rendererOnly`/`agentOnly`/`rendererOrAgent`; the wire function kinds are
11
16
  `callRendererFunction`/`callAgentFunction` +
12
17
  `rendererFunctionResponse`/`agentFunctionResponse`; the MIME type is
13
18
  `application/a2ui+json`; catalog resolution is strict (component `catalogId` →
14
19
  surface `catalogId` → error, no registry default). The producer's
15
- `wireFormat: 'v1'` flag exists and defaults to `'dialect'`
16
- (`packages/genui/adia-producer/exit-gate.js`). Documents authored here stay
17
- dialect-shaped; the bridge owns the translation — never hand-write Candidate
18
- envelopes from this skill's surfaces.
19
-
20
- site-a2ui (the build-time HTML→A2UI docs-site transpile) is RULED fit as the
21
- **dialect side's regression corpus**, not a v1.0 conformance bed (ADR-0068):
22
- it exercises the dialect renderer, the ADR-0061 lifecycle path, and the
23
- engine transpiler at real-content scale in production, but never touches the
24
- producer, the bridge, or the `wireFormat` flag so it neither blocks the
25
- v1.0 migration nor gets re-pointed at the v1 wire. **Named expiry:** that
26
- ruling is load-bearing on `wireFormat` defaulting to `'dialect'`; the flag-flip
27
- ADR that makes `'v1'` the shipping default MUST re-rule site-a2ui's fitness
28
- (re-point vs retirement-by-attrition) the fitness verdict expires with the
29
- `'dialect'` default. Expanding site-a2ui new message kinds, new consumers,
30
- or a promotion PROGRAM toward all routes also invalidates the ruling's
31
- basis and needs a new decision; burn-down of existing
32
- `visual-drift`/`blocked-format-gap` rows (including a route thereby becoming
33
- parity-promoted) is ordinary maintenance and stays permitted (ADR-0068
34
- Decision 5).
20
+ `wireFormat` flag (`packages/genui/adia-producer/exit-gate.js`) **[flipped
21
+ 2026-08-30, PR #2412]** now defaults to `'v1'`, not `'dialect'` ADR-0072
22
+ ratified the flip (its precondition, genui-system#51's re-verification,
23
+ re-scoped and satisfied via ADR-0096/PR #2401) and the flip itself has since
24
+ executed. Documents authored here stay dialect-shaped; the bridge owns the
25
+ translation never hand-write Candidate envelopes from this skill's
26
+ surfaces.
27
+
28
+ **Catalogs are opt-out scopes, not a taxonomy.** A2UI v1.0 lets a renderer
29
+ mix catalogs within one surface: `createSurface.catalogId` is the default,
30
+ and any component may carry its own `catalogId` to override it
31
+ (a2ui.org/specification/v1.0-a2ui/, "Catalog Reference"). So the useful way
32
+ to split a catalog is by what an app OMITS, never by component kind — Buttons
33
+ and Inputs are never omitted together, whole feature areas are. This is the
34
+ ratified basis of the five-catalog partition (gh#2211, Kim 2026-08-28):
35
+ `adia.core` / `adia.navigation` / `adia.data` / `adia.agent` / `adia.shells`,
36
+ every one a derived view over the yaml `category` axis and package path,
37
+ never a hand list. Two facts that trip a re-derivation: the `category` axis
38
+ had no `data` bucket for tables/charts (they declared `agent`; the partition's
39
+ pre-step re-categorizes five components), and `packages/web-modules/**` is a
40
+ path seam, not a category (its sidecars mostly declare `layout`/`container`).
41
+ The partition lives on the Layer B side only; the dialect catalog stays one
42
+ file per ADR-0059 §1. The 44 L1 harvested widgets are a pattern library, not
43
+ catalog members.
44
+
45
+ site-a2ui (the build-time HTML→A2UI docs-site transpile) was RULED fit as
46
+ the **dialect side's regression corpus**, not a v1.0 conformance bed
47
+ (ADR-0068): it exercised the dialect renderer, the ADR-0061 lifecycle path,
48
+ and the engine transpiler at real-content scale in production, but never
49
+ touched the producer, the bridge, or the `wireFormat` flag. That fitness
50
+ ruling was load-bearing on `wireFormat` defaulting to `'dialect'`, with a
51
+ **Named expiry**: the flag-flip ADR that makes `'v1'` the shipping default
52
+ had to re-rule site-a2ui's fitness (re-point vs retirement-by-attrition).
53
+
54
+ **[resolved, ADR-0072]** That trigger has fired and been ruled:
55
+ retirement-by-attrition, not re-point (Decision 2) — promotion program
56
+ closed, site-a2ui moves to breakage-only maintenance, an attrition-exit
57
+ ticket tracks the wind-down (gh#2410), and the mechanism is removed once the
58
+ promoted set reaches zero. The flip itself has since executed (PR #2412,
59
+ merged 2026-08-30: `exit-gate.js` now defaults to `'v1'`) — site-a2ui is in
60
+ its attrition window now, not a still-open future trigger. Burn-down of
61
+ existing `visual-drift`/`blocked-format-gap` rows is no longer "ordinary
62
+ maintenance toward parity promotion" (ADR-0068 Decision 5) — it is wind-down
63
+ toward the mechanism's removal per gh#2410.
35
64
 
36
65
  All paths repo-relative. Specs worth reading before structural changes:
37
66
  `.claude/docs/specs/a2ui-v0.9-catalog-guide.md` (protocol + catalog format),
@@ -151,6 +180,11 @@ for any constant or decision lives in git and PR descriptions
151
180
  currently fails, mostly a schema-generation gap around `data-*`/`span`
152
181
  attributes, not corpus-content defects — see the ticket before
153
182
  assuming a chunk is actually broken).
183
+ 13. **Every generated catalog schema carries three synthesized universal
184
+ props today** (`slot`/`hidden`/`ariaLive`, none declared in any yaml
185
+ SoT); ADR-0097 rules a fourth, `traits`, but that part is decided-not-
186
+ yet-shipped (gh#2513) — see `primitive-authoring/references/
187
+ yaml-contract.md` §Synthesized universal props for the full contract.
154
188
 
155
189
  ## Test + run commands (all verified in root package.json)
156
190
 
@@ -57,13 +57,20 @@ Staleness is exposed as one attribute plus three events, never styling:
57
57
 
58
58
  The lifecycle is renderer-runtime work on gen-ui-kit's side of the ADR-0059
59
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.
60
+ `commitSurfaceUpdate` / `abortSurfaceUpdate` as v1.0 server kinds) are
61
+ defined by the v1.0 Candidate reference implementation — `a2ui.schema.json`
62
+ gains nothing, the dialect wire format is byte-identical. Never hand-write
63
+ lifecycle envelopes from this skill's surfaces; the Bridge owns the mapping
64
+ when the kinds land.
65
+
66
+ **[amended 2026-08-29, ADR-0096]** `adiahealth/gen-ui-system` is absorbed
67
+ first-party under `packages/genui/` and the standalone repo is archived —
68
+ there is no external, separately-governed "upstream standard" to wait on
69
+ any more. ADR-0096 Decision 5: gen-ui-kit "owns the whole stack now... and
70
+ the v1.0 Candidate reference implementation itself, not only the consumer
71
+ side of a vendor boundary." Stream-driven regeneration now proceeds on
72
+ gen-ui-kit's own schedule against the in-repo `packages/genui/` source,
73
+ not an upstream release.
67
74
 
68
75
  ## Interlock worth knowing
69
76
 
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: component-md-authoring
3
+ description: >-
4
+ Author the two judgment sections of a component's `component.md` —
5
+ Screen-reader spec and Behavioral spec — and keep it PR-fresh. Use when a
6
+ component's states, composed children, aria behavior, or error/empty/
7
+ loading handling changes and it already has (or should grow) a
8
+ `component.md`, or when asked to "add component.md for X" / "write the
9
+ screen-reader spec for X" / "why did check:component-md-fresh fail". NOT
10
+ the yaml prop/slot/event/token contract itself (primitive-authoring owns
11
+ that — this skill only owns the two authored yaml fields,
12
+ `screenReader`/`behavioral`, plus the optional `intent` field); NOT gen-ui
13
+ corpus/retrieval wiring (a2ui-maintenance); NOT a component's CSS token
14
+ audit (component-token-audit).
15
+ disable-model-invocation: false
16
+ user-invocable: true
17
+ ---
18
+
19
+ # component-md-authoring
20
+
21
+ `component.md` (gh#2615) is a generated shell, per-component, sitting next
22
+ to its `.yaml` SoT (`packages/web-components/components/<name>/component.md`,
23
+ or `packages/web-modules/<cluster>/<name>/component.md` for a composite/
24
+ shell). Every section except two is mechanically transcluded from the yaml
25
+ by `scripts/build/gen-component-md.mjs` — Intent, API (props/events/slots),
26
+ Structural (Light DOM anatomy + states + composes), Tokens, Rules,
27
+ Anti-patterns, Related. This skill's whole charter is the two sections that
28
+ aren't: **Screen-reader spec** and **Behavioral spec**.
29
+
30
+ ## The load-bearing decision: where the authoring happens
31
+
32
+ You do not hand-edit `component.md`. You edit the yaml's `screenReader:`
33
+ and `behavioral:` fields (and, ideally, `intent:`) — `component.md` is
34
+ regenerated from them. This is deliberate, not incidental:
35
+
36
+ - **No second source of truth.** plan-2615's evidence pass on gh#2615 found
37
+ most of component.md's "intent layer" already lives in the yaml
38
+ (`a2ui.rules`, `anti_patterns`, `related`, examples). The two genuine
39
+ gaps — screen-reader and behavioral judgment — get the SAME treatment:
40
+ authored once, in yaml, transcluded everywhere else (component.md today;
41
+ gen-ui corpus derivation once a2ui-maintenance wires it in).
42
+ - **The freshness gate is PR-blocking, not staleness-only.** Because the
43
+ authored content lives in a yaml field, `component.md` is 100%
44
+ mechanically regenerable — `check:component-md-fresh` can do a real byte-
45
+ diff, the same shape as `check:reference-docs-fresh`, except PR-blocking
46
+ (operator ruling 2026-08-31) rather than advisory-only. A hand-edit
47
+ directly in `component.md` will be silently clobbered by the next
48
+ `npm run docs:component-md` and will fail the gate as "not fresh" — this
49
+ is the guard rail, not a bug.
50
+
51
+ ## Authoring a component's two sections
52
+
53
+ 1. Confirm the component doesn't already have adequate coverage — read its
54
+ existing `states:`, `a2ui.rules`, and `.class.js` source. Per
55
+ primitive-authoring's own first principle, **source wins**: verify every
56
+ claim you're about to write (focus order, aria attribute names, event
57
+ names) against the actual `.class.js`/`.js` file, not just the yaml
58
+ prose.
59
+ 2. **Screen-reader spec** — focus order across composed children (order
60
+ `showModal()`/connect moves focus, what wraps at the tab boundary),
61
+ live-region announcement sequence (what fires `role="alert"` or an
62
+ `aria-live` region, and when), and any keyboard map beyond the trait
63
+ default (`pressable`/`focusable` already cover Enter/Space/click — only
64
+ document what's ADDITIONAL, e.g. arrow-key grid nav, Escape-dismiss).
65
+ Do not restate a static `aria-*` attribute the yaml's `props`/`states`
66
+ already document plainly — that's derived content, not new judgment.
67
+ 3. **Behavioral spec** — dismiss/error/empty/loading states and
68
+ transitions NOT already modeled by `states:`. Distinguish "fetching" vs
69
+ "confirmed empty" where both exist (see `table.yaml`'s `screenReader`/
70
+ `behavioral` for a worked example: three distinct states, not one).
71
+ Name what is explicitly NOT handled (no built-in error state, no
72
+ built-in loading state) as clearly as what is — an absence is often the
73
+ more actionable fact for a consumer.
74
+ 4. Both fields require `minLength: 20` (schema-enforced) — a placeholder
75
+ one-liner will fail `check:components-valid`. Write real prose, grounded
76
+ in source, not a restatement of the component's `description`.
77
+ 5. Regenerate and verify:
78
+
79
+ ```bash
80
+ node scripts/build/components.mjs --validate # schema-valid yaml
81
+ npm run docs:component-md # regenerate component.md
82
+ npm run check:component-md-fresh # PR-blocking gate
83
+ ```
84
+
85
+ 6. If this is the component's FIRST component.md (yaml previously had
86
+ neither field), run `npm run build:components` too — the corpus/catalog
87
+ rebuild picks up the new yaml content, and `npm run eval:diff --
88
+ --engine zettel` should show no regression (preserve-not-regress floor,
89
+ owned by a2ui-maintenance).
90
+
91
+ ## Scope (gh#2615 pilot)
92
+
93
+ `scripts/build/gen-component-md.mjs`'s `SCAN_ROOTS` covers
94
+ `packages/web-components/components/` and `packages/web-modules/chat/`
95
+ today — the pilot 5 (`button`, `modal`, `table`, `field`, `chat-shell`).
96
+ Extending to every web-modules cluster, or sweeping the remaining ~145
97
+ primitives, is deliberately out of scope for this pass (file a follow-up
98
+ task rather than silently expanding `SCAN_ROOTS` for one-off need — a
99
+ cluster added there without a plan for authoring every component inside it
100
+ just produces components with a `.yaml` but no eligible `component.md`,
101
+ which the generator already handles gracefully by skipping them, but which
102
+ defeats the point of a rollout plan).
103
+
104
+ ## Cross-references
105
+
106
+ - `primitive-authoring`'s authoring-cycle: add "new/changed states or aria
107
+ behavior → component-md-authoring's authored sections may need a pass"
108
+ to your own SoT-change checklist when editing a yaml that already has a
109
+ `component.md` sibling.
110
+ - `scripts/schemas/component.yaml.schema.json` — `intent`/`screenReader`/
111
+ `behavioral` field definitions (all optional; a component with a `.yaml`
112
+ but neither authored field simply has no `component.md` yet).
113
+ - `scripts/verify/check-component-md-fresh.mjs` — the PR-blocking gate:
114
+ byte-freshness (component.md matches a fresh render) AND same-PR
115
+ coverage (a component.md-bearing component's source/yaml change must
116
+ touch component.md in the same diff).
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "Component Md Authoring"
3
+ short_description: "Author the two judgment sections of a component's `component.md` — Screen-reader spec and Behavioral spec — and keep it PR-fresh."
@@ -31,6 +31,7 @@ Two entry variants, converging at Step 5:
31
31
  | 9 | Dispatch publish workflows; wait; verify registry | Publish |
32
32
  | 10 | GH releases + site deploy dispatch | Deploy |
33
33
  | 11 | Author release notes (default, not optional) | No |
34
+ | 12 | Restore the pnpm dev layout (`npm ci` left it npm-shaped) | node_modules only |
34
35
 
35
36
  ---
36
37
 
@@ -44,8 +45,18 @@ git -C "$REPO" status --short
44
45
  git -C "$REPO" log --oneline -8
45
46
  git -C "$REPO" fetch && git -C "$REPO" log HEAD..origin/main --oneline # must be empty
46
47
  git -C "$REPO" tag --list 'vX.Y.Z' '*-vX.Y.Z' # must NOT exist yet
48
+ [ -d "$REPO/node_modules/.pnpm" ] && echo "STOP: pnpm-shaped node_modules — run npm ci first" # gate 9 precondition, see §3.1 layout note
47
49
  ```
48
50
 
51
+ **Check the `node_modules` layout here, not at gate 9.** The §3.1 layout note (gh#1359)
52
+ already says gate 9 (`check:js-bundles-fresh`) needs the npm-ci layout, but it sits AFTER
53
+ the gate roster and is easy to read past — the v0.8.55 cut (2026-08-28) ran the full
54
+ 33-gate pre-flight under a pnpm-shaped tree, lost ~12 minutes to gates 1-8 and 10-33
55
+ passing, then failed gate 9 with phantom bundle drift (1.24 MB on disk vs 1.52 MB fresh
56
+ on every JS entry — the Phosphor icon glob resolving differently, not a real source
57
+ change). The one-line check above fails in under a second instead. `npm ci` to recover;
58
+ `npm install` alone does NOT reshape an existing pnpm tree.
59
+
49
60
  `branch --show-current` ≠ `main` → stop; cutting on a feature branch pushes a stale `main` ref while the tags point at the feature tip. Recovery: [`recovery-paths.md`](recovery-paths.md) §Scenario 8. If multiple unpushed `release(*):` commits exist → this is a batch push, [`recovery-paths.md`](recovery-paths.md) §Scenario 2.
50
61
 
51
62
  ## §Step 2 — Classify uncommitted files; stash strays
@@ -244,7 +255,9 @@ git -C "$REPO" checkout -b "release/vX.Y.Z"
244
255
  git -C "$REPO" reset HEAD >/dev/null 2>&1
245
256
  git -C "$REPO" add package-lock.json packages/*/package.json packages/*/CHANGELOG.md \
246
257
  packages/gen-ui/a2ui/*/package.json packages/gen-ui/a2ui/*/CHANGELOG.md \
247
- packages/genui/adia-catalog/base.json packages/genui/adia-catalog/adia-pack.json \
258
+ packages/genui/adia-catalog/adia.core.json packages/genui/adia-catalog/adia.navigation.json \
259
+ packages/genui/adia-catalog/adia.data.json packages/genui/adia-catalog/adia.agent.json \
260
+ packages/genui/adia-catalog/adia.shells.json \
248
261
  docs/ops/releases/vX.Y.Z.md # + in-scope source + Step-3.0 regen outputs
249
262
  git -C "$REPO" diff --cached --stat | tail -3 # count must match the allowlist
250
263
  ```
@@ -261,6 +274,19 @@ node scripts/build/components.mjs --verify && npm run check:chunks-fresh && npm
261
274
 
262
275
  Drift here means a regen output was left out of the allowlist — stage it and re-run. <2s now vs ~5min of tag-move recovery after CI catches it. Do not proceed to tag with drift.
263
276
 
277
+ ## §Step 5.6 — Unstaged-tracked-files guard (`release-pack.mjs`, gh#2473)
278
+
279
+ `release-pack.mjs`'s Step 5 mechanizes this: right after its own `git add`
280
+ (the allowlist above, as automated), it runs `git status --porcelain` and
281
+ fails the cut if any tracked file is still modified-in-the-worktree —
282
+ proof the allowlist covered everything bump.mjs / cut-hygiene touched this
283
+ cut, not just what §Step 5.5's three named freshness gates happen to check.
284
+ This is the fourth time the allowlist itself went stale (gh#1198, gh#1899,
285
+ gh#1954, gh#2473 — most recently the factory README's generation-MCP pin
286
+ prose), so the guard is generic rather than another named file. A manual
287
+ cut should run the equivalent check by hand: `git status --porcelain`
288
+ after staging must be empty of `M`/`D` lines.
289
+
264
290
  ## §Step 5.7 — Release PR: push the branch, merge, re-baseline
265
291
 
266
292
  The release commit reaches `main` through the standard PR flow. Mechanized
@@ -415,6 +441,25 @@ Any Step-2 stashes: `git stash pop`; flag conflicts to the operator.
415
441
 
416
442
  Always author notes at end-of-cycle without being asked — context is freshest now. Single version → [`notes-authoring.md`](notes-authoring.md); ≥2 versions since the last broadcast → its §Rollup section. Surface the draft inline for copy-paste; the operator owns posting. Skip only on an explicit "no notes".
417
443
 
444
+ ## §Step 12 — Restore the dev layout
445
+
446
+ The cut runs under `npm ci` (Step 1's layout check, gate 9), and that leaves
447
+ `node_modules` npm-shaped. The dev server refuses to start on that tree:
448
+ `npm run dev`'s `predev` hook (`scripts/dev/check-pnpm-layout.mjs`) hard-stops
449
+ because the Phosphor icon glob matches zero files under the hoisted layout and
450
+ every `<icon-ui>` would render empty (gh#340). Put the tree back before handing
451
+ the checkout to anyone, including yourself:
452
+
453
+ ```bash
454
+ pnpm install # single checkout
455
+ node scripts/dev/bootstrap-worktree.mjs # inside a linked worktree
456
+ ```
457
+
458
+ Both are idempotent and touch no committed file (`pnpm-lock.yaml` is
459
+ gitignored). Live cost of skipping this: the v0.8.55 cut (2026-08-28) left the
460
+ operator's primary checkout unable to run `npm run dev` until the layout was
461
+ restored by hand.
462
+
418
463
  ## §The 0.8.38 cut (the clean-world cut — delete this section after it lands)
419
464
 
420
465
  The first cut AFTER the estate-split bridge. Pre-conditions, all verifiable
@@ -159,6 +159,7 @@ The two `audit:*` probes are soft-fail pre-cut (exit-1 only on criticals); findi
159
159
  - **What:** the vitest suite (~1000+ tests).
160
160
  - **Stale-test failure:** the test asserts a behavior a peer deliberately changed (CHANGELOG-documented) without updating the assertion. Tell it apart by reading assertion vs CHANGELOG vs source: if the code matches the CHANGELOG's described behavior, the test is stale — update the assertion (see [`recovery-paths.md`](recovery-paths.md) §Scenario 5). Real regression → fix the regression.
161
161
  - **Parallel-contention flake:** heavy web-modules composite suites can fail under full parallelism on a loaded machine (`signals: drain loop exceeded 100 iterations`). Load-dependent, not a code defect. Sequential is the source of truth, and **the roster gate now runs it directly** (`npm run test:unit:serial` = `vitest run --no-file-parallelism`, gate 4 since 2026-07-19) — a parallel `test:unit` flake outside the roster still isn't a blocker, and don't raise the drain guard.
162
+ - **Same-host contention timeout (gh#2195):** gate 4 running solo (Phase 1, see the execution-model note above) isolates it from every OTHER pre-flight gate, but not from unrelated concurrent load on the same shared, multi-tenant host — another agent's build, a peer's own `npm run check`. gh#2195's diagnosis found this surfaces as a genuine 45s per-test timeout on a DIFFERENT single file each run, with no repeat culprit (the contention signature, not an order-dependent leak) — and found no separate "release pre-flight runner" with its own core count exists to recalibrate `worker-cap.mjs` against; it's the same operator/agent host either way. `release-pack.mjs`'s `runSoloGateWithRetry()` now retries gate 4 exactly once, scoped to only the file(s) it named as failed, when the failure output has a parseable `FAIL <file>` list — a file that fails once and passes clean on that immediate re-run was contention, not a regression; a file that fails twice is treated as a real one and the pre-flight still aborts. No other gate, and no OTHER invocation of `test:unit:serial` (CI, local dev, `npm run check`), gets this retry.
162
163
  - **Exit 143 (SIGTERM):** the vitest process was KILLED (resource pressure / a stray terminator), not a test failure — re-run the gate directly (`npx vitest run --no-file-parallelism`) before diagnosing anything; a clean re-run means transient, proceed (v0.8.34 handoff hit this).
163
164
  - **First-time-at-cut failures are REAL (v0.8.34):** this serial suite runs tests PR CI never does — `exit-gate.corpus` (dialect-catalog conformance over real harvested chunks) surfaces yaml-schema drift (e.g. an array prop missing `items.type`, the command/combobox `DynamicStringList` mis-map) only HERE, potentially weeks after the yaml edit merged green. Treat such a failure as a genuine latent defect to root-cause at the yaml SoT, never as release-blocking noise. (Structural fix — promoting the corpus batch into PR CI — tracked as a follow-up.)
164
165