@adia-ai/adia-ui-forge 0.8.61 → 0.8.63

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.
Files changed (142) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/.codex-plugin/plugin.json +3 -3
  3. package/CHANGELOG.md +309 -274
  4. package/README.md +54 -18
  5. package/__init__.py +8 -8
  6. package/agents/a2ui-maintenance-agent.corpus.json +7 -7
  7. package/agents/a2ui-maintenance-agent.md +6 -6
  8. package/agents/a2ui-planner-agent.md +11 -11
  9. package/agents/demo-audit-agent.corpus.json +4 -4
  10. package/agents/demo-audit-agent.md +8 -9
  11. package/agents/framework-checker.md +10 -11
  12. package/agents/framework-planner-agent.md +9 -10
  13. package/agents/gen-ui-review-agent.corpus.json +4 -4
  14. package/agents/gen-ui-review-agent.md +8 -8
  15. package/agents/package-release-agent.corpus.json +4 -4
  16. package/agents/package-release-agent.md +9 -10
  17. package/agents/primitive-authoring-agent.corpus.json +1 -1
  18. package/agents/primitive-authoring-agent.md +5 -5
  19. package/agents/routing-corpus.json +46 -46
  20. package/codex.interface.json +1 -1
  21. package/commands/gen-ui-review.md +1 -1
  22. package/commands/package-release.md +2 -2
  23. package/package.json +1 -1
  24. package/plugin.yaml +2 -2
  25. package/prompts/gen-ui-review.md +1 -1
  26. package/prompts/package-release.md +2 -2
  27. package/references/contracts/a2ui-mcp-surface.md +7 -7
  28. package/references/contracts/migration-guide-format.md +6 -7
  29. package/references/shared/content-trust.md +3 -5
  30. package/skills/a2ui-maintenance/SKILL.md +13 -16
  31. package/skills/a2ui-maintenance/evals/evals.json +2 -2
  32. package/skills/a2ui-maintenance/evals/routing-corpus.json +1 -1
  33. package/skills/a2ui-maintenance/references/anti-patterns.md +10 -10
  34. package/skills/a2ui-maintenance/references/chunk-authoring.md +11 -12
  35. package/skills/a2ui-maintenance/references/corpus-discipline.md +13 -14
  36. package/skills/a2ui-maintenance/references/data-model-reactivity.md +22 -25
  37. package/skills/a2ui-maintenance/references/eval-diagnostics.md +21 -21
  38. package/skills/a2ui-maintenance/references/format-extension-decisions.md +12 -13
  39. package/skills/a2ui-maintenance/references/leverage-rules.md +6 -6
  40. package/skills/a2ui-maintenance/references/mcp-pipeline-ops.md +9 -10
  41. package/skills/a2ui-maintenance/references/mcp-tool-reference.md +11 -12
  42. package/skills/a2ui-maintenance/references/pipeline-overview.md +33 -38
  43. package/skills/a2ui-maintenance/references/semantic-fail-lifting.md +13 -14
  44. package/skills/a2ui-maintenance/references/strategy-engines.md +14 -16
  45. package/skills/a2ui-maintenance/references/surface-lifecycle.md +10 -11
  46. package/skills/a2ui-maintenance/references/zettel-calibration.md +14 -16
  47. package/skills/component-md-authoring/SKILL.md +20 -21
  48. package/skills/component-md-authoring/agents/openai.yaml +1 -1
  49. package/skills/cross-harness-authoring-standards/SKILL.md +19 -21
  50. package/skills/cross-harness-authoring-standards/agents/openai.yaml +1 -1
  51. package/skills/cross-harness-compatibility-standards/SKILL.md +34 -35
  52. package/skills/cross-harness-compatibility-standards/agents/openai.yaml +1 -1
  53. package/skills/demo-audit/SKILL.md +38 -38
  54. package/skills/demo-audit/evals/routing-corpus.json +1 -1
  55. package/skills/demo-audit/references/admin-shell-anatomy.md +21 -25
  56. package/skills/demo-audit/references/app-shell-pitfalls.md +11 -13
  57. package/skills/demo-audit/references/auto-fix-allowlist.md +3 -3
  58. package/skills/demo-audit/references/card-anatomy-sweep.md +10 -11
  59. package/skills/demo-audit/references/chat-shell-anatomy.md +25 -26
  60. package/skills/demo-audit/references/editor-shell-anatomy.md +25 -28
  61. package/skills/demo-audit/references/html-attr-sweep.md +12 -13
  62. package/skills/demo-audit/references/mode7-status-battery.md +4 -4
  63. package/skills/demo-audit/references/native-leak-annotations.md +8 -8
  64. package/skills/demo-audit/references/output-contract-worked-example.md +8 -8
  65. package/skills/demo-audit/references/probe-discipline-and-escalation.md +2 -2
  66. package/skills/demo-audit/references/visual-probe-triage.md +21 -23
  67. package/skills/gen-ui-review/SKILL.md +27 -27
  68. package/skills/gen-ui-review/agents/openai.yaml +1 -1
  69. package/skills/gen-ui-review/evals/routing-corpus.json +1 -1
  70. package/skills/gen-ui-review/references/corpus-html-patterns.md +28 -29
  71. package/skills/gen-ui-review/references/exit-gate-mechanics.md +5 -5
  72. package/skills/gen-ui-review/references/lookup-maintenance.md +2 -2
  73. package/skills/gen-ui-review/references/loop-protocol.md +25 -25
  74. package/skills/gen-ui-review/references/rubric-cosmetic.md +10 -10
  75. package/skills/gen-ui-review/references/rubric-decompose.md +15 -16
  76. package/skills/gen-ui-review/references/rubric-score.md +23 -24
  77. package/skills/gen-ui-review/references/scorecard-worked-examples.md +12 -12
  78. package/skills/gen-ui-review/references/scores.schema.json +2 -2
  79. package/skills/llm-client-maintenance/SKILL.md +12 -12
  80. package/skills/llm-client-maintenance/evals/routing-corpus.json +1 -1
  81. package/skills/llm-client-maintenance/references/adapter-contract.md +27 -27
  82. package/skills/llm-client-maintenance/references/add-a-provider.md +25 -25
  83. package/skills/llm-client-maintenance/references/bridge-facade.md +31 -31
  84. package/skills/llm-client-maintenance/references/browser-proxy-boundary.md +17 -17
  85. package/skills/llm-client-maintenance/references/model-registry.md +14 -14
  86. package/skills/llm-client-maintenance/references/streaming-sse.md +21 -21
  87. package/skills/package-release/SKILL.md +21 -23
  88. package/skills/package-release/evals/evals.json +2 -2
  89. package/skills/package-release/evals/routing-corpus.json +2 -2
  90. package/skills/package-release/references/authorization-model.md +6 -8
  91. package/skills/package-release/references/changelog-discipline.md +25 -27
  92. package/skills/package-release/references/cut-procedure.md +129 -136
  93. package/skills/package-release/references/gates-catalog.md +42 -43
  94. package/skills/package-release/references/independent-package-release.md +14 -15
  95. package/skills/package-release/references/invariants-detail.md +9 -9
  96. package/skills/package-release/references/mechanization.md +11 -12
  97. package/skills/package-release/references/migration-guide-authoring.md +20 -20
  98. package/skills/package-release/references/notes-authoring.md +20 -20
  99. package/skills/package-release/references/recovery-paths.md +28 -28
  100. package/skills/primitive-authoring/SKILL.md +19 -19
  101. package/skills/primitive-authoring/agents/openai.yaml +1 -1
  102. package/skills/primitive-authoring/evals/evals.json +2 -2
  103. package/skills/primitive-authoring/evals/routing-corpus.json +2 -2
  104. package/skills/primitive-authoring/references/INDEX.md +22 -22
  105. package/skills/primitive-authoring/references/anti-patterns.md +76 -77
  106. package/skills/primitive-authoring/references/api-contract.md +63 -65
  107. package/skills/primitive-authoring/references/authoring-cycle.md +47 -50
  108. package/skills/primitive-authoring/references/canonical-pattern-index.md +118 -118
  109. package/skills/primitive-authoring/references/code-style.md +50 -52
  110. package/skills/primitive-authoring/references/common-gotchas.md +23 -23
  111. package/skills/primitive-authoring/references/composite-demo-protocol.md +42 -45
  112. package/skills/primitive-authoring/references/css-patterns.md +97 -97
  113. package/skills/primitive-authoring/references/for-attribute-event-contract.md +12 -12
  114. package/skills/primitive-authoring/references/form-control-sizing.md +16 -18
  115. package/skills/primitive-authoring/references/lifecycle-patterns.md +42 -42
  116. package/skills/primitive-authoring/references/llm-bridge.md +21 -21
  117. package/skills/primitive-authoring/references/module-promotion.md +51 -51
  118. package/skills/primitive-authoring/references/primitive-audit.md +16 -16
  119. package/skills/primitive-authoring/references/shell-patterns.md +81 -81
  120. package/skills/primitive-authoring/references/svg-authoring.md +62 -66
  121. package/skills/primitive-authoring/references/token-contract.md +45 -49
  122. package/skills/primitive-authoring/references/trait-pages.md +8 -8
  123. package/skills/primitive-authoring/references/worked-example.md +39 -39
  124. package/skills/primitive-authoring/references/yaml-contract.md +139 -143
  125. package/skills/site-deployment/SKILL.md +25 -26
  126. package/skills/site-deployment/agents/openai.yaml +1 -1
  127. package/skills/site-deployment/evals/routing-corpus.json +1 -1
  128. package/skills/site-deployment/references/deploy-playbooks.md +51 -53
  129. package/skills/site-docs-authoring/SKILL.md +14 -14
  130. package/skills/site-docs-authoring/agents/openai.yaml +1 -1
  131. package/skills/site-docs-authoring/evals/evals.json +1 -1
  132. package/skills/site-docs-authoring/evals/routing-corpus.json +1 -1
  133. package/skills/site-docs-authoring/intent.md +18 -18
  134. package/skills/ssr-compatibility/SKILL.md +24 -25
  135. package/skills/ssr-compatibility/agents/openai.yaml +1 -1
  136. package/skills/ssr-compatibility/evals/evals.json +1 -1
  137. package/skills/ssr-compatibility/evals/routing-corpus.json +1 -1
  138. package/skills/ssr-compatibility/references/consumer-workarounds.md +22 -23
  139. package/skills/ssr-compatibility/references/failure-shapes.md +84 -91
  140. package/skills/ssr-compatibility/references/guard-patterns.md +54 -58
  141. package/skills/ssr-compatibility/references/status-ledger.md +17 -17
  142. package/skills/ssr-compatibility/references/test-without-linkedom.md +26 -27
@@ -1,8 +1,8 @@
1
- # YAML component contract `<name>.yaml` schema
1
+ # YAML component contract, `<name>.yaml` schema
2
2
 
3
3
  Authoritative source-of-truth fields for `packages/web-components/components/<name>/<name>.yaml` and `packages/web-modules/<cluster>/<name>/<name>.yaml`. The build pipeline (`scripts/build/components.mjs`) reads these yamls + emits sidecar JSON (`<name>.a2ui.json`) that feeds the docs site, the A2UI runtime registries, and consumer harnesses.
4
4
 
5
- This is the authoritative schema reference for the authoring lane. The JSON Schema lives at `scripts/schemas/component.yaml.schema.json` (referenced by every yaml's `$schema:` key). Amended 2026-08-16 per ADR-0057: that schema is the documented contract + IDE aid, not a run validator no build step evaluates it against the yamls. The build-time checks that DO exist are hand-written throws in `compileComponent()` (`scripts/build/components.mjs`): a missing `component:` field, a `component: Surface` (reserved the A2UI v1.0 implicit root container, SPEC REQ-011/gh#1353), a `status:` value outside the five-value enum (see §`status:` below), a missing `category:` field OR a `category:` value outside the twelve-value enum (see §`category:` below, ADR-0065), and malformed `a2ui.allowedParents`/`a2ui.allowedChildren` composition constraints (see §composition constraints below plus a full-build cross-reference check that every referenced name is a real `component:` in the catalog). Every other schema constraint (`required: [name, tag, component, description]`, `minLength`, …) is IDE-visible only. This file covers the human-facing contract: what each field means, when to use which value, and the canonical shape of a complete yaml.
5
+ This is the authoritative schema reference for the authoring lane. The JSON Schema lives at `scripts/schemas/component.yaml.schema.json` (referenced by every yaml's `$schema:` key). Amended 2026-08-16 per ADR-0057: that schema is the documented contract + IDE aid, not a run validator, no build step evaluates it against the yamls. The build-time checks that DO exist are hand-written throws in `compileComponent()` (`scripts/build/components.mjs`): a missing `component:` field, a `component: Surface` (reserved, the A2UI v1.0 implicit root container, SPEC REQ-011/gh#1353), a `status:` value outside the five-value enum (see §`status:` below), a missing `category:` field OR a `category:` value outside the twelve-value enum (see §`category:` below, ADR-0065), and malformed `a2ui.allowedParents`/`a2ui.allowedChildren` composition constraints (see §composition constraints below, plus a full-build cross-reference check that every referenced name is a real `component:` in the catalog). Every other schema constraint (`required: [name, tag, component, description]`, `minLength`, …) is IDE-visible only. This file covers the human-facing contract: what each field means, when to use which value, and the canonical shape of a complete yaml.
6
6
 
7
7
  ---
8
8
 
@@ -14,98 +14,98 @@ $schema: ../../../../scripts/schemas/component.yaml.schema.json
14
14
  name: UIMyComponent # Class name (PascalCase, UI-prefixed)
15
15
  tag: my-component-ui # Custom element tag (kebab-case, -ui-suffixed)
16
16
  component: MyComponent # Short component name (no UI- prefix)
17
- category: form # Category see §category field below (ADR-0065, twelve-value enum)
17
+ category: form # Category, see §category field below (ADR-0065, twelve-value enum)
18
18
  version: 1 # Schema version (always 1 for now)
19
- status: stable # Stability tier see §status field below
19
+ status: stable # Stability tier, see §status field below
20
20
  description: >-
21
21
  Short one-paragraph description of what the component does and when
22
22
  to use it. Used by the docs site, sidecar, and a2ui registry. Be
23
23
  concrete about behavior + appearance, not generic ("a button").
24
24
  props:
25
- … # Prop schemas see §props field below
25
+ … # Prop schemas, see §props field below
26
26
  events:
27
- … # Event schemas fired by the component
27
+ … # Event schemas, fired by the component
28
28
  slots:
29
- … # Consumer-fillable light-DOM insertion points see §slots vs parts below
29
+ … # Consumer-fillable light-DOM insertion points, see §slots vs parts below
30
30
  parts:
31
- … # Template-owned anatomy see §slots vs parts below
31
+ … # Template-owned anatomy, see §slots vs parts below
32
32
  css-vars:
33
33
  … # CSS custom properties the component reads
34
34
  ```
35
35
 
36
36
  ---
37
37
 
38
- ## `slots:` vs `parts:` consumer-fillable vs template-owned anatomy (ADR-0067)
38
+ ## `slots:` vs `parts:`, consumer-fillable vs template-owned anatomy (ADR-0067)
39
39
 
40
40
  **Decision rule**: does an author (a human, or an LLM generating an A2UI
41
- document) ever place their OWN content at this named span? If yes even
42
- with a stamped fallback when nothing is supplied it's `slots:`. If the
41
+ document) ever place their OWN content at this named span? If yes, even
42
+ with a stamped fallback when nothing is supplied, it's `slots:`. If the
43
43
  component's own `render()`/template ALWAYS stamps it itself, from a prop or
44
- attribute, and no author-supplied content is ever accepted there it's
44
+ attribute, and no author-supplied content is ever accepted there, it's
45
45
  `parts:`. **Check element source, never the description prose alone**
46
- (AGENTS.md: source wins) a name that *sounds* internal
46
+ (AGENTS.md: source wins), a name that *sounds* internal
47
47
  (`actions`, `text`, `leading`) can still be a real insertion point in a
48
48
  given component; `table-toolbar.yaml`'s `actions` slot LOOKS stamped by
49
49
  name but its `class.js` explicitly absorbs pre-existing `[slot="actions"]`
50
- children (a real, author-fillable insertion point) the opposite of
50
+ children (a real, author-fillable insertion point), the opposite of
51
51
  `check.yaml`'s `box`, which `static template = () => html\`<span
52
52
  slot="box"></span>\`` stamps unconditionally every render.
53
53
 
54
54
  Both keys share the identical `Slot` schema shape (`description:` required,
55
- `fallback:` optional) the only difference is which key an entry lives
55
+ `fallback:` optional): the only difference is which key an entry lives
56
56
  under. `scripts/build/components.mjs` forwards both verbatim onto the
57
57
  sidecar (`x-adiaui.slots` / `x-adiaui.parts`) with no other processing.
58
58
 
59
- **Why the split matters three real consumers read `slots:` and present
59
+ **Why the split matters, three real consumers read `slots:` and present
60
60
  every entry as fillable, with no code-level filtering for anything under
61
61
  `parts:`:**
62
62
 
63
63
  - `packages/gen-ui/engine/retrieval/component-entry.js`'s
64
- `serializeReference()` feeds the LLM-facing `reference`-detail catalog
64
+ `serializeReference()`, feeds the LLM-facing `reference`-detail catalog
65
65
  entry (MCP tools, `getComponentAPI()`).
66
66
  - `packages/gen-ui/engine/compose/strategies/monolithic/_shared.js`'s
67
- `adaptV09Component()` feeds the monolithic engine's prompt catalog.
68
- - `scripts/docs/anatomy-sweep.mjs`'s `genSlots()` renders the docs-site
67
+ `adaptV09Component()`, feeds the monolithic engine's prompt catalog.
68
+ - `scripts/docs/anatomy-sweep.mjs`'s `genSlots()`, renders the docs-site
69
69
  "slots" anatomy section.
70
70
 
71
- A `parts:` entry never reaches any of the three above moving template-owned
71
+ A `parts:` entry never reaches any of the three above, moving template-owned
72
72
  anatomy there is a structural fix, not a naming convention alone. An
73
73
  existing entry under `slots:` that's actually template-owned (e.g. a
74
74
  component predating this ADR) is a real bug: it advertises to an LLM that
75
75
  filling it does something, when the component's own template replaces
76
- whatever's there on the next render the exact gh#284 destructive-replace
76
+ whatever's there on the next render, the exact gh#284 destructive-replace
77
77
  shape, applied to a *documented* slot instead of an undocumented one.
78
78
 
79
79
  `scripts/dev/audit-slot-vocab-vs-css.mjs` (the yaml-vs-CSS `[slot="X"]`
80
- cross-check) reads BOTH `slots:` and `parts:` a `parts:` entry is still a
80
+ cross-check) reads BOTH `slots:` and `parts:`, a `parts:` entry is still a
81
81
  real `slot="X"` DOM attribute the component's own CSS may position, just
82
82
  never author-fillable, so it stays in that audit's declared-vocabulary set.
83
83
  `scripts/dev/audit-template-child-conflict.mjs` (the gh#284 container-shape
84
- check) is unaffected either way it only checks for a slot literally named
84
+ check) is unaffected either way, it only checks for a slot literally named
85
85
  `default`.
86
86
 
87
87
  ---
88
88
 
89
- ## `a2ui.allowedParents:` / `a2ui.allowedChildren:` composition constraints (SPEC REQ-011, gh#1353)
89
+ ## `a2ui.allowedParents:` / `a2ui.allowedChildren:`, composition constraints (SPEC REQ-011, gh#1353)
90
90
 
91
91
  Optional keys inside the `a2ui:` block, alongside `rules:`. Each is a
92
92
  non-empty list of catalog `component:` names (NOT tags) naming the parents
93
93
  this component may sit under / the direct children it may contain. The
94
94
  reserved name `Surface` (the A2UI v1.0 implicit root container) is legal
95
95
  only in `allowedParents` and means "may sit at the surface root". **Omitted
96
- means unconstrained** never write an empty list (that would mean "allowed
96
+ means unconstrained**, never write an empty list (that would mean "allowed
97
97
  nowhere"; the build refuses it).
98
98
 
99
99
  `allowedParents` matches the nearest custom-element ancestor, not the
100
100
  immediate DOM parent (gh#3310): the generated lint rule's
101
101
  `compositionFindings()` walks up past native (non-hyphenated) wrapper
102
- elements `section`, `div`, `td`, `tr`, `tbody`, and any other plain HTML
103
- tag until it finds a real catalog component tag or reaches the surface
102
+ elements, `section`, `div`, `td`, `tr`, `tbody`, and any other plain HTML
103
+ tag, until it finds a real catalog component tag or reaches the surface
104
104
  root. This mirrors Light DOM's own composition reality (AGENTS.md: CSS
105
- positions by tag + ancestor + DOM order) a wrapper interposed for layout
105
+ positions by tag + ancestor + DOM order), a wrapper interposed for layout
106
106
  or semantics (a `<section>` inside a card, a `<td>` in a table body) doesn't
107
107
  change a component's logical host. `allowedChildren`, by contrast, still
108
- matches DIRECT children only a named-slot child that should be exempt
108
+ matches DIRECT children only, a named-slot child that should be exempt
109
109
  from the default-slot list is a separate, open gap (gh#3308), not addressed
110
110
  by this semantics change.
111
111
 
@@ -117,23 +117,23 @@ a2ui:
117
117
  - …
118
118
  ```
119
119
 
120
- **Authoring rule verify against element source, exactly like the
120
+ **Authoring rule, verify against element source, exactly like the
121
121
  `slots:`/`parts:` decision above.** Declare a constraint only when the
122
122
  component's own source enforces or assumes it (e.g. `stepper.class.js`
123
123
  queries `stepper-item-ui`; `segmented.class.js` warns on non-`segment-ui`
124
124
  children). A parent that adopts items through wrappers (menu.class.js's
125
- deliberate descendant query) must NOT constrain a declared constraint
125
+ deliberate descendant query) must NOT constrain, a declared constraint
126
126
  stricter than the source is a defect, not documentation.
127
127
 
128
128
  **`allowedChildren` is a default-slot-only check (gh#3308).** A direct
129
129
  child carrying ANY `slot=` attribute is a sibling-level named slot, not a
130
- default-slot member the lint-side matcher (`compositionFindings`)
130
+ default-slot member, the lint-side matcher (`compositionFindings`)
131
131
  exempts it from `allowedChildren` entirely, regardless of the slot's name.
132
132
  This is why menu-ui can declare `allowedChildren: [MenuItem, MenuDivider,
133
133
  MenuLabel]` for its default slot while still accepting an arbitrary
134
134
  focusable element on `slot="trigger"` ("typically button-ui, but any
135
135
  focusable element works") without a false positive. When a named slot
136
- *should* be constrained too (rare most named slots exist precisely
136
+ *should* be constrained too (rare, most named slots exist precisely
137
137
  because their content varies), add an `allowedChildrenBySlot:` map
138
138
  alongside `allowedChildren:`, keyed by slot name, same catalog-name-list
139
139
  shape:
@@ -150,7 +150,7 @@ a2ui:
150
150
  ```
151
151
 
152
152
  A slot with no entry in `allowedChildrenBySlot` (or the key omitted
153
- entirely) stays unconstrained by design this is the common case, and
153
+ entirely) stays unconstrained by design: this is the common case, and
154
154
  matches "omitted means unconstrained" for `allowedChildren`/`allowedParents`
155
155
  above.
156
156
 
@@ -165,7 +165,7 @@ per gh#2116) across the five opt-out-scoped catalogs (`adia.core.json`,
165
165
  validator enforces them (`UNALLOWED_PARENT`/`UNALLOWED_CHILD`). Module-tier
166
166
  yamls (web-modules) now carry a v1.0 sidecar too and land in `adia.shells`.
167
167
  `allowedChildrenBySlot` (gh#3308) is NOT part of this catalog/sidecar
168
- pipeline `components.mjs` never reads it, it never lands in
168
+ pipeline, `components.mjs` never reads it, it never lands in
169
169
  `x-adiaui`/`catalog-a2ui_1_0.json`, and the A2UI v1.0 protocol validator
170
170
  never enforces it. It exists purely for the lint-side check below.
171
171
 
@@ -173,7 +173,7 @@ A non-empty `allowedParents`/`allowedChildren`/`allowedChildrenBySlot`
173
173
  generates an enforced lint rule (LLD-0016 §C4, gh#2647):
174
174
  `scripts/build/gen-composition-rules.mjs` emits `scripts/lint/
175
175
  rules/generated/composition/<name>.mjs`, which flags a markup file where
176
- the tag nests under (or contains) a non-declared tag `allowedChildren`
176
+ the tag nests under (or contains) a non-declared tag, `allowedChildren`
177
177
  checked against default-slot children only, `allowedChildrenBySlot`
178
178
  against the matching named-slot children (see above). Advisory (`warn`)
179
179
  until a corpus-wide rollout promotes it (`npm run build:composition-rules`
@@ -231,42 +231,42 @@ coverage exactly as either list does.
231
231
 
232
232
  ---
233
233
 
234
- ## `examples:` field a2ui example ids (semantic-id grammar, gh#2492)
234
+ ## `examples:` field, a2ui example ids (semantic-id grammar, gh#2492)
235
235
 
236
236
  Each `examples[].a2ui` block is a JSON array of component nodes (the same
237
237
  `updateComponents.components[]` shape `.claude/docs/specs/a2ui-editor.md`
238
238
  documents for the editor's live doc store). That spec's line "other
239
239
  component ids are free-form (convention: `c-{n}` for generated ids)" governs
240
- **editor-generated** ids only ids the editor mints when a human drags a
240
+ **editor-generated** ids only, ids the editor mints when a human drags a
241
241
  component onto the canvas. It was never a license for **authored** ids
242
242
  inside a component's own yaml examples, and treating it as one produced a
243
243
  corpus-wide drift toward cryptic, positional ids (`q`, `k1`, `k1v`, `hdr`)
244
244
  that don't describe what they are once an example has more than one or two
245
- nodes reported in gh#2492 against `blockquote.yaml`, `badge.yaml`,
245
+ nodes, reported in gh#2492 against `blockquote.yaml`, `badge.yaml`,
246
246
  `aside.yaml`, `alert.yaml`, and `anchor-bar.yaml` (the last four
247
247
  corroborating it as a corpus-wide pattern, not a one-off).
248
248
 
249
- **Grammar authored `a2ui.examples[]` ids only:**
249
+ **Grammar, authored `a2ui.examples[]` ids only:**
250
250
 
251
251
  - **Kebab-case, role-descriptive.** The id names what the node IS or DOES in
252
252
  the example, not its position in the array. `quote-body`, not `q` or
253
253
  `node-2`.
254
254
  - **Unique per example.** Scoped to one `examples[]` entry, not the whole
255
- yaml reusing `header` across two examples in the same file is fine;
255
+ yaml, reusing `header` across two examples in the same file is fine;
256
256
  reusing an id twice inside one example is not (the renderer's flat
257
257
  `children: string[]` lookup would collide).
258
258
  - **Compound ids read parent-then-role** for a node that belongs to a named
259
- cluster: `kpi-revenue`, `kpi-revenue-value`, `kpi-revenue-label` not
259
+ cluster: `kpi-revenue`, `kpi-revenue-value`, `kpi-revenue-label`, not
260
260
  `k1`, `k1v`, `k1l`. This is what lets a reader studying the copy-paste-able
261
261
  example understand the structure from the ids alone, without cross-
262
262
  referencing the tree.
263
- - **Exception the root/wrapper id may stay short when the example has
263
+ - **Exception, the root/wrapper id may stay short when the example has
264
264
  exactly one top-level container and the short id is still a real word**,
265
265
  e.g. `card`, `row`, `panel`, as long as every id it contains follows the
266
266
  grammar. A single generic wrapper doesn't need `card-wrapper-root`; a
267
267
  wrapper's *children* still do.
268
268
  - Ids are internal wiring keys (`children: string[]` references, rendered
269
- only as `data-a2ui-id`) never user-visible copy but they double as the
269
+ only as `data-a2ui-id`), never user-visible copy, but they double as the
270
270
  readable structure of the example a consumer studies, which is the whole
271
271
  reason this grammar exists.
272
272
 
@@ -289,7 +289,7 @@ reported repro):
289
289
 
290
290
  ```jsonc
291
291
  // before (badge.yaml chart-dashboard, positional style mixed with semantic
292
- // ids in the SAME example k1/k1h/k1v alongside header-row/dash-title)
292
+ // ids in the SAME example, k1/k1h/k1v alongside header-row/dash-title)
293
293
  { "id": "k1", "component": "Card", "children": ["k1h", "k1v"] }
294
294
 
295
295
  // after
@@ -297,7 +297,7 @@ reported repro):
297
297
  ```
298
298
 
299
299
  **Enforcement**: the `EXAMPLE-ID-GRAMMAR` rule
300
- (`scripts/lint/rules/shared/example-id-grammar.mjs`, gh#2649 moved out of
300
+ (`scripts/lint/rules/shared/example-id-grammar.mjs`, gh#2649, moved out of
301
301
  the retired `scripts/verify/check-example-ids.mjs` into the shared lint
302
302
  rule bank per LLD-0016 §C3) walks every yaml's `examples[].a2ui` nodes and
303
303
  reports ids that fail the grammar (a bare 1-2 char id, a `^[a-z]\d+`
@@ -306,15 +306,15 @@ duplicate). gh#2492 Phase 2 swept the corpus-wide 526 violations across 48
306
306
  files to zero; `npm run check:example-id-grammar` keeps that promotion
307
307
  build-blocking in the `npm run check` chain (non-zero exit on any
308
308
  violation) even though the rule's own bank-default severity is
309
- `advisory` a new example that violates the grammar now fails the build
309
+ `advisory`, a new example that violates the grammar now fails the build
310
310
  immediately, not just on a future sweep. Known gap: the checker's
311
311
  positional-pattern regex catches `letter+digits` (`k1`, `c2`) but not a
312
- `letter-digit-letter-digit` chain like `g1i1` out of scope for this
312
+ `letter-digit-letter-digit` chain like `g1i1`, out of scope for this
313
313
  sweep (nothing flagged it), left for a future refinement.
314
314
 
315
315
  ---
316
316
 
317
- ## `status:` field stability tier
317
+ ## `status:` field, stability tier
318
318
 
319
319
  **Required** for all new components. Existing components default to `stable` if unset, but new yamls MUST set this explicitly.
320
320
 
@@ -326,134 +326,132 @@ sweep (nothing flagged it), left for a future refinement.
326
326
  | `deprecated` | Has a replacement; check the component's `related:` section. Docs site shows a `danger`-variant badge labeled "deprecated". |
327
327
  | `early-access` | Customer-preview tier; release notes gate. Docs site shows an `info`-variant badge labeled "early access". |
328
328
 
329
- **Ratified, closed enum compiler-enforced at build time, mirrored in the schema (ADR-0057, ratified 2026-08-15).** The five values above are the whole vocabulary; `draft` is NOT a value (the one `draft` in the estate, `embed-shell.yaml`, was corrected to `experimental` when the enum went live a sixth value on a single occurrence is data-entry drift, not a vocabulary gap). Enforcement: `scripts/build/components.mjs:105` holds `STATUS_VALUES` and `compileComponent()` (`components.mjs:258-260`) throws on any out-of-enum `status:` at the same place it throws on a missing `component:` so `npm run verify:components` (`node scripts/build/components.mjs --verify`, a member of the `npm run check` aggregate) hard-fails the yaml with a file-and-value error. An invalid status no longer merely skips a docs badge; it stops the build. `scripts/schemas/component.yaml.schema.json:23-27` declares the same enum (default `stable`) for the `$schema:` IDE contract, but no validator runs that file the hand-synced constant in `components.mjs` is the live gate. `status` is orthogonal to the ADR-0050 L0–L4 tier ladder (tier = what a component is composed of; status = how much to trust its contract today), and nothing in `packages/gen-ui/engine/retrieval/` filters or ranks on it. Source: ADR-0057.
329
+ **Ratified, closed enum, compiler-enforced at build time, mirrored in the schema (ADR-0057, ratified 2026-08-15).** The five values above are the whole vocabulary; `draft` is NOT a value (the one `draft` in the estate, `embed-shell.yaml`, was corrected to `experimental` when the enum went live, a sixth value on a single occurrence is data-entry drift, not a vocabulary gap). Enforcement: `scripts/build/components.mjs:105` holds `STATUS_VALUES` and `compileComponent()` (`components.mjs:258-260`) throws on any out-of-enum `status:` at the same place it throws on a missing `component:`, so `npm run verify:components` (`node scripts/build/components.mjs --verify`, a member of the `npm run check` aggregate) hard-fails the yaml with a file-and-value error. An invalid status no longer merely skips a docs badge; it stops the build. `scripts/schemas/component.yaml.schema.json:23-27` declares the same enum (default `stable`) for the `$schema:` IDE contract, but no validator runs that file, the hand-synced constant in `components.mjs` is the live gate. `status` is orthogonal to the ADR-0050 L0–L4 tier ladder (tier = what a component is composed of; status = how much to trust its contract today), and nothing in `packages/gen-ui/engine/retrieval/` filters or ranks on it. Source: ADR-0057.
330
330
 
331
331
  **Guidance**:
332
332
 
333
- - Set `beta` or `experimental` at FIRST AUTHORING for any component that's not in the stable API contract yet. Don't default to `stable` and bump later the badge is consumer-facing, and stable→beta is a downgrade signal.
333
+ - Set `beta` or `experimental` at FIRST AUTHORING for any component that's not in the stable API contract yet. Don't default to `stable` and bump later: the badge is consumer-facing, and stable→beta is a downgrade signal.
334
334
  - Only set `stable` after the component has shipped at least one MINOR cycle and gathered consumer feedback. The bar for `stable` is "no API changes anticipated in the next 3 MINOR releases."
335
335
  - `deprecated` requires a `related:` entry pointing at the replacement. Without one, consumers can't recover.
336
336
 
337
- **Sidecar emission**: `x-adiaui.status` field in `<name>.a2ui.json`. The docs site (`site/site.js`) reads this and injects the badge automatically no HTML change needed in `<name>.examples.html`.
337
+ **Sidecar emission**: `x-adiaui.status` field in `<name>.a2ui.json`. The docs site (`site/site.js`) reads this and injects the badge automatically, no HTML change needed in `<name>.examples.html`.
338
338
 
339
339
  **Verification**: `grep -L '^status:' packages/web-components/components/*/*.yaml` should return empty (every yaml has a status). Run before opening any authoring PR that adds new yamls.
340
340
 
341
341
  ---
342
342
 
343
- ## `category:` field functional grouping
343
+ ## `category:` field, functional grouping
344
344
 
345
- **Required.** Every yaml sets this; `scripts/build/components.mjs` forwards it verbatim onto the sidecar as `x-adiaui.category`, and `packages/gen-ui/engine/retrieval/catalog.js` reads it from there for every YAML-backed component no second, hand-maintained category list for anything with a yaml SoT. `catalog.js` does still carry one small, DELIBERATE exception: a 3-entry `PSEUDO_TYPE_CATEGORY` map (`section`/`header`/`footer` → `card-child`) for `@adia-ai/a2ui` registry pseudo-types that have no yaml SoT at all (v0.9 composition slot-children, not real primitives) nothing to derive from, so this one small map stays hand-maintained by design, not drift.
345
+ **Required.** Every yaml sets this; `scripts/build/components.mjs` forwards it verbatim onto the sidecar as `x-adiaui.category`, and `packages/gen-ui/engine/retrieval/catalog.js` reads it from there for every YAML-backed component, no second, hand-maintained category list for anything with a yaml SoT. `catalog.js` does still carry one small, DELIBERATE exception: a 3-entry `PSEUDO_TYPE_CATEGORY` map (`section`/`header`/`footer` → `card-child`) for `@adia-ai/a2ui` registry pseudo-types that have no yaml SoT at all (v0.9 composition slot-children, not real primitives), nothing to derive from, so this one small map stays hand-maintained by design, not drift.
346
346
 
347
347
  | Value | When to use |
348
348
  | --- | --- |
349
349
  | `action` | A standalone, click-to-fire trigger (`button-ui`, `toggle-scheme-ui`). |
350
- | `agent` | AI/agent-facing surfaces chat, trace, tool output, tabular/chart data views (`chat-thread-ui`, `agent-trace-ui`, `table-ui`, `chart-ui`, `embed-ui`). |
350
+ | `agent` | AI/agent-facing surfaces, chat, trace, tool output, tabular/chart data views (`chat-thread-ui`, `agent-trace-ui`, `table-ui`, `chart-ui`, `embed-ui`). |
351
351
  | `container` | A chrome/wrapping surface that holds other content (`card-ui`, `modal-ui`, `drawer-ui`, `menu-ui`, `command-ui`). |
352
352
  | `data` | Structured/tabular data display, not a full agent surface (`tree-ui`, `heatmap-ui`). |
353
- | `display` | Passive content rendering text, media, status glyphs (`text-ui`, `icon-ui`, `badge-ui`, `avatar-ui`, `link-ui`, `mark-ui`, `richtext-ui` a non-editable renderer, not a form field). |
353
+ | `display` | Passive content rendering, text, media, status glyphs (`text-ui`, `icon-ui`, `badge-ui`, `avatar-ui`, `link-ui`, `mark-ui`, `richtext-ui`, a non-editable renderer, not a form field). |
354
354
  | `feedback` | Status/notification/progress communication (`spinner-ui`, `inline-message-ui`, `progress-ui`, `progress-row-ui`, `step-progress-ui`, `feed-ui`, `feed-item-ui`). |
355
355
  | `form` | Data-entry composite/field-level components, not raw bindable controls (`field-ui`, `fields-ui`, `rating-ui`, `toggle-option-ui`). |
356
356
  | `input` | Bindable form controls (`input-ui`, `select-ui`, `check-ui`, `switch-ui`, `textarea-ui`, `radio-ui`). |
357
- | `layout` | Pure structural/spatial primitives no content semantics of their own (`row-ui`, `col-ui`, `grid-ui`, `stack-ui`, `list-ui`). |
358
- | `navigation` | Wayfinding/switcher controls, including a switcher family's child items (`breadcrumb-ui`, `pagination-ui`, `menu-item-ui`, `segmented-ui`/`segment-ui`, `tabs-ui`/`tab-ui`, `stepper-ui`/`stepper-item-ui`). `toggle-group-ui` is `navigation` too, but its child `toggle-option-ui` is `form` (a wrapper/item split, like `menu-ui`/`menu-item-ui` not a same-category pair). |
357
+ | `layout` | Pure structural/spatial primitives, no content semantics of their own (`row-ui`, `col-ui`, `grid-ui`, `stack-ui`, `list-ui`). |
358
+ | `navigation` | Wayfinding/switcher controls, including a switcher family's child items (`breadcrumb-ui`, `pagination-ui`, `menu-item-ui`, `segmented-ui`/`segment-ui`, `tabs-ui`/`tab-ui`, `stepper-ui`/`stepper-item-ui`). `toggle-group-ui` is `navigation` too, but its child `toggle-option-ui` is `form` (a wrapper/item split, like `menu-ui`/`menu-item-ui`, not a same-category pair). |
359
359
  | `shells` | Page-level app-shell composites (`simple-shell-ui` and its siblings). |
360
360
  | `utility` | Non-visual/accessibility helpers (`skip-nav-ui`, `visually-hidden-ui`). |
361
361
 
362
- **Ratified, closed enum compiler-enforced at build time, mirrored in the schema (ADR-0065).** These twelve values are the whole vocabulary; the census that ratified them found 18 free-form values in live use (typos like `forms`/`data-display`, one-off singletons, and three named misclassifications) all folded or corrected onto this set as part of the same change. Enforcement: `scripts/build/components.mjs` holds `CATEGORY_VALUES` and `compileComponent()` throws on a MISSING `category:` field (unlike `status:`, `category:` is required, not defaulted) as well as on any out-of-enum value, the same place and severity as the `status:` check above so `npm run verify:components` hard-fails an invalid OR absent category. `scripts/schemas/component.yaml.schema.json`'s `category` enum mirrors this list for the `$schema:` IDE contract; the hand-synced constant in `components.mjs` is the live gate, same relationship as `status`. Source: ADR-0065.
362
+ **Ratified, closed enum, compiler-enforced at build time, mirrored in the schema (ADR-0065).** These twelve values are the whole vocabulary; the census that ratified them found 18 free-form values in live use (typos like `forms`/`data-display`, one-off singletons, and three named misclassifications), all folded or corrected onto this set as part of the same change. Enforcement: `scripts/build/components.mjs` holds `CATEGORY_VALUES` and `compileComponent()` throws on a MISSING `category:` field (unlike `status:`, `category:` is required, not defaulted) as well as on any out-of-enum value, the same place and severity as the `status:` check above, so `npm run verify:components` hard-fails an invalid OR absent category. `scripts/schemas/component.yaml.schema.json`'s `category` enum mirrors this list for the `$schema:` IDE contract; the hand-synced constant in `components.mjs` is the live gate, same relationship as `status`. Source: ADR-0065.
363
363
 
364
364
  **The six one-off drift values ADR-0065 folded**, each independently justified by what the component does, not a blanket rule:
365
365
 
366
366
  | Drift value | Folds to | Example |
367
367
  | --- | --- | --- |
368
- | `forms` | `form` | `toggle-option.yaml` spelling drift against `form`'s existing members. |
369
- | `data-display` | `data` | `heatmap.yaml` joins `tree.yaml`/`tree-item.yaml`, same spelling drift shape. |
370
- | `content` | `display` | `link.yaml` inline content rendering, same role as `text-ui`/`code-ui`. |
371
- | `typography` | `display` | `mark.yaml` a text-highlight element, same role as `text-ui`. |
372
- | `control` | `action` | `toggle-scheme.yaml` a click-to-fire toggle, same shape as `button-ui`. |
373
- | `interaction` | `container` | `admin-command.yaml` a command-palette surface, same role as `command-ui`. |
368
+ | `forms` | `form` | `toggle-option.yaml`, spelling drift against `form`'s existing members. |
369
+ | `data-display` | `data` | `heatmap.yaml`, joins `tree.yaml`/`tree-item.yaml`, same spelling drift shape. |
370
+ | `content` | `display` | `link.yaml`, inline content rendering, same role as `text-ui`/`code-ui`. |
371
+ | `typography` | `display` | `mark.yaml`, a text-highlight element, same role as `text-ui`. |
372
+ | `control` | `action` | `toggle-scheme.yaml`, a click-to-fire toggle, same shape as `button-ui`. |
373
+ | `interaction` | `container` | `admin-command.yaml`, a command-palette surface, same role as `command-ui`. |
374
374
 
375
- Three named misclassifications were also fixed, not folded: `check.yaml`/`switch.yaml`/`textarea.yaml` (`layout` → `input` bindable form controls, not structural primitives), `tabs.yaml` (`container` → `navigation`, unifying with `tab.yaml`), and `feed.yaml` (`container` → `feedback`, unifying with `feed-item.yaml`). Full rationale and the progress-family partial unification: ADR-0065 Decision §2–§4.
375
+ Three named misclassifications were also fixed, not folded: `check.yaml`/`switch.yaml`/`textarea.yaml` (`layout` → `input`, bindable form controls, not structural primitives), `tabs.yaml` (`container` → `navigation`, unifying with `tab.yaml`), and `feed.yaml` (`container` → `feedback`, unifying with `feed-item.yaml`). Full rationale and the progress-family partial unification: ADR-0065 Decision §2–§4.
376
376
 
377
- **A sibling family (a wrapper + its child items, e.g. `tabs-ui`/`tab-ui`) is not required to share one category by default** `menu-ui` (`container`) + `menu-item-ui` (`navigation`) is a deliberate, working split. Where a family's sibling values disagreed with no evident rationale, ADR-0065 unified them; new families should pick per-component, not assume unification is required.
377
+ **A sibling family (a wrapper + its child items, e.g. `tabs-ui`/`tab-ui`) is not required to share one category by default**, `menu-ui` (`container`) + `menu-item-ui` (`navigation`) is a deliberate, working split. Where a family's sibling values disagreed with no evident rationale, ADR-0065 unified them; new families should pick per-component, not assume unification is required.
378
378
 
379
- **Sidecar emission**: `x-adiaui.category` field in `<name>.a2ui.json`. `packages/gen-ui/engine/retrieval/catalog.js`'s `buildCatalog()` reads this directly per entry no separate registration step.
379
+ **Sidecar emission**: `x-adiaui.category` field in `<name>.a2ui.json`. `packages/gen-ui/engine/retrieval/catalog.js`'s `buildCatalog()` reads this directly per entry, no separate registration step.
380
380
 
381
381
  ---
382
382
 
383
- ## Semantic color-family axis two role-classes, two names (ADR-0044, ADR-0064)
383
+ ## Semantic color-family axis, two role-classes, two names (ADR-0044, ADR-0064)
384
384
 
385
385
  Every component carries at most one STYLE axis and one FAMILY axis (the
386
386
  semantic color family: `default | info | success | warning | danger`,
387
387
  `+primary` where the role-class already carries brand emphasis), and every
388
388
  enum value belongs to exactly one axis. The family axis's ATTRIBUTE NAME is
389
- decided by role-class never one universal name (a same-name meaning-flip
389
+ decided by role-class, never one universal name (a same-name meaning-flip
390
390
  is a silent-failure migration and poisons the trained corpus, per ADR-0044
391
391
  LLD §3):
392
392
 
393
- - **Role-class A `variant` is unclaimed:** the family axis is named
393
+ - **Role-class A, `variant` is unclaimed:** the family axis is named
394
394
  `variant`. Badge/tag's ratified shape (ADR-0044), plus `rating-ui` and the
395
395
  `variant`-only siblings (inline-message, feed-item, empty-state, menu-item,
396
396
  progress-row).
397
- - **Role-class B an existing identity/style axis already claims the
397
+ - **Role-class B, an existing identity/style axis already claims the
398
398
  selector slot:** the family axis is named `color`. Button's shape
399
399
  (`variant`=style, `color`=family), extended by ADR-0064 to `text-ui`
400
400
  (`variant`=typography role), `chart-ui`/`heatmap-ui` (`type`=kind),
401
401
  `icon-ui` (`weight`=glyph style), `spinner-ui` (`variant`=animation), and
402
- `toggle-scheme-ui`. Renames owed by this ruling (follow-on build, gh#1376
403
- — not yet landed): `icon-ui[tone]` → `[color]`, `heatmap-ui[colorScheme]`
402
+ `toggle-scheme-ui`. Renames owed by this ruling (follow-on build, gh#1376, not yet landed): `icon-ui[tone]` → `[color]`, `heatmap-ui[colorScheme]`
404
403
  → `[color]`, `spinner-ui[tone]` → `[color]`.
405
404
 
406
- `accent` is RETIRED from the family enum everywhere ADR-0044 removed it
405
+ `accent` is RETIRED from the family enum everywhere, ADR-0044 removed it
407
406
  from badge/tag/button; ADR-0064 removes it from the seven stragglers
408
407
  (text, chart, icon, heatmap, rating, spinner, toggle-scheme) with no
409
408
  replacement value. Never mint `accent` in a new enum.
410
409
 
411
- Two ratified non-family exceptions the name without the semantics:
410
+ Two ratified non-family exceptions, the name without the semantics:
412
411
 
413
- - `swatch-ui[color]` / `noodles-ui[color]` an arbitrary CSS color string,
412
+ - `swatch-ui[color]` / `noodles-ui[color]`, an arbitrary CSS color string,
414
413
  not a semantic enum (ADR-0054 §11 exemption, unchanged).
415
- - `spinner-ui[color]` (post-rename) a closed contrast-mode enum
414
+ - `spinner-ui[color]` (post-rename), a closed contrast-mode enum
416
415
  (`current | subtle | inverse`), NOT the family vocabulary; never assume it
417
416
  accepts `info`/`success`/`warning`/`danger` by analogy.
418
417
 
419
418
  ---
420
419
 
421
- ## Catalog tiers L0–L4, `origin`, and the promotion rule (ADR-0050, ADR-0066)
420
+ ## Catalog tiers, L0–L4, `origin`, and the promotion rule (ADR-0050, ADR-0066)
422
421
 
423
- ADR-0050's L0–L4 ladder is the ONLY tier grammar never mint a second
422
+ ADR-0050's L0–L4 ladder is the ONLY tier grammar, never mint a second
424
423
  manifest format. ADR-0066 refines it three ways:
425
424
 
426
- - **`origin: primitive | module` on every L0 entry** both YAML source
425
+ - **`origin: primitive | module` on every L0 entry**, both YAML source
427
426
  roots (web-components primitives AND web-modules composites) compile into
428
427
  the same `catalog-a2ui_1_0.json` through one shared contract;
429
428
  `derive-catalog-tiers.mjs` stamps which root an entry came from onto
430
429
  `tier-index.json`. A module is legitimately a member of TWO rungs at two
431
430
  grains: its component API (props/events/slots) is L0, its assembled shell
432
- composition is L3 ruled correct, not a modeling defect.
431
+ composition is L3, ruled correct, not a modeling defect.
433
432
  - **The promotion rule, stated once:** patterns/zettel compositions are the
434
- SOLE promotion source, and they enter the ladder at exactly one point
435
- pattern → L1 widget, through `curate-l1-widgets.mjs`'s gates (which writes
433
+ SOLE promotion source, and they enter the ladder at exactly one point, pattern → L1 widget, through `curate-l1-widgets.mjs`'s gates (which writes
436
434
  only `l1-widgets.json`). The higher rungs (L1 → L2 → L3 → L4) are AUTHORED
437
- edges hand-written `tiers/l*-*.json` manifests whose `composes` reference
435
+ edges, hand-written `tiers/l*-*.json` manifests whose `composes` reference
438
436
  the rung below, reserved/unblocked per ADR-0050's own phasing; a module's
439
437
  L3 membership comes from an authored L3 manifest, never from its yaml
440
438
  (which contributes only the L0 entry + `origin`). There is no
441
439
  patterns↔module edge, primitives and modules never "promote" into each
442
- other, and nothing promotes automatically or in reverse curation is the
440
+ other, and nothing promotes automatically or in reverse, curation is the
443
441
  one-way valve (ADR-0050: "corpus derives from catalogs, never the
444
442
  reverse").
445
443
  - **The two pattern-facing outputs stay separate by design:**
446
444
  `site/patterns-index.json` / `pattern-index.md` are a generated,
447
445
  developer-facing index over the FULL pattern/template census, intentionally
448
- independent of the L0–L4 machine-validated schema a different audience,
446
+ independent of the L0–L4 machine-validated schema, a different audience,
449
447
  never a convergence gap to "fix".
450
448
 
451
- (`status:` above is orthogonal to the tier ladder tier = what an entry is
449
+ (`status:` above is orthogonal to the tier ladder, tier = what an entry is
452
450
  composed of; status = how much to trust its contract today.)
453
451
 
454
452
  ---
455
453
 
456
- ## `props:` field prop schemas
454
+ ## `props:` field, prop schemas
457
455
 
458
456
  Each prop is a top-level key inside `props:`. The full prop schema:
459
457
 
@@ -473,13 +471,13 @@ props:
473
471
  - ghost
474
472
  ```
475
473
 
476
- ### Synthesized universal props `slot` / `hidden` / `ariaLive` / `traits`
474
+ ### Synthesized universal props, `slot` / `hidden` / `ariaLive` / `traits`
477
475
 
478
476
  `deriveProps()` (`scripts/build/derive-genui-catalog.mjs`) prepends three
479
477
  props to every component's generated catalog schema before it ever reads a
480
478
  yaml's own `props:` block: `slot: {type: string}`, `hidden: {type:
481
479
  boolean}`, `ariaLive: {type: string}` (REQ-013 accessibility pair, gh#1353).
482
- **No yaml SoT declares any of these** they're synthesized, not authored,
480
+ **No yaml SoT declares any of these**, they're synthesized, not authored,
483
481
  and a sidecar that ever DOES declare one of these keys itself simply
484
482
  overwrites the synthesized definition.
485
483
 
@@ -488,27 +486,26 @@ overwrites the synthesized definition.
488
486
  ratified via PR #2524) rules that `traits: {type: string}` becomes a fourth
489
487
  member of this synthesized set, carrying the same space-separated grammar
490
488
  as the existing HTML `[traits="…"]` declarative attribute
491
- (`.claude/docs/specs/traits.md`, "Method 3" `"ripple confetti-burst"`,
492
- not a JSON array) making `traits` legal on every component's A2UI wire
489
+ (`.claude/docs/specs/traits.md`, "Method 3", `"ripple confetti-burst"`,
490
+ not a JSON array), making `traits` legal on every component's A2UI wire
493
491
  schema with no renderer change, and, once wired, checked by
494
492
  `catalog-validator.js` against the live trait registry
495
493
  (`packages/web-components/traits/_catalog.json`) with a **hard FAIL on an
496
494
  unknown trait name** (the same rejection behavior the raw HTML mechanism
497
495
  already has). As of this writing `deriveProps()` still synthesizes only the
498
- three props above and `catalog-validator.js` has no trait-name check
499
- gh#2513 tracks the build.
496
+ three props above and `catalog-validator.js` has no trait-name check, gh#2513 tracks the build.
500
497
 
501
498
  ### Sentinel-0 defaults and tag-promoting props (ADR-0102, 2026-09-01)
502
499
 
503
- Not every escape hatch belongs on `CatalogComponentCommon` a prop scoped
500
+ Not every escape hatch belongs on `CatalogComponentCommon`, a prop scoped
504
501
  to one component's own semantics stays on that component's own yaml, even
505
502
  when it changes the rendered tag. `text-ui`'s `level` (integer 0-6,
506
503
  default `0`) is the worked example: `0` is the sentinel for "no
507
- promotion, current behavior" the same `0 = off` convention `text-ui`'s
508
- own `lines` prop already used (`lines: 0` = no clamp) and `1`-`6`
504
+ promotion, current behavior", the same `0 = off` convention `text-ui`'s
505
+ own `lines` prop already used (`lines: 0` = no clamp), and `1`-`6`
509
506
  promotes the rendered element to a real native `<h1>`-`<h6>`, independent
510
507
  of `variant` (which stays presentational-only: typography tokens, never a
511
- tag). `deriveProps()` needs no change for this a per-sidecar prop like
508
+ tag). `deriveProps()` needs no change for this, a per-sidecar prop like
512
509
  `level` already flows into the generated catalog schema generically; only
513
510
  a `CatalogComponentCommon` universal (`slot`/`hidden`/`ariaLive`/`traits`,
514
511
  above) needs a wire-schema edit. See ADR-0102 for the full contract
@@ -520,11 +517,11 @@ above) needs a wire-schema edit. See ADR-0102 for the full contract
520
517
 
521
518
  | Use `required: true` | Don't use `required: true` |
522
519
  | --- | --- |
523
- | `field-ui.label` no visible/accessible label without it | `button-ui.variant` has a sensible default |
524
- | `icon-ui.name` nothing renders without it | `select-ui.placeholder` useful but optional |
525
- | `nav-item-ui.text` empty nav item | `card-ui.size` affects styling, not function |
526
- | `chart-ui.type` can't render a chart of "nothing" | `stat-ui.change-indicator` optional enhancement |
527
- | `tabs-ui.value` needs an initial selected tab | `tag-ui.variant` has a default |
520
+ | `field-ui.label`, no visible/accessible label without it | `button-ui.variant`, has a sensible default |
521
+ | `icon-ui.name`, nothing renders without it | `select-ui.placeholder`, useful but optional |
522
+ | `nav-item-ui.text`, empty nav item | `card-ui.size`, affects styling, not function |
523
+ | `chart-ui.type`, can't render a chart of "nothing" | `stat-ui.change-indicator`, optional enhancement |
524
+ | `tabs-ui.value`, needs an initial selected tab | `tag-ui.variant`, has a default |
528
525
 
529
526
  **Heuristic**: ask "if I author `<my-component-ui></my-component-ui>` with nothing else, is the component **broken** or just **default-styled**?" If broken → mark required. If default-styled → don't.
530
527
 
@@ -540,11 +537,11 @@ above) needs a wire-schema edit. See ADR-0102 for the full contract
540
537
  - `rating-ui.value`
541
538
  - `tabs-ui.value`
542
539
 
543
- **Sidecar emission**: `required: true` propagates to the JSON Schema `required` array in `<name>.a2ui.json`. The A2UI validator + MCP tools consume this array correct marking improves validation quality on generated UI trees.
540
+ **Sidecar emission**: `required: true` propagates to the JSON Schema `required` array in `<name>.a2ui.json`. The A2UI validator + MCP tools consume this array, correct marking improves validation quality on generated UI trees.
544
541
 
545
542
  **Anti-pattern**: marking ALL props required because they all "have a useful value." That defeats the validation signal. `required` is a strict-failure constraint, not a "recommended" hint.
546
543
 
547
- ### `type: array` `items.type` is LOAD-BEARING (gh#970)
544
+ ### `type: array`, `items.type` is LOAD-BEARING (gh#970)
548
545
 
549
546
  An array prop's catalog mapping (components.mjs TKT-0010) branches on
550
547
  `items.type`:
@@ -559,14 +556,14 @@ options:
559
556
  dynamic: true
560
557
  ```
561
558
 
562
- - `items: {type: object}` → `#/$defs/DynamicObjectList` rich option
559
+ - `items: {type: object}` → `#/$defs/DynamicObjectList`, rich option
563
560
  objects validate.
564
- - **`items` omitted → `#/$defs/DynamicStringList` silently** and the
561
+ - **`items` omitted → `#/$defs/DynamicStringList` silently**, and the
565
562
  dialect validator then REJECTS every real composition that passes rich
566
563
  objects ("/options/0 must be string … oneOf"). command-ui and
567
564
  combobox-ui both shipped this way; nothing caught it until the
568
565
  `exit-gate.corpus` gate at v0.8.34 release pre-flight (that gate runs
569
- in the release serial suite, NOT in PR CI the failure lands at cut
566
+ in the release serial suite, NOT in PR CI, the failure lands at cut
570
567
  time, weeks after the yaml edit).
571
568
 
572
569
  **Heuristic**: if the prop description says "Array of {…}", the yaml MUST
@@ -590,14 +587,14 @@ string-list schema is the exact silent-mismatch shape.
590
587
  **Authoring contract**:
591
588
 
592
589
  1. **DO NOT use these attribute names for any other purpose** (table column markers, sort-state, etc.) inside `<admin-shell>` descendants. The CSS rules will apply unintended layout. Use namespaced names instead (`data-page-col`, `data-sort-col`, `data-my-actions`).
593
- 2. **`admin-shell` ancestor is required**. An earlier dist CSS shipped bare global selectors that applied to ANY element with these attributes on ANY page loading `admin-shell.min.css` including `<table>` headers (silent layout breakage in Safari/WebKit). Source + dist now both prefix `admin-shell` ancestor. This is a hard constraint: the parent-tag selector is the only reliable CDN-safe scoping mechanism (LightningCSS strips `@scope` blocks).
590
+ 2. **`admin-shell` ancestor is required**. An earlier dist CSS shipped bare global selectors that applied to ANY element with these attributes on ANY page loading `admin-shell.min.css`, including `<table>` headers (silent layout breakage in Safari/WebKit). Source + dist now both prefix `admin-shell` ancestor. This is a hard constraint: the parent-tag selector is the only reliable CDN-safe scoping mechanism (LightningCSS strips `@scope` blocks).
594
591
  3. **Outside `<admin-shell>`, these names have NO EFFECT**. If you need `[data-col]` semantics on a non-admin-shell page, you must author your own CSS (the helpers do not apply globally).
595
592
 
596
593
  **Documented for consumers** in the adia-factory plugin's composition references (reserved layout-helper attribute names).
597
594
 
598
595
  ---
599
596
 
600
- ## `data-msg-*` exempt component-side config family (gh#1332/#1464, ADR-0060)
597
+ ## `data-msg-*`, exempt component-side config family (gh#1332/#1464, ADR-0060)
601
598
 
602
599
  `data-msg-required` / `data-msg-pattern` / `data-msg-minlength` /
603
600
  `data-msg-maxlength` / `data-msg-min` / `data-msg-max` / `data-msg-bad-input`
@@ -607,29 +604,28 @@ are read directly by form-associated components (`core/form.js`'s shared
607
604
  `payment-method-form.class.js`) to override a native constraint-violation's
608
605
  default message with a consumer-supplied string.
609
606
 
610
- **Disposition: EXEMPT never declared as a yaml `states:`/`props:` entry.**
607
+ **Disposition: EXEMPT, never declared as a yaml `states:`/`props:` entry.**
611
608
  Both yaml surfaces this contract offers are the wrong shape for this family:
612
609
 
613
610
  - `states:` declares **presence-boolean host state the component itself
614
611
  reflects outward** (idle/loaded/error, this file's own §Reserved section's
615
- neighbor pattern) `data-msg-*` carries no state at all; it is a
612
+ neighbor pattern), `data-msg-*` carries no state at all; it is a
616
613
  consumer-authored string the component only ever *reads*, never sets.
617
614
  - `props:` would need one string prop per validation-message key, repeated
618
- across every one of the 7+ consuming components but the read path is
615
+ across every one of the 7+ consuming components, but the read path is
619
616
  `core/form.js`'s shared mixin, not any single component's own yaml SoT.
620
617
  Declaring it per-component would multiply one shared mixin contract across
621
- every consumer's yaml with no single owning SoT to declare it once a
618
+ every consumer's yaml with no single owning SoT to declare it once, a
622
619
  cross-cutting mixin-contract change, not a per-component yaml edit.
623
620
 
624
621
  ADR-0060's own boundary discriminator (§Decision 3) already places this
625
622
  family outside the trait-tier `data-*` ratification and explicitly routes it
626
- "to gh#1332's Category A/D triage for its own converge-or-ratify call" this
623
+ "to gh#1332's Category A/D triage for its own converge-or-ratify call": this
627
624
  section IS that call. The family stays `data-*`, undeclared in any yaml,
628
625
  with its contract documented at the shared source instead: `core/form.js`'s
629
626
  own header JSDoc (the mixin all consumers share) and the canonical
630
627
  `form-system` pattern doc (`packages/web-components/patterns/form-system/
631
- form-system.examples.html`, rendered directly at `/site/patterns/form-system`)
632
- — both already enumerate the full family with a worked example. A future
628
+ form-system.examples.html`, rendered directly at `/site/patterns/form-system`), both already enumerate the full family with a worked example. A future
633
629
  architectural pass that wants to
634
630
  promote this to a declared per-component contract needs its own ADR (the
635
631
  scope is a mixin-wide contract change, not a small-ticket edit); nothing
@@ -648,14 +644,14 @@ node scripts/build/components.mjs --verify # same as above, direct invocation
648
644
  The build:
649
645
 
650
646
  1. Reads every `<name>.yaml` under `packages/web-components/components/` and `packages/web-modules/<cluster>/`
651
- 2. Hand-checks the source yaml in `compileComponent()` missing `component:` and out-of-enum `status:` both throw (`components.mjs:255-260`). Amended 2026-08-16 per ADR-0057: it does NOT run `scripts/schemas/component.yaml.schema.json` as a validator (an earlier revision of this list claimed it did); the schema file is documentation + IDE contract only.
647
+ 2. Hand-checks the source yaml in `compileComponent()`, missing `component:` and out-of-enum `status:` both throw (`components.mjs:255-260`). Amended 2026-08-16 per ADR-0057: it does NOT run `scripts/schemas/component.yaml.schema.json` as a validator (an earlier revision of this list claimed it did); the schema file is documentation + IDE contract only.
652
648
  3. Emits `<name>.a2ui.json` (the sidecar) co-located with the yaml + js + css
653
649
  4. Emits the `traits/_catalog.json` aggregate
654
650
  5. `--verify` mode: re-runs steps 1-4 in-memory and fails if any sidecar drifts from disk content (CI hard-fail)
655
651
 
656
- **Never hand-edit `<name>.a2ui.json`** it's regenerated from the yaml. The yaml is the SoT.
652
+ **Never hand-edit `<name>.a2ui.json`**: it's regenerated from the yaml. The yaml is the SoT.
657
653
 
658
- **Downstream of the sidecars two more derived artifacts (gh#970's release-PR stop):**
654
+ **Downstream of the sidecars, two more derived artifacts (gh#970's release-PR stop):**
659
655
 
660
656
  ```bash
661
657
  node scripts/build/derive-genui-catalog.mjs # genui's five opt-out-scoped catalogs derive FROM the sidecars
@@ -664,7 +660,7 @@ npm run check:genui-catalog # the drift gate that fails PR CI
664
660
 
665
661
  Any yaml change that alters a sidecar's prop schemas STALES the genui
666
662
  catalog. The main regen chain (`harvest:chunks` → `build:embeddings:chunks`
667
- → `build:patterns-index`) does NOT cover it it's a separate derivation
663
+ → `build:patterns-index`) does NOT cover it, it's a separate derivation
668
664
  with its own gate, and skipping it passes every local check that isn't
669
665
  `check:genui-catalog` itself.
670
666
 
@@ -676,8 +672,8 @@ This is the canonical end-to-end procedure for creating a new component yaml + j
676
672
 
677
673
  1. **Author `<name>.yaml`** with all required fields:
678
674
  - `name:`, `tag:`, `component:`, `category:`, `version: 1`
679
- - `status:` pick from the table above
680
- - `description:` concrete one-paragraph
675
+ - `status:`, pick from the table above
676
+ - `description:`, concrete one-paragraph
681
677
  - `props:` with per-prop `type:`, `default:`, optional `required: true`, optional `enum:` / `values:`
682
678
  - `events:`, `slots:`, `css-vars:` as applicable
683
679
  2. **Author `<name>.js`** following the `UIElement` / `UIFormElement` patterns (see [code-style.md](code-style.md))
@@ -700,20 +696,20 @@ This is the canonical end-to-end procedure for creating a new component yaml + j
700
696
  node scripts/docs/anatomy-sweep.mjs
701
697
  ```
702
698
 
703
- This auto-generates the **canonical anatomy sections** (`slots`, `data-attrs`, `keyboard`, `css-vars`, `a2ui`, `related`) from the sidecar. The sweep is idempotent skip-on-already-present, safe to re-run. Hand-author `accessibility` and any prop-demo sections; the sweep covers the schema-derivable sections only.
699
+ This auto-generates the **canonical anatomy sections** (`slots`, `data-attrs`, `keyboard`, `css-vars`, `a2ui`, `related`) from the sidecar. The sweep is idempotent, skip-on-already-present, safe to re-run. Hand-author `accessibility` and any prop-demo sections; the sweep covers the schema-derivable sections only.
704
700
 
705
701
  Canonical `data-property` vocabulary for `<section data-section data-property="X">`:
706
- - `usage` canonical worked example
707
- - `props` prop reference table
708
- - `slots` named-slot semantics
709
- - `events` fired events
710
- - `data-attrs` `data-*` attributes the component reads
711
- - `css-vars` CSS custom properties
712
- - `keyboard` keyboard interaction model
713
- - `accessibility` ARIA, screen-reader notes
714
- - `a2ui` A2UI runtime integration notes
715
- - `related` sibling/replacement components
716
- - `<prop-name>` visual demo for a specific prop
702
+ - `usage`, canonical worked example
703
+ - `props`, prop reference table
704
+ - `slots`, named-slot semantics
705
+ - `events`, fired events
706
+ - `data-attrs`, `data-*` attributes the component reads
707
+ - `css-vars`, CSS custom properties
708
+ - `keyboard`, keyboard interaction model
709
+ - `accessibility`, ARIA, screen-reader notes
710
+ - `a2ui`, A2UI runtime integration notes
711
+ - `related`, sibling/replacement components
712
+ - `<prop-name>`, visual demo for a specific prop
717
713
 
718
714
  The sweep also **normalizes legacy section data-properties**: `Properties` → `props`, `Events` → `events`, `CSS Tokens` → `css-vars`, `Usage` → `usage`. Run with `--dry` first to preview changes:
719
715
 
@@ -734,10 +730,10 @@ After the playbook, the component is consumable by the docs site, the A2UI runti
734
730
 
735
731
  ## Cross-references
736
732
 
737
- - `.claude/docs/specs/component-token-contract.md` token/variant/mode contract
738
- - `.claude/docs/specs/component-implementation-patterns.md` implementation patterns
739
- - [code-style.md](code-style.md) JS code style rules
740
- - [css-patterns.md](css-patterns.md) light-DOM CSS cascade rules
741
- - [api-contract.md](api-contract.md) props/events/slots conventions
742
- - [authoring-cycle.md](authoring-cycle.md) the 5-step authoring procedure
743
- - `scripts/schemas/component.yaml.schema.json` JSON Schema (documented contract + IDE aid; not run as a validator `compileComponent()` enforces only `component:` and the `status` enum, see §Build pipeline)
733
+ - `.claude/docs/specs/component-token-contract.md`, token/variant/mode contract
734
+ - `.claude/docs/specs/component-implementation-patterns.md`, implementation patterns
735
+ - [code-style.md](code-style.md), JS code style rules
736
+ - [css-patterns.md](css-patterns.md), light-DOM CSS cascade rules
737
+ - [api-contract.md](api-contract.md), props/events/slots conventions
738
+ - [authoring-cycle.md](authoring-cycle.md), the 5-step authoring procedure
739
+ - `scripts/schemas/component.yaml.schema.json`, JSON Schema (documented contract + IDE aid; not run as a validator, `compileComponent()` enforces only `component:` and the `status` enum, see §Build pipeline)