@adia-ai/adia-ui-factory 0.2.2 → 0.2.4

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 (95) hide show
  1. package/.claude-plugin/plugin.json +12 -3
  2. package/.mcp.json +1 -1
  3. package/CHANGELOG.md +12 -0
  4. package/README.md +24 -1
  5. package/bin/adia-scaffold +93 -13
  6. package/package.json +1 -1
  7. package/references/shell-embed.md +10 -0
  8. package/references/spa-architecture.md +7 -0
  9. package/skills/adia-ui-kit/CHANGELOG.md +41 -0
  10. package/skills/adia-ui-kit/SKILL.md +442 -0
  11. package/skills/adia-ui-kit/assets/figma-make/guidelines/Guidelines.md +87 -0
  12. package/skills/adia-ui-kit/assets/figma-make/guidelines/components.md +142 -0
  13. package/skills/adia-ui-kit/assets/figma-make/guidelines/styles.md +118 -0
  14. package/skills/adia-ui-kit/assets/figma-make/guidelines/tokens.md +120 -0
  15. package/skills/adia-ui-kit/assets/team-scaffold/archive-README.md +30 -0
  16. package/skills/adia-ui-kit/assets/team-scaffold/drafts-README.md +57 -0
  17. package/skills/adia-ui-kit/assets/team-scaffold/inbox-README.md +76 -0
  18. package/skills/adia-ui-kit/assets/team-scaffold/outbox-README.md +46 -0
  19. package/skills/adia-ui-kit/assets/team-scaffold/team-root.README.md +51 -0
  20. package/skills/adia-ui-kit/assets/team-scaffold/tickets-README.md +208 -0
  21. package/skills/adia-ui-kit/assets/team-scaffold/tickets-REGISTRY.md +81 -0
  22. package/skills/adia-ui-kit/assets/templates/AGENTS.template.md +128 -0
  23. package/skills/adia-ui-kit/assets/templates/CLAUDE.template.md +1 -0
  24. package/skills/adia-ui-kit/assets/templates/FEEDBACK-OMISSIONS-DEFENSE.template.md +150 -0
  25. package/skills/adia-ui-kit/assets/templates/FEEDBACK.template.md +213 -0
  26. package/skills/adia-ui-kit/assets/templates/RESPONSE.template.md +114 -0
  27. package/skills/adia-ui-kit/assets/templates/figma-make-guidelines.md +90 -0
  28. package/skills/adia-ui-kit/evals/adversarial-content-trust.json +83 -0
  29. package/skills/adia-ui-kit/evals/evals.json +55 -0
  30. package/skills/adia-ui-kit/evals/routing-corpus.json +121 -0
  31. package/skills/adia-ui-kit/evals/teach-routing-cases.json +92 -0
  32. package/skills/adia-ui-kit/references/capabilities.md +245 -0
  33. package/skills/adia-ui-kit/references/catalog-lookup.md +186 -0
  34. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v1.md +8 -0
  35. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v2.md +3585 -0
  36. package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v3.md +1899 -0
  37. package/skills/adia-ui-kit/references/common-gotchas-consumer.md +522 -0
  38. package/skills/adia-ui-kit/references/component-literacy.md +291 -0
  39. package/skills/adia-ui-kit/references/composition.md +245 -0
  40. package/skills/adia-ui-kit/references/correction-loop.md +462 -0
  41. package/skills/adia-ui-kit/references/css-policy.md +343 -0
  42. package/skills/adia-ui-kit/references/decision-model.md +158 -0
  43. package/skills/adia-ui-kit/references/diagnostic-output.md +57 -0
  44. package/skills/adia-ui-kit/references/docs-catalog.md +239 -0
  45. package/skills/adia-ui-kit/references/exclusions.md +225 -0
  46. package/skills/adia-ui-kit/references/feedback-authoring.md +466 -0
  47. package/skills/adia-ui-kit/references/figma-make.md +244 -0
  48. package/skills/adia-ui-kit/references/flows-auth.md +307 -0
  49. package/skills/adia-ui-kit/references/flows-content.md +206 -0
  50. package/skills/adia-ui-kit/references/flows-data.md +348 -0
  51. package/skills/adia-ui-kit/references/flows-interaction.md +181 -0
  52. package/skills/adia-ui-kit/references/flows-shells.md +336 -0
  53. package/skills/adia-ui-kit/references/gap-detection.md +266 -0
  54. package/skills/adia-ui-kit/references/harness.md +284 -0
  55. package/skills/adia-ui-kit/references/loading-protocol.md +406 -0
  56. package/skills/adia-ui-kit/references/local-link.md +198 -0
  57. package/skills/adia-ui-kit/references/mcp.md +401 -0
  58. package/skills/adia-ui-kit/references/migration.md +116 -0
  59. package/skills/adia-ui-kit/references/mission.md +194 -0
  60. package/skills/adia-ui-kit/references/mode-routing.md +298 -0
  61. package/skills/adia-ui-kit/references/patterns-agent.md +223 -0
  62. package/skills/adia-ui-kit/references/patterns-data.md +1065 -0
  63. package/skills/adia-ui-kit/references/patterns-forms.md +223 -0
  64. package/skills/adia-ui-kit/references/patterns-layout.md +326 -0
  65. package/skills/adia-ui-kit/references/patterns-recipes.md +1416 -0
  66. package/skills/adia-ui-kit/references/patterns-shells.md +1097 -0
  67. package/skills/adia-ui-kit/references/patterns-traits.md +259 -0
  68. package/skills/adia-ui-kit/references/patterns-wiring.md +339 -0
  69. package/skills/adia-ui-kit/references/pev-rationale.md +137 -0
  70. package/skills/adia-ui-kit/references/reasoning-gate.md +146 -0
  71. package/skills/adia-ui-kit/references/reasoning-methodologies.md +112 -0
  72. package/skills/adia-ui-kit/references/recon.md +192 -0
  73. package/skills/adia-ui-kit/references/rendering-model.md +431 -0
  74. package/skills/adia-ui-kit/references/response-authoring.md +398 -0
  75. package/skills/adia-ui-kit/references/session-log-schema.md +203 -0
  76. package/skills/adia-ui-kit/references/session-log-template.md +118 -0
  77. package/skills/adia-ui-kit/references/setup.md +652 -0
  78. package/skills/adia-ui-kit/references/skill-hygiene.md +135 -0
  79. package/skills/adia-ui-kit/references/spec-to-ui-reasoning.md +394 -0
  80. package/skills/adia-ui-kit/references/state.md +229 -0
  81. package/skills/adia-ui-kit/references/teach-protocol.md +421 -0
  82. package/skills/adia-ui-kit/references/theme.md +142 -0
  83. package/skills/adia-ui-kit/references/version-check.md +69 -0
  84. package/skills/adia-ui-kit/scripts/audit-decision-trace.mjs +198 -0
  85. package/skills/adia-ui-kit/scripts/audit-kit-roster.mjs +366 -0
  86. package/skills/adia-ui-kit/scripts/changelog-archive.mjs +126 -0
  87. package/skills/adia-ui-kit/scripts/check-adia-versions.py +404 -0
  88. package/skills/adia-ui-kit/scripts/run-skill-evals.mjs +358 -0
  89. package/skills/adia-ui-kit/scripts/validate-session-log.mjs +242 -0
  90. package/skills/adia-ui-kit/skill.json +102 -0
  91. package/skills/adia-ui-migration/CHANGELOG.md +47 -0
  92. package/skills/adia-ui-migration/SKILL.md +381 -0
  93. package/skills/adia-ui-migration/skill.json +29 -0
  94. package/skills/adia-ui-spa/SKILL.md +1 -1
  95. package/skills/adia-ui-verify/SKILL.md +2 -2
@@ -0,0 +1,291 @@
1
+ ---
2
+ name: component-literacy
3
+ load-when: Before Rung 13 (Component selection) when input is composition or PRD-derived intent. Fires in conjunction with picking AdiaUI primitives at kit §1 Catalog Lookup. The literacy gate that prevents CSS-illiteracy as accepted composition posture.
4
+ load-size-tokens: ~2,800
5
+ required-for:
6
+ - Mode 1-4 composition that selects 3+ substrate primitives
7
+ - Any composition that embeds composites (admin-shell, chat-shell, editor-shell, payment-method-list, etc.) — embedded composites inherit visual surface from their CSS
8
+ - NAILED tier of kit verify-target (structurally-verified-only does not require this; nailed does)
9
+ companion-skill: "adia-ui-authoring v1.8.0+ (Phase 2.5a — kit's literacy gate is its sister skill's protocol applied at composition tier)"
10
+ postmortem-precedent:
11
+ - ".brain/postmortems/2026-05-24-component-css-illiteracy.md (v1.8.0 — CSS-illiteracy as authoring failure mode)"
12
+ - ".brain/postmortems/2026-05-24-card-structure-audit-enforcement-gap.md (v1.8.1 — detector ≠ enforcement; the second-order failure mode)"
13
+ ---
14
+
15
+ # Component Literacy — kit's pre-Rung-13 gate
16
+
17
+ > **The kit's Goodhart risk:** §Plan-Execute-Verify Mode 1-4 verify-target ("render in playground + audit scripts pass") is structurally self-passable. Audits validate recipe markup against substrate yaml SoT but never measure visual proportions, never read primitive CSS, never check token contracts beyond name validity. A composition can pass every audit gate while shipping a visual defect because the agent never opened the components' `.css` files. Authoring's 2026-05-24 CSS-illiteracy postmortem proved this is not a hypothetical failure — it is the default failure when verify metrics are author-designed and CSS reads are optional.
18
+
19
+ This reference is the kit's **Rung 13 precondition gate** — fires in conjunction with kit §1 Catalog Lookup when selecting AdiaUI primitives for a composition. It does not replace §1; it forces the CSS read to happen at selection time rather than after-the-fact (or never).
20
+
21
+ Sister-skill alignment: `adia-ui-authoring` v1.8.0 ships the same gate as §Phase 2.5a for composite-demo authoring. The two senior skills share the literacy discipline at different tiers of the AdiaUI workflow (kit = composition; authoring = substrate primitive authoring). Both produce a `preflight.yaml` artifact with the same shape.
22
+
23
+ ---
24
+
25
+ ## §When to load this reference
26
+
27
+ Fires when:
28
+
29
+ - Selecting 3+ AdiaUI primitives at kit §1 Catalog Lookup
30
+ - Embedding ANY composite (admin-shell, chat-shell, editor-shell, simple-shell, payment-method-list, search-result, etc.) — composites inherit visual surface from their CSS at embed time
31
+ - Targeting the `nailed` tier of kit §PEV Mode 1-4 verify-target (vs the default `structurally-verified-only`)
32
+ - After §SpecToUi resolves Rungs 0-12 + wireframe, BEFORE handing off to §1
33
+
34
+ Skip when:
35
+
36
+ - Composition uses ≤2 primitives the agent has already read in this session (cite the read; don't re-read)
37
+ - The verify-target chosen at the §Plan step is `structurally-verified-only` only (machine-signals-only — no human visual ack required)
38
+
39
+ > **Next-layer companion**: after the literacy gate fires, the four recurring consumer-side composition traps live in [`common-gotchas-consumer.md`](common-gotchas-consumer.md) (composite grammar bypass · parent CSS clobbering child display · mixed control sizes · `minmax(min, 1fr)` vs container queries). Reading is not recognizing — that reference is the checklist for what the literacy reads SHOULD have made you notice. Load it before Phase 4 author or when debugging "audit passes but looks broken" defects. Sister-aligned with `adia-ui-authoring` v1.8.2.
40
+
41
+ ---
42
+
43
+ ## §What the gate enforces (3 invariants)
44
+
45
+ **1. The agent cannot fill in literacy fields without opening the CSS.**
46
+
47
+ The required fields (`default_render`, `slot_sizing_rules`, `exposed_tokens`, `embed_gotchas`) exist BECAUSE they are unfabricable. Skim-and-make-up is detectable in review (and self-evident on the next read by anyone else). If you cannot write three sentences about what `<table-ui>` renders at default — what its padding, border, alternation, and density signature look like — you have not read its CSS, and you are about to compose with vocabulary you do not understand.
48
+
49
+ **2. `why_chosen` + `alternatives_considered` forces the choice to be argued.**
50
+
51
+ If you cannot write one sentence justifying why `<table-ui>` is the right primitive for THIS decision over `<grid-ui>` of `<card-ui>` OR `<list-ui>`, the choice is not deliberate — it is pattern-matched from prompt vocabulary. That is the KP-02 anti-pattern (Shell-vocabulary primacy) at the primitive tier.
52
+
53
+ **3. Embedded composites get extra fields.**
54
+
55
+ When you embed a composite (e.g., `<payment-method-list>` inside an admin-page-body), you inherit its full visual surface. Reading the composite's `.class.js` stamp/render method is mandatory — semantic API knowledge of the composite is insufficient. The embed inherits its rows, its row spacing, its brand-cell proportions, its empty-state shape. If you have not read those, you are compositing against a black box and your verify is structurally inadequate.
56
+
57
+ ---
58
+
59
+ ## §Output artifact
60
+
61
+ `.brain/findings/<task>.preflight.yaml` (sibling to `<task>.wireframe.md` per §SpecToUi reference) OR `.adia-ui-kit/preflight-<task>.yaml` in a consumer repo without `.brain/` directory.
62
+
63
+ The artifact is required-for the `nailed` tier of kit §PEV verify; optional-for `structurally-verified-only`.
64
+
65
+ ### Required structure
66
+
67
+ ```yaml
68
+ # Pre-flight component literacy — <task-slug>
69
+ # Required before kit §1 Catalog Lookup locks primitive selection
70
+ # (when targeting `nailed` tier of kit §PEV Mode 1-4 verify).
71
+ # Audit trail field: kit verify-target audit JSON's
72
+ # `component_literacy_path` MUST reference this file.
73
+
74
+ task_slug: <task-slug>
75
+ task_intent: <one-sentence from §SpecToUi Rung 1>
76
+ substrate_version: "@adia-ai/*@<version from lockstep manifest>"
77
+ pre_flight_authored_at: <ISO 8601 timestamp>
78
+ pre_flight_author: <agent or human identifier>
79
+
80
+ # ────────────────────────────────────────────────────────────────
81
+ # PRIMITIVES — used directly in the composition
82
+ # ────────────────────────────────────────────────────────────────
83
+
84
+ primitives_used:
85
+ - slug: <primitive-tag-without-ui-suffix> # e.g. card, table, button
86
+ css_path: packages/web-components/components/<dir>/<dir>.css
87
+ css_sha256: <12+ hex of file at read time>
88
+ css_read_at: <ISO 8601>
89
+ default_render: |
90
+ What this primitive renders with no attributes set.
91
+ Include actual computed dimensions (px or rem with px in parens).
92
+ Example: "display: block; full-width. Padding --card-inset
93
+ (default --a-inset = space-4 ≈ 16px). Border 1px subtle,
94
+ radius lg (~12px), bg --a-canvas-1, shadow-sm."
95
+ slot_sizing_rules:
96
+ - "[slot='<name>']: <how this slot sizes its content>"
97
+ - "..."
98
+ exposed_tokens:
99
+ - "<--token-name>: <fallback chain summary>"
100
+ visual_signature: |
101
+ One paragraph: what does this primitive look like at default?
102
+ Frame, padding, density, fg/bg, signature chrome.
103
+ embed_gotchas:
104
+ - <known issue or non-obvious behavior when embedding>
105
+ why_chosen: <one sentence: why this primitive fits this slot/region>
106
+ alternatives_considered:
107
+ - <slug>: <why rejected>
108
+
109
+ # ────────────────────────────────────────────────────────────────
110
+ # EMBEDDED COMPOSITES — composites composed into this task's surface
111
+ # ────────────────────────────────────────────────────────────────
112
+
113
+ embedded_composites:
114
+ - slug: <composite-tag-without-ui-suffix> # e.g. admin-shell, payment-method-list
115
+ css_path: packages/web-modules/<cluster>/<dir>/<dir>.css
116
+ class_path: packages/web-modules/<cluster>/<dir>/<dir>.class.js
117
+ css_sha256: <hash>
118
+ class_sha256: <hash>
119
+ read_at: <ISO 8601>
120
+ composite_renders_what: |
121
+ Read the .class.js's stamp/render methods.
122
+ Describe the Level 5 tree this composite produces.
123
+ Include the data-* attribute regions and how they nest.
124
+ per_item_proportions:
125
+ # Honest dimensional observations from the CSS read.
126
+ # If a row's brand-cell is 50% icon-to-frame ratio, note it here.
127
+ <dimension_name>: <value + computed px>
128
+ <ratio_or_density_note>: <observation>
129
+ visual_note: |
130
+ Honest visual assessment. If proportions look off, say so here —
131
+ this is the place to surface visual-debt that the embedded
132
+ composite's own future cycle should address. Do NOT patch the
133
+ embedded composite from THIS task's cycle (cross-cycle scope
134
+ discipline; see §Cross-cycle-scope below).
135
+ embed_gotchas:
136
+ - <token collision, contrast issue, density issue with parent chrome>
137
+ why_chosen: <one sentence>
138
+ alternatives_considered:
139
+ - <slug>: <why rejected>
140
+
141
+ # ────────────────────────────────────────────────────────────────
142
+ # PATTERNS REFERENCED — named compositions from kit/site catalog
143
+ # ────────────────────────────────────────────────────────────────
144
+
145
+ patterns_referenced:
146
+ - pattern_id: <kebab-case> # e.g. admin-page-header, kpi-strip
147
+ canonical_source: <path>
148
+ composed_of: [<primitive>, <primitive>]
149
+ why_chosen: <one sentence>
150
+ ```
151
+
152
+ ---
153
+
154
+ ## §Worked-example reading (compressed)
155
+
156
+ A real preflight entry for `<card-ui>` (kit's most-embedded primitive) reads:
157
+
158
+ ```yaml
159
+ - slug: card-ui
160
+ css_path: packages/web-components/components/card/card.css
161
+ css_sha256: '4a0bdf16c687' # pinned at read time
162
+ css_read_at: '2026-05-24T18:00:00Z'
163
+ default_render: |
164
+ display: block; full-width by default. Padding via --card-inset
165
+ token (default = --a-inset = space-4 ≈ 16px). Border 1px subtle,
166
+ radius lg (~12px), bg --a-canvas-1, shadow-sm by default.
167
+ slot_sizing_rules:
168
+ - "Header slot: laid out via card-ui's own header-slot grammar with --card-header-gap (space-2)."
169
+ - "Default content (no slot): direct children flow vertically; --card-gap sets row spacing."
170
+ - "Footer slot: --card-footer-gap (space-2)."
171
+ exposed_tokens:
172
+ - "--card-inset (padding)"
173
+ - "--card-gap (content row gap)"
174
+ - "--card-bg / --card-fg / --card-border"
175
+ visual_signature: |
176
+ Bordered container, rounded-lg, subtle shadow. Default chrome is
177
+ neutral (--a-canvas-1). When size='sm', padding shrinks; this is
178
+ how payment-method-list rows feel tighter than billing-overview's
179
+ header card.
180
+ embed_gotchas:
181
+ - "Setting --card-inset on a parent that uses card-ui changes padding for ALL nested card-ui children unless they re-declare. Cascade is intentional but easy to miss."
182
+ - "Header slot has its own gap; don't add an extra gap on direct children — they double up."
183
+ why_chosen: |
184
+ Header region (page-level chrome) and each KPI tile both need
185
+ bordered card chrome with consistent radius + padding + density.
186
+ alternatives_considered:
187
+ - "raw <header>: rejected — no consistent chrome with KPI tiles below"
188
+ - "<section-ui>: rejected — reading-column wrapper, not card chrome"
189
+ ```
190
+
191
+ The fields that CANNOT be fabricated without reading CSS: `default_render`, `slot_sizing_rules`, `exposed_tokens`, `embed_gotchas`, `visual_signature`. These are the literacy fields. Their presence is the proof.
192
+
193
+ ---
194
+
195
+ ## §Verify-target — when is the literacy gate satisfied?
196
+
197
+ The literacy gate is satisfied when:
198
+
199
+ - [ ] Every primitive used in the composition has a `primitives_used` entry
200
+ - [ ] Every embedded composite has an `embedded_composites` entry with `composite_renders_what` + `per_item_proportions`
201
+ - [ ] All required fields per entry populated (none are `<...>` placeholders)
202
+ - [ ] `css_sha256` values present (proves the file was read at a specific state)
203
+ - [ ] `why_chosen` + `alternatives_considered` non-empty per entry
204
+ - [ ] `visual_note` present in `embedded_composites` even when proportions look correct (the note is required; "no issues" is a valid value)
205
+
206
+ Once satisfied, the task may target the `nailed` tier of kit §PEV verify (see kit SKILL.md §PEV verify-target table). Without the literacy gate, the maximum claim is `structurally-verified-only`.
207
+
208
+ ---
209
+
210
+ ## §Cross-cycle-scope discipline
211
+
212
+ **Embedded composites are not patchable from THIS task's cycle.**
213
+
214
+ If reading `<payment-method-list>` reveals that its brand-cell renders at 50% icon-to-frame (a real defect — see postmortem), the literacy artifact NOTES the observation in `per_item_proportions.visual_note`. The fix belongs in `payment-method-list`'s own composite cycle, not in the task that embeds it. The note creates a paper trail that the embed was a deliberate choice with eyes open.
215
+
216
+ **Why:** mixing cross-cycle scopes leads to compounding regressions. The author of the embedding task does not own the embedded composite's verify path; patching its CSS from a downstream task bypasses its own canonical verify. The right action is:
217
+
218
+ 1. Author the literacy `visual_note`
219
+ 2. Open a substrate FB ticket (per kit §Team Tickets) citing the literacy artifact as evidence
220
+ 3. Proceed with the embed at `structurally-verified-only` tier (NAILED tier is unreachable until embedded composite is fixed in its own cycle)
221
+
222
+ This mirrors authoring's §Phase 2.5a `visual_note` discipline. Cross-skill consistency.
223
+
224
+ ---
225
+
226
+ ## §Kit §PEV verify-target — the NAILED status contract
227
+
228
+ Kit §PEV Mode 1-4 verify-target splits into TWO tiers based on whether the literacy gate fired:
229
+
230
+ | Tier | Means | Required signals |
231
+ |---|---|---|
232
+ | `structurally-verified-only` | Machine checks pass; no human visual ack; composition is structurally sound but visual fidelity is unverified | (a) Composed surface renders in playground without errors; (b) `audit-native-primitive-leak` passes; (c) `audit-shell-composition` passes (if shell-bearing); (d) `audit-kit-recipes` passes against substrate yaml SoT |
233
+ | `nailed` | Structurally verified AND author has done CSS literacy AND human-eyes ack | All of `structurally-verified-only` + `component_literacy_path` populated + `visual_verify_acknowledged_at` timestamp + `visual_verify_screenshot` path + `visual_verify_notes` prose |
234
+
235
+ **Default tier is `structurally-verified-only`.** `nailed` is reachable only by completing the literacy + visual axis. The split exists because the 2026-05-24 authoring postmortem showed structural-pass alone is insufficient — the visual-proportion defect existed in code that passed every machine check.
236
+
237
+ The kit consumer chooses the tier at the §Plan step (per §PEV). A task with high consequence (production-bound feature, brand-critical surface, multi-role workflow) should target `nailed`. A task with low consequence (internal prototype, exploration) may target `structurally-verified-only` and skip the literacy gate. **Be honest about which tier you chose** — claiming `nailed` while skipping the literacy gate is the Goodhart-on-NAILED failure mode from the postmortem.
238
+
239
+ ### Detector ≠ Enforcement (sibling-postmortem v1.8.1 lesson)
240
+
241
+ **The audit existing is not the same as the audit firing.** This is the second-order failure mode documented in `.brain/postmortems/2026-05-24-card-structure-audit-enforcement-gap.md` (companion to the CSS-illiteracy postmortem). The card-structure audit was authored, wired into `npm run check`, and exit-non-zero locally for 7 days while violations merged because (a) an upstream gate in the chained `&&` pipeline failed first, short-circuiting the downstream check; (b) branch protection allowed merges with red CI status.
242
+
243
+ **Apply this to kit verify:**
244
+
245
+ - The `structurally-verified-only` tier requires audits to RUN and PASS, not just to EXIST in the kit. Verify the audits ran in your verify session — don't assume `npm run check` covers them if upstream gates may have short-circuited.
246
+ - For consumer repos, use [`npm run audit:health`](#audit-health) to surface which gates are currently silent on `main`. A gate that should be enforcing kit's contract but isn't running is a hidden hole in the verify path.
247
+ - The `nailed` tier's `<task>.preflight.yaml` artifact is currently a MANUAL gate (mechanical `audit:preflight-completeness` is forward work). Manual + unenforced = same failure class as the card-structure audit drift. **The artifact-presence check is the enforcement surface for now.** If the kit consumer's CI doesn't fail when `phase_2_5_preflight_path` is missing from the audit JSON, the tier claim is unverified.
248
+
249
+ **Tier-claim discipline (extended at kit v3.7.1):** claiming `nailed` requires THREE invariants:
250
+
251
+ 1. The literacy artifact EXISTS at the expected path
252
+ 2. The artifact is COMPLETE (every primitive + embedded composite covered; no `<...>` placeholders)
253
+ 3. The verify session that produced the structurally-verified-only signals ACTUALLY RAN those audits — not assumed-to-have-run via an aggregate `npm run check` that may have short-circuited upstream
254
+
255
+ Without all three, the maximum honest claim is `structurally-verified-only`.
256
+
257
+ <a id="audit-health"></a>
258
+
259
+ ### Discovery: `npm run audit:health` (chat-ui infra, kit cites)
260
+
261
+ The chat-ui repository ships `npm run audit:health` (added in commit `2778367e4` — see authoring v1.8.1 forward-work closure). It runs every `check:*`, `audit:*`, `verify:*` script INDEPENDENTLY (not chained), producing a daily failure surface at `.brain/findings/audit-health-YYYY-MM-DD.md` + JSON variant via `npm run audit:health:json`.
262
+
263
+ This is the substrate-side detector for silent-failure gates. **Run it before claiming `nailed`** on chat-ui-substrate-adjacent work, to confirm that the kit-relevant audits (`audit-kit-recipes`, `audit-native-primitive-leak`, `audit-shell-composition`, `audit-demo-slot-vs-css`) are actually firing in the current `main`. If any of those show in the failing-gates list, the kit's `structurally-verified-only` signals from your local verify session may be misleading — they pass locally but aren't enforced upstream.
264
+
265
+ Consumer repos without `audit:health` should run kit's individual audit scripts directly per `audit-scripts.md`, then verify each script's exit code. Don't trust an aggregate `&& npm run check` to surface failures — chains short-circuit.
266
+
267
+ ---
268
+
269
+ ## §References
270
+
271
+ **Sister-skill source (authoring v1.8.0–v1.8.1):**
272
+
273
+ - `.agents/skills/adia-ui-authoring/references/composite-demo-protocol.md` — §Phase 2.5a Pre-flight Component Literacy + §NAILED status contract
274
+ - `.brain/postmortems/2026-05-24-component-css-illiteracy.md` — load-bearing rationale for the literacy gate; the structural failure mode this gate prevents
275
+ - `.brain/postmortems/2026-05-24-card-structure-audit-enforcement-gap.md` — sibling-postmortem (v1.8.1); the second-order failure mode (detector exists, enforcement absent) the §Detector-≠-Enforcement section addresses
276
+
277
+ **Kit references that hand off to / from this gate:**
278
+
279
+ - [`spec-to-ui-reasoning.md`](spec-to-ui-reasoning.md) §SpecToUi — Rungs 0-12 must resolve BEFORE the literacy gate; the literacy gate is the Rung 13 precondition
280
+ - [`catalog-lookup.md`](catalog-lookup.md) — kit §1 Catalog Lookup; the literacy gate fires here, not after
281
+ - [`composition.md`](composition.md) — kit §2 Composition; consumes the literacy artifact as input (cites the read primitives)
282
+ - [`common-gotchas-consumer.md`](common-gotchas-consumer.md) — next-layer Phase 4 author checklist; the four recurring consumer-side traps that recur even AFTER literacy is established (reading isn't recognizing). Sister-aligned with `adia-ui-authoring` v1.8.2 (commit `62f57f973`).
283
+ - `audit-scripts.md` — the bundled audit scripts that produce the `structurally-verified-only` signal
284
+
285
+ **Kit modes:**
286
+
287
+ - §SpecToUi (kit mode 15) — resolves Rungs 0-12; hands off to §1 + this literacy gate
288
+ - §1 Catalog Lookup (kit) — fires WITH this literacy gate, not before or after
289
+ - §2 Composition (kit) — consumes the literacy artifact
290
+ - §3 Validation (kit) — produces the structurally-verified-only signals
291
+ - §PEV Mode 1-4 verify-target — splits into structurally-verified-only vs nailed based on whether this gate fired
@@ -0,0 +1,245 @@
1
+ ---
2
+ name: composition
3
+ load-when: Authoring the actual HTML + A2UI JSON output once the primitives are selected. Covers slot vocabulary, attribute conventions, data binding, accessibility, and the composition contract
4
+ load-size-tokens: ~2,400
5
+ required-for:
6
+ - composition modes 1-4 after Catalog Lookup completes
7
+ ---
8
+
9
+ # §2 — Composition
10
+
11
+ ### When to use this skill
12
+
13
+ - Building a complete screen or flow from the component library
14
+ (login form, dashboard, settings page, artifact feed, chat).
15
+ - Wiring components through the A2UI protocol (createSurface,
16
+ updateComponents, wireComponents).
17
+ - Laying out content with the four layout primitives.
18
+ - Attaching traits (pressable, focusable, draggable, resizable).
19
+ - Writing a new page or app that uses AdiaUI components.
20
+
21
+ ### When NOT to use
22
+
23
+ - Authoring or modifying components in `packages/web-components/` →
24
+ use `adia-ui-authoring` (renamed from `adia-ui-author` 2026-05-22;
25
+ now a 6-mode rollup that also absorbed `adia-ui-code-bestpractices`,
26
+ `bespoke-shell-children`, and `promote-inline-to-module`).
27
+ - Changing generator / pattern-library internals → use `adia-ui-a2ui`.
28
+ - Running the MCP validation pipeline → use `adia-ui-a2ui`.
29
+
30
+ ### First principles
31
+
32
+ > **Before composing:** if you haven't looked up the components in your
33
+ > plan, stop and run §1 Catalog Lookup. The `Concept index` below is a
34
+ > hint, not a substitute for the yaml.
35
+
36
+ 1. **Every surface is a card.** The card content model (header / section /
37
+ footer) is mandatory for any block-level surface. When in doubt,
38
+ wrap in `<card-ui>`.
39
+
40
+ 2. **Composition is pure markup.** No `<style>` blocks, no inline `style=`,
41
+ no `<script>`. All variance comes from attributes on existing components.
42
+
43
+ 3. **Layout primitives over bare `<div>`.** `col-ui`, `row-ui`, `grid-ui`,
44
+ `stack-ui` are the canonical containers. Bare `<div>` is a validator flag.
45
+
46
+ 4. **One layout wrapper per section.** Every `<section>` inside a card
47
+ contains exactly one layout primitive.
48
+
49
+ 5. **Tokens, not raw values — and the name must exist.** CSS: `var(--a-space-3)` not `12px`.
50
+ Color: `var(--a-fg)` not `#111`. No raw hex anywhere.
51
+ **Critical trap — CSS fallback silently masks broken token names.** `font-size: var(--a-text-xs)` on a
52
+ non-existent token renders at the browser default with zero warning, no DevTools red, no console error.
53
+ Common broken-name patterns (real name → wrong guess): `--a-weight-medium` ≠ `--a-font-medium`,
54
+ `--a-ui-xs` ≠ `--a-text-xs`, `--a-code-family` ≠ `--a-font-mono`, `--a-canvas-0` ≠ `--a-surface`.
55
+ **Verify before use**: `grep -r '\-\-a-<name>' packages/web-components/styles/` — no grep hit = the
56
+ name is wrong. 16 broken references shipped undetected for months in a color-app session (FB-44).
57
+
58
+ 6. **A2UI JSON is the machine contract.** Every HTML composition has an
59
+ equivalent A2UI JSON representation. The JSON is what the gen-ui
60
+ pipeline validates and stores.
61
+
62
+ ### Concept index (what to reach for)
63
+
64
+ | Need | Component / Pattern |
65
+ |---|---|
66
+ | App frame | `<admin-shell>` (admin) · `<chat-shell>` (chat) · `<editor-shell>` (editor) · `<simple-shell>` (marketing/single) — one tag per posture, no umbrella `<app-shell>` |
67
+ | Primary nav | `<nav-ui>` with `<nav-item-ui>` children — place inside the shell's `slot="leading"` sidebar |
68
+ | Section nav | `<tabs-ui>` (tab-style; v0.6.34+ default size is universal `--a-size` ≈ 30px — pre-v0.6.34 default was hardcoded 36px. Add `[size="lg"]` to restore the pre-v0.6.34 visual.) or `<nav-ui>` with `<nav-item-ui>` for non-tab section navigation |
69
+ | Route tabs | `<tabs-ui>` (see size note above) |
70
+ | Page content block | `<card-ui>` with header / section / footer slots |
71
+ | Stacked layout | `<col-ui gap="…">` |
72
+ | Side-by-side | `<row-ui gap="…">` |
73
+ | Grid | `<grid-ui columns="…">` · asymmetric: `columns="5"` + `span="3"` + `span="2"` |
74
+ | Responsive layout | `@bp` annotation on any layout prop: `columns="2 4@md"` · `gap="2 4@md"` · `justify="start between@md"` — breakpoints xs/sm/md/lg/xl (0/480/768/1024/1280 px). Never use `@media` or inline style for layout breakpoints. |
75
+ | Stack (overlap) | `<stack-ui>` |
76
+ | Text | `<text-ui variant="body|heading|title|display|caption|label|kicker|…">` plus optional `size="sm|md|lg"`, `color="subtle|strong|accent|danger|success|warning|default"`, `weight="regular|medium|semibold|bold"`, `text-align="start|center|end|justify"` (overlays added v0.6.18, FB-10) |
77
+ | Button | `<button-ui variant="primary|secondary|ghost|danger">` |
78
+ | Input | `<input-ui type="text|email|search|…">` — always in `<field-ui>` |
79
+ | Select | `<select-ui>` — always in `<field-ui>` |
80
+ | Checkbox | `<check-ui label="…">` — self-labeling, NOT in field-ui |
81
+ | Switch | `<switch-ui label="…">` — self-labeling, NOT in field-ui |
82
+ | Radio | `<radio-ui label="…">` — self-labeling |
83
+ | Form label wrapper | `<field-ui label="…" [inline] [align="end"]>` |
84
+ | Data table | `<table-ui>` + `<table-toolbar-ui>` (always paired) |
85
+ | KPI number | `<stat-ui label="…" value="…" [trend="up|down"]>` |
86
+ | Badge | `<badge-ui variant="…">` |
87
+ | Icon | `<icon-ui name="…">` (Phosphor icon names) |
88
+ | Avatar | `<avatar-ui>` |
89
+ | Alert | `<alert-ui variant="info|warning|danger|success">` |
90
+ | Modal | `<modal-ui>` wrapping `<card-ui>` |
91
+ | Drawer | `<drawer-ui side="right|left">` |
92
+ | Popover | `<popover-ui>` |
93
+ | Tooltip | `<tooltip-ui content="…">` |
94
+ | Command palette | `<command-ui>` |
95
+ | Chat thread | `<chat-thread>` |
96
+ | Progress | `<progress-ui>` |
97
+ | Skeleton | `<skeleton-ui>` |
98
+ | Divider | `<divider-ui>` |
99
+ | Traits | `pressable`, `focusable`, `draggable`, `resizable`, `selectable` |
100
+
101
+ ### v0.6.34 new primitives (substrate currency — 11 new tags)
102
+
103
+ Released 2026-05-23 substrate cut; ZERO kit recipes yet — full coverage will land as patterns emerge. Until then, use this keyword index to discover them:
104
+
105
+ | Tag | Category | Use when |
106
+ |---|---|---|
107
+ | `<calendar-grid-ui>` | input (substrate) | A single-month calendar grid as a substrate primitive — NOT the user-facing date affordance. Use `<calendar-picker-ui>` (popover wrapper) for a complete date picker; reach for `<calendar-grid-ui>` only when authoring a higher-tier widget that already has its own trigger/popover. |
108
+ | `<combobox-ui>` | input | Typeahead-filterable single-select — the constrained-choice combobox per WAI-APG. **Distinct from `<select-ui>`**: combobox lets users TYPE to filter; select is point-and-click only. Use combobox when the option list is long (>20 entries) and users know what they're looking for; use select for short, fully-scannable lists. The committed value MUST be from the options list (no free-form entry). |
109
+ | `<date-range-picker-ui>` | input | Compound form primitive for start + end date pair with optional named preset shortcuts ("Today", "Last 7 days", "This month"). Trigger button → popover with two synchronized calendar panes + a preset side rail. Form-associated under one `name`. Emits `{from, to}` ISO 8601. For dashboard-level "current time window" controls (preset chip-row + comparison), use `<date-range-selector-ui>` instead. |
110
+ | `<datetime-picker-ui>` | input | Single-control date + time selection. Trigger button → popover with `<calendar-picker-ui>` on the left + `<time-picker-ui>` on the right. Emits ISO 8601 datetime string. Per ADR-0025 NEVER wraps native `<input type="datetime-local">` (bespoke surface owns the affordance). Form-associated under one `name`. |
111
+ | `<integration-card-ui>` | display | Single-tile primitive for one third-party integration (Slack, GitHub, Stripe…). Logo + name + description + status pill + primary action button whose label/variant derives from `[status]`. Compose into a grid via the SPEC-063 integrations-page composite. |
112
+ | `<list-window-ui>` | display | Virtualized / windowed list — renders only the visible slice (~50 DOM rows) of a large items[] array. For chat threads, feeds, log streams, nav lists, search-result panes. Composes a `render`-function prop OR a slotted `<template>` for row materialization. Fixed-size fast-path + variable-size mode. |
113
+ | `<spinner-ui>` | feedback | Circular indeterminate-loading indicator (rotating arc / full ring / three bouncing dots inside a sized box). Use when wait duration is unknown and the shape of the upcoming content isn't yet known. Fills the circular-spinner gap between `<skeleton-ui>` (rectangular placeholder) and `<progress-ui>` (linear determinate bar). Animation pauses via `[paused]`. |
114
+ | `<time-picker-ui>` | input | Time-of-day picker with discrete segments (hour, minute, optional second, optional AM/PM). Each segment is a WAI-ARIA Spinbutton with Arrow/PageUp-Down/Home-End/Tab semantics. Form-associated under one `name`. Emits `"HH:mm"` or `"HH:mm:ss"`. |
115
+ | `<date-range-selector-ui>` | input (module) | **Dashboard-level "current time window" chooser** — a module-tier composite pairing a preset chip-row (Today / 7d / 30d / 90d / QTD / YTD / Custom) with an embedded `<date-range-picker-ui>`. Use at the TOP of a metrics page; emits the same `{from, to}` shape as the underlying picker so downstream consumers don't care which control fired. |
116
+ | `<confirm-dialog-ui>` | feedback (module) | Non-destructive yes/no confirmation dialog — thin composite over `<modal-ui>` with the canonical confirm shape pre-stamped (title + optional icon header, description + optional rich body, primary/secondary action footer). Reach for this instead of hand-rolling a `<modal-ui>` for every yes/no prompt. For destructive confirmations, set `[variant="danger"]` on the primary button. |
117
+ | `<onboarding-checklist-ui>` | feedback (module) | Module-tier "Getting started" widget (the Stripe / Linear / Vercel dashboard pattern). Composes `<progress-ui>` (top fill bar) + `<list-ui>` + `<list-item-ui>` rows for each setup step. Place at the top of a dashboard page when first-run; auto-hide once `progress=100`. |
118
+
119
+ Recipes for these primitives will land as patterns emerge in real consumer use. If you're authoring one and the kit lacks coverage, `node scripts/teach-route.mjs --payload="<description>"` will route the new recipe to the right `references/patterns-*.md` file.
120
+
121
+ ### A2UI JSON wiring
122
+
123
+ Three message types for composition:
124
+
125
+ ```json
126
+ [
127
+ {
128
+ "type": "createSurface",
129
+ "surfaceId": "s1",
130
+ "components": [
131
+ { "id": "c1", "component": "Card", "children": ["c2", "c3"] },
132
+ { "id": "c2", "component": "Header", "title": "Dashboard" },
133
+ { "id": "c3", "component": "Stat", "label": "MRR", "value": "$42K" }
134
+ ]
135
+ }
136
+ ]
137
+ ```
138
+
139
+ - `component` values are PascalCase (`Card`, `Button`, `Field`, `Stat`)
140
+ - `id` values are lowercase-kebab
141
+ - `children` is an ordered array of child component IDs
142
+ - `slot` overrides the default slot for a child
143
+ - Data bindings go in a `wireComponents` message, not inline
144
+
145
+ ### App shell selection guide
146
+
147
+ | Posture | Shell | When |
148
+ |---|---|---|
149
+ | Monitoring / acting | `admin-shell` | Sidebar IA, multiple routes, data-heavy |
150
+ | Chat / conversational | `chat-shell` | Thread-centric, agent interaction |
151
+ | Editing / creating | `editor-shell` | Canvas + toolbar + panels |
152
+ | Single surface | `simple-shell` | Marketing, landing, auth, wizard |
153
+ | Embedded / raw | `a2ui-root` | Gen-UI output, embedded renderers |
154
+
155
+ ### Form composition rules
156
+
157
+ - Wide controls (`input-ui`, `select-ui`, `textarea-ui`, `slider-ui`,
158
+ `calendar-picker-ui`, `upload-ui`) MUST be inside `<field-ui>`.
159
+ - Self-labeling widgets (`check-ui`, `switch-ui`, `radio-ui`, `toggle-ui`)
160
+ MUST NOT be inside `<field-ui>` — they carry their own `[label]`.
161
+ - Use `<fields-ui>` for multi-column form grids.
162
+ - Use `<field-ui align="end">` to right-align labels in a multi-field stack.
163
+
164
+ ### Data table pairing rule
165
+
166
+ `<table-ui>` is always paired with `<table-toolbar-ui>`. The toolbar
167
+ provides search, filter, sort, and column controls **on by default** —
168
+ authoring a table without a toolbar is an anti-pattern (`check-composes`
169
+ will flag it).
170
+
171
+ > **Pitfall: `<table-toolbar-ui>` controls are opt-OUT, not opt-in.**
172
+ > Search, filter, sort, and column-visibility are all enabled by default
173
+ > the moment you place a `<table-toolbar-ui>` adjacent to a table. To
174
+ > disable specific controls, use the **boolean opt-out attributes**:
175
+ >
176
+ > ```html
177
+ > <!-- All four controls active (default) -->
178
+ > <table-toolbar-ui id="users-toolbar"></table-toolbar-ui>
179
+ >
180
+ > <!-- Suppress filter + column-visibility, keep search + sort -->
181
+ > <table-toolbar-ui id="users-toolbar" no-filter no-columns></table-toolbar-ui>
182
+ > ```
183
+ >
184
+ > | Attribute | Effect |
185
+ > | --------- | ------ |
186
+ > | `no-search` | Hide the search input |
187
+ > | `no-filter` | Hide the filter chips |
188
+ > | `no-sort` | Disable the sort affordance |
189
+ > | `no-columns` | Hide the column-visibility menu |
190
+ >
191
+ > **Common mistakes** (silently ignored — the toolbar still renders with
192
+ > default behavior):
193
+ > - `searchable` — not a real attribute. Search is already on; omit it.
194
+ > - `exportable` — not a real attribute. The toolbar doesn't expose
195
+ > export functionality; use a sibling `<button-ui>` if you need an
196
+ > export action.
197
+ >
198
+ > Verified against
199
+ > `node_modules/@adia-ai/web-components/components/table-toolbar/table-toolbar.yaml`
200
+ > (lines around `attribute: no-*`).
201
+
202
+ ### Theming via component-leaf tokens (OD-5 -default suffix, v0.6.34+)
203
+
204
+ Two distinct token layers govern AdiaUI visuals:
205
+
206
+ 1. **Global semantic tokens** — `--a-bg`, `--a-fg`, `--a-accent-bg`, `--a-space-N`, `--a-radius-k`, etc. Set at `:root` (theme) or any ancestor (scope). Cascade through components. Use these for app-wide theming.
207
+
208
+ 2. **Component-leaf tokens** — `--button-bg`, `--tabs-button-height`, `--card-pad`, etc. Owned by individual components. Set per-instance via inline style or via a wrapper class. Used for one-off visual overrides.
209
+
210
+ **OD-5 (v0.6.34) changed how the leaf layer works:** every component-leaf token now has a `-default` partner. The component CSS reads `var(--button-bg, var(--button-bg-default))` instead of `var(--a-fg)` directly. Consumer overrides at any ancestor surface now take effect; pre-v0.6.34 the leaf default shadowed wrapper overrides.
211
+
212
+ ```css
213
+ /* Pre-v0.6.34 — this DIDN'T work (leaf default shadowed the override):
214
+ .danger-zone button-ui {
215
+ --button-bg: red;
216
+ }
217
+ */
218
+
219
+ /* Post-v0.6.34 — this works as expected: */
220
+ .danger-zone button-ui {
221
+ --button-bg: red;
222
+ /* Component CSS resolves: var(--button-bg, var(--button-bg-default))
223
+ → "red" wins; no shadowing. */
224
+ }
225
+
226
+ /* Theme-wide override (set at :root or theme scope): */
227
+ :root {
228
+ --button-bg-default: var(--a-accent-bg);
229
+ /* Re-routes the default itself; instance --button-bg overrides still win. */
230
+ }
231
+ ```
232
+
233
+ **Naming convention:** for any leaf token `--X`, the substrate also exposes `--X-default`. Override `--X` for per-instance customization; override `--X-default` (typically at `:root`) to retarget the theme's resolved default. Discover tokens by inspecting `node_modules/@adia-ai/web-components/components/<name>/<name>.css` for the `:where(:scope)` block.
234
+
235
+ **Global vs leaf — when each:**
236
+ - App-wide theming → set global `--a-*` tokens at `:root` (preferred)
237
+ - One-component customization → set its `--<component>-*` leaf token in a scope
238
+ - New global token (theme extension) → not kit territory; substrate ADR + token registry
239
+
240
+ ### Notes on common pitfalls
241
+
242
+ The `--a-*` global token surface remained stable across v0.6.34; only leaf tokens changed. Existing recipes that set `--a-bg`, `--a-fg`, etc. continue working unchanged.
243
+
244
+
245
+ ---