@adia-ai/adia-ui-factory 0.8.1 → 0.8.2

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 (49) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.mcp.json +1 -1
  3. package/CHANGELOG.md +15 -0
  4. package/agents/app-architect.md +5 -3
  5. package/agents/consumer-verifier.md +38 -0
  6. package/agents/routing-corpus.json +32 -2
  7. package/agents/screen-composer.md +3 -1
  8. package/bin/adia-lint +59 -1
  9. package/bin/adia-probe.mjs +116 -0
  10. package/bin/adia-scaffold +91 -1
  11. package/bin/record-lint +142 -0
  12. package/commands/adia-genui.md +3 -1
  13. package/commands/adia-info.md +14 -0
  14. package/commands/adia-migrate.md +9 -3
  15. package/commands/adia-orient.md +5 -2
  16. package/commands/adia-scaffold.md +4 -2
  17. package/commands/adia-verify.md +15 -4
  18. package/package.json +1 -1
  19. package/references/a2ui-mcp-tools.md +1 -1
  20. package/references/llm.md +1 -1
  21. package/references/migration.md +11 -1
  22. package/references/project-shapes.md +15 -6
  23. package/references/shell-admin.md +2 -2
  24. package/references/shell-chat.md +8 -5
  25. package/references/ssr-integration.md +1 -1
  26. package/skills/adia-compose/SKILL.md +2 -2
  27. package/skills/adia-compose/assets/figma-make/guidelines/Guidelines.md +5 -5
  28. package/skills/adia-compose/assets/figma-make/guidelines/styles.md +2 -2
  29. package/skills/adia-compose/evals/routing-corpus.json +216 -0
  30. package/skills/adia-data/SKILL.md +29 -3
  31. package/skills/adia-data/evals/routing-corpus.json +172 -0
  32. package/skills/adia-genui/SKILL.md +24 -6
  33. package/skills/adia-genui/evals/routing-corpus.json +173 -0
  34. package/skills/adia-host/SKILL.md +16 -0
  35. package/skills/adia-host/evals/routing-corpus.json +172 -0
  36. package/skills/adia-llm/SKILL.md +7 -7
  37. package/skills/adia-llm/evals/routing-corpus.json +173 -0
  38. package/skills/adia-migrate/SKILL.md +46 -8
  39. package/skills/adia-migrate/evals/routing-corpus.json +171 -0
  40. package/skills/adia-orient/SKILL.md +20 -13
  41. package/skills/adia-orient/evals/routing-corpus.json +216 -0
  42. package/skills/adia-project/SKILL.md +6 -4
  43. package/skills/adia-project/evals/routing-corpus.json +171 -0
  44. package/skills/adia-shells/SKILL.md +23 -3
  45. package/skills/adia-shells/evals/routing-corpus.json +167 -0
  46. package/skills/adia-verify/SKILL.md +23 -2
  47. package/skills/adia-verify/evals/routing-corpus.json +171 -0
  48. package/skills/adia-verify/references/verification.md +8 -1
  49. package/references/verification.md +0 -35
@@ -3,7 +3,7 @@ name: adia-verify
3
3
  description: >-
4
4
  Browser-QA gate for adia-ui surfaces — renders headless with zero
5
5
  console/page errors, non-zero bounding boxes, and a screenshot actually
6
- read, plus AdiaUI a11y checks. Use before shipping a surface, on
6
+ read, plus AdiaUI a11y checks. Use when shipping a surface, on
7
7
  "verify/QA this page", or when "tests pass" is the only evidence. NOT for
8
8
  composing/fixing UI (adia-compose) or structural lint (adia-lint hook).
9
9
  disable-model-invocation: false
@@ -27,7 +27,27 @@ Probe shape, the failure classes only this gate catches (0×0 host, empty-page-w
27
27
 
28
28
  ## Tooling boundary
29
29
 
30
- The advisory `adia-lint` PostToolUse hook mechanizes the structural slice on every write (shadow DOM, raw color/px, `::slotted`, native-primitive leaks, legacy shell shapes, SSR traps) and never blocks — fix its findings rather than re-deriving its rules. The framework's `audit:shell-composition` / `audit:native-primitive-leak` run in the @adia-ai framework repo; they are not shipped in this plugin and cannot be invoked from a consumer app. Everything else — the render, the screenshot read, a11y — is self-verified: no shipped script enforces it.
30
+ The advisory `adia-lint` PostToolUse hook mechanizes the structural slice on every write (shadow DOM, raw color/px, `::slotted`, native-primitive leaks, legacy shell shapes, SSR traps, and the shell-nesting/LLM-key/genui-validate rules) and never blocks — fix its findings rather than re-deriving its rules. The framework's `audit:shell-composition` / `audit:native-primitive-leak` run in the @adia-ai framework repo; they are not shipped in this plugin and cannot be invoked from a consumer app.
31
+
32
+ The render gate itself IS shipped: `node "${CLAUDE_PLUGIN_ROOT}/bin/adia-probe.mjs" <url> --selector <key-element> [--json]` runs gates 1–2 mechanically (console/page errors, bounding boxes, the `deviceScaleFactor: 2` capture — set at context creation, where it actually takes effect) and emits the VerifyProof below with verdict `pass-pending-read`. The screenshot READ and the a11y judgment slice stay yours — the probe's `imageRead` slot exists precisely so a report can't silently skip them. Requires Playwright in the consumer app (`npm i -D playwright`).
33
+
34
+ ## Deliverable — the VerifyProof
35
+
36
+ The QA pass returns this record (the probe emits the mechanized half via `--json`; the reader completes it):
37
+
38
+ ```text
39
+ VerifyProof
40
+ url: <the probed page>
41
+ consoleErrors: pass | fail — <each error verbatim; empty = pass>
42
+ boundingBoxes: pass | fail — <selector: w×h per key element; any 0×0 = fail>
43
+ screenshot: <path> @ deviceScaleFactor 2
44
+ imageRead: <what the pixels actually show — REQUIRED prose, never "looks fine">
45
+ a11y: pass | fail — region role/label · .open-driven overlays · heading roles · keyboard path · AA contrast
46
+ structure: adia-lint clean on every written file | <findings>
47
+ verdict: ship | hold — <one line naming the blocker if hold>
48
+ ```
49
+
50
+ A VerifyProof with an empty `imageRead` or a bare "looks fine" is incomplete — the slot carries what was SEEN, so a later reader can challenge it.
31
51
 
32
52
  ## Verify rubric
33
53
 
@@ -39,5 +59,6 @@ A surface ships only when all pass:
39
59
  | Screenshot read `[gate]` | the `deviceScaleFactor: 2` capture was looked at, after the latest structural change |
40
60
  | Accessible `[gate]` | region role + label; `.open`-driven overlays; real heading roles; keyboard path; AA contrast |
41
61
  | Structurally clean `[gate]` | `adia-lint` reports no smells on every file written for the surface |
62
+ | Data wired `[gate]` | the surface's Wiring Record (adia-data §Deliverable) exists with every round-trip row observed — a screen with unrecorded state wiring isn't done |
42
63
 
43
64
  Neighboring work routes out: composing or fixing the surface → `adia-compose` · shell chrome → `adia-shells` · hydration/state → `adia-data` · generated-markup validation → `adia-genui`.
@@ -0,0 +1,171 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "adia-verify routing accuracy corpus",
4
+ "version": "1.0.0",
5
+ "purpose": "Routing-eval corpus for adia-verify (adia-ui-factory plugin). Each phrase declares whether adia-verify SHOULD be the routing target. Scored by the estate's TF-IDF routing-eval runner against the skill's description (heuristic token overlap).",
6
+ "scoring_notes": "Heuristic signal, not ground truth. Treat misroutes as a prompt to tighten the skill description, never as a reason to keyword-stuff it. Real harness routing is LLM-driven.",
7
+ "license": "internal",
8
+ "scope": "adia-verify routing — does this phrase activate adia-verify (the consumer-app browser-QA exit gate), and does it correctly stay OUT of adia-release's release pre-flight gates, which is the one known central-corpus misroute for any 'verify'-flavored phrase?",
9
+
10
+ "minimums_per_spec": {
11
+ "trigger_phrases": 14,
12
+ "adversarial_phrases": 6,
13
+ "task_shapes_covered": "browser-gate, qa-request, a11y-check, debug-symptom, anti-pattern-tests-pass",
14
+ "adversarial_fraction": "30%"
15
+ },
16
+
17
+ "phrases": [
18
+ {
19
+ "id": "verify-gate-01",
20
+ "phrase": "verify this surface renders with zero console errors before we ship it",
21
+ "should_route_to_verify": true,
22
+ "expected_shape": "browser-gate",
23
+ "rationale": "Canonical pre-ship browser-render gate phrasing — matches the skill's own 'before shipping a surface' trigger."
24
+ },
25
+ {
26
+ "id": "verify-gate-02",
27
+ "phrase": "run the browser gate on the new settings page",
28
+ "should_route_to_verify": true,
29
+ "expected_shape": "browser-gate",
30
+ "rationale": "Direct 'browser gate' terminology from the skill's own name for its check."
31
+ },
32
+ {
33
+ "id": "verify-gate-03",
34
+ "phrase": "check that bounding boxes are non-zero on the dashboard before merging",
35
+ "should_route_to_verify": true,
36
+ "expected_shape": "browser-gate",
37
+ "rationale": "Non-zero bounding box is the gate's literal pass condition."
38
+ },
39
+
40
+ {
41
+ "id": "verify-qa-01",
42
+ "phrase": "verify/QA this page before we ship it",
43
+ "should_route_to_verify": true,
44
+ "expected_shape": "qa-request",
45
+ "rationale": "Verbatim 'verify/QA this page' phrase from the skill description."
46
+ },
47
+ {
48
+ "id": "verify-qa-02",
49
+ "phrase": "is this screen done? run the exit gate on it",
50
+ "should_route_to_verify": true,
51
+ "expected_shape": "qa-request",
52
+ "rationale": "'Is this screen done' — the exit-gate framing this skill owns."
53
+ },
54
+ {
55
+ "id": "verify-qa-03",
56
+ "phrase": "QA the checkout flow before it goes live for users",
57
+ "should_route_to_verify": true,
58
+ "expected_shape": "qa-request",
59
+ "rationale": "Consumer-app pre-launch QA request; deliberately avoids the word 'release' to not collide with adia-release."
60
+ },
61
+
62
+ {
63
+ "id": "verify-a11y-01",
64
+ "phrase": "run an accessibility pass on the profile page",
65
+ "should_route_to_verify": true,
66
+ "expected_shape": "a11y-check",
67
+ "rationale": "A11y check is one of the two gate halves this skill owns."
68
+ },
69
+ {
70
+ "id": "verify-a11y-02",
71
+ "phrase": "check AA contrast and the keyboard path on the new modal",
72
+ "should_route_to_verify": true,
73
+ "expected_shape": "a11y-check",
74
+ "rationale": "AA contrast + keyboard path are named rubric rows."
75
+ },
76
+ {
77
+ "id": "verify-a11y-03",
78
+ "phrase": "does this overlay have a real heading role and an aria-label on its region?",
79
+ "should_route_to_verify": true,
80
+ "expected_shape": "a11y-check",
81
+ "rationale": "Region role + heading role are named a11y-gate items."
82
+ },
83
+
84
+ {
85
+ "id": "verify-debug-01",
86
+ "phrase": "the screen renders completely blank, help me figure out why",
87
+ "should_route_to_verify": true,
88
+ "expected_shape": "debug-symptom",
89
+ "rationale": "'Empty page' symptom — a named failure class only this gate catches."
90
+ },
91
+ {
92
+ "id": "verify-debug-02",
93
+ "phrase": "this element reports a 0x0 bounding box, why isn't it sized",
94
+ "should_route_to_verify": true,
95
+ "expected_shape": "debug-symptom",
96
+ "rationale": "0x0 host is the skill's named failure class."
97
+ },
98
+ {
99
+ "id": "verify-debug-03",
100
+ "phrase": "the page looks broken visually but the console shows no errors",
101
+ "should_route_to_verify": true,
102
+ "expected_shape": "debug-symptom",
103
+ "rationale": "Clean-console-but-visually-broken is the anti-pattern this gate exists to catch."
104
+ },
105
+
106
+ {
107
+ "id": "verify-anti-01",
108
+ "phrase": "our unit tests pass, but I want someone to actually look at the rendered page before we call it done",
109
+ "should_route_to_verify": true,
110
+ "expected_shape": "anti-pattern-tests-pass",
111
+ "rationale": "Directly invokes the skill's named anti-pattern: 'tests pass, ship it'."
112
+ },
113
+ {
114
+ "id": "verify-anti-02",
115
+ "phrase": "confirm the surface actually renders and isn't just clipped — don't take the test suite's word for it",
116
+ "should_route_to_verify": true,
117
+ "expected_shape": "anti-pattern-tests-pass",
118
+ "rationale": "Clipped-content-despite-passing-tests is the gate's reason to exist."
119
+ },
120
+
121
+ {
122
+ "id": "verify-adv-01",
123
+ "phrase": "run the pre-flight verification gates before we cut the v0.8 release",
124
+ "should_route_to_verify": false,
125
+ "expected_alternative": "adia-release (forge plugin)",
126
+ "rationale": "Adversarial — the known central-corpus misroute: 'verify' language describing release pre-flight gates (F-N1, tag/publish checkpoints), not a consumer-app browser QA pass."
127
+ },
128
+ {
129
+ "id": "verify-adv-02",
130
+ "phrase": "run a dogfood sweep across every demo page in the framework repo",
131
+ "should_route_to_verify": false,
132
+ "expected_alternative": "adia-dogfood (forge plugin)",
133
+ "rationale": "Adversarial — framework-side demo sweep (visual probe, attr-quote typos, shell composition) is adia-dogfood's territory, not the consumer-app exit gate."
134
+ },
135
+ {
136
+ "id": "verify-adv-03",
137
+ "phrase": "the QA pass found the button is unstyled and misplaced — go fix the screen",
138
+ "should_route_to_verify": false,
139
+ "expected_alternative": "adia-compose (adia-ui-factory plugin)",
140
+ "rationale": "Adversarial — verify only reports the gap; fixing the composed screen routes to adia-compose (generator, not the gate)."
141
+ },
142
+ {
143
+ "id": "verify-adv-04",
144
+ "phrase": "the gate found the data isn't hydrating on load — fix the state wiring",
145
+ "should_route_to_verify": false,
146
+ "expected_alternative": "adia-data (adia-ui-factory plugin)",
147
+ "rationale": "Adversarial — fixing a hydration/state defect the gate surfaced belongs to adia-data, not to re-running verify."
148
+ },
149
+ {
150
+ "id": "verify-adv-05",
151
+ "phrase": "run the structural lint check on the files from my last commit",
152
+ "should_route_to_verify": false,
153
+ "expected_alternative": "adia-lint hook (advisory PostToolUse hook, not a skill)",
154
+ "rationale": "Adversarial — structural smells (shadow DOM, raw color/px, native-primitive leaks) are the adia-lint hook's mechanized slice; verify only checks that hook reports clean, it doesn't run the lint itself."
155
+ },
156
+ {
157
+ "id": "verify-adv-06",
158
+ "phrase": "write unit tests for the new date-parsing utility function",
159
+ "should_route_to_verify": false,
160
+ "expected_alternative": null,
161
+ "rationale": "Adversarial — generic unit-test authoring with no browser-render or a11y surface; no AdiaUI skill should activate."
162
+ }
163
+ ],
164
+
165
+ "evaluator_notes": {
166
+ "current_state": "20 cases (14 trigger + 6 adversarial). Each of the 5 task shapes has 2-3 trigger cases; adv-01 specifically targets the documented known misroute (verify-flavored phrase landing on adia-release).",
167
+ "promotion_criteria": "Promote to a CI gate (warn → hard-fail) when F1 ≥ 0.85 on this corpus across 3+ consecutive runs without description edits.",
168
+ "review_cadence": "Re-run on every adia-verify description edit. Add 1-2 new cases per checkpoint reflecting newly-observed routing failure modes.",
169
+ "known_limitations": "verify-adv-01 encodes the single highest-value adversarial for this skill: 'verify' as a bare word is release-gate-shaped in the central corpus, and the heuristic scorer may weight token overlap toward adia-release's own 'pre-flight gates' language. The description's browser/a11y-specific vocabulary (bounding boxes, console.error, aria-label) is the intended disambiguator."
170
+ }
171
+ }
@@ -13,9 +13,16 @@ Render the surface in a real (headless) browser and assert four things, in order
13
13
 
14
14
  Gates 1 and 2 are independent, not redundant: `customElements.whenDefined(name)` never rejects, so a `Promise.all([...whenDefined]).then(bootstrap)` gate with one never-imported tag hangs forever — shell chrome still renders (tag-keyed CSS), the console stays **clean**, and the page is empty. Only the bounding-box and screenshot checks see it.
15
15
 
16
- Minimal probe shape (Playwright; works against a Vite static host or an SSR dev URL):
16
+ The shipped probe runs this mechanically and emits the VerifyProof:
17
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/adia-probe.mjs" <url> --selector <el> --json`.
18
+ Its logic, for when you need a bespoke variant (Playwright; works against a
19
+ Vite static host or an SSR dev URL):
17
20
 
18
21
  ```js
22
+ // deviceScaleFactor must be set at CONTEXT creation — scale:'device' on a
23
+ // default context captures at 1x and silently fails gate 3's 2x claim.
24
+ const context = await browser.newContext({ deviceScaleFactor: 2 });
25
+ const page = await context.newPage();
19
26
  const errors = [];
20
27
  page.on('console', m => m.type() === 'error' && errors.push(m.text()));
21
28
  page.on('pageerror', e => errors.push(String(e)));
@@ -1,35 +0,0 @@
1
- # Verification — the exit gate
2
-
3
- Mode-independent. A surface is done when it passes the **browser gate** + the a11y check — not when it compiles and not when unit tests pass. "Tests pass, ship it" is the anti-pattern: unit tests are necessary, not sufficient (happy-dom/vitest pass for components that render broken in real browsers).
4
-
5
- ## The browser gate (the real gate)
6
-
7
- Render the surface in a real (headless) browser and assert four things:
8
-
9
- 1. **Zero `console.error` / `pageerror` on load** — collect them during navigation; any is a failure.
10
- 2. **Non-zero bounding boxes** on the key elements — catches the "upgraded but never sized" 0×0 host, where the element exists but renders nothing.
11
- 3. **Read the screenshot** — capture at `deviceScaleFactor: 2` and actually look at it. Content can be present in the DOM yet visually clipped, overlapped, or off-canvas; only the pixels catch that. A probe that screenshots but doesn't read it hasn't verified anything.
12
- 4. **Re-probe after every structural change** — a stale screenshot lies.
13
-
14
- Minimal probe shape (Playwright; works against a Vite static host or an SSR dev URL):
15
-
16
- ```js
17
- const errors = [];
18
- page.on('console', m => m.type() === 'error' && errors.push(m.text()));
19
- page.on('pageerror', e => errors.push(String(e)));
20
- await page.goto(url, { waitUntil: 'networkidle' });
21
- const box = await page.locator('my-surface').boundingBox(); // expect non-zero w/h
22
- await page.screenshot({ path: 'probe.png', scale: 'device' }); // then READ probe.png
23
- // gate: errors.length === 0 && box.width > 0 && box.height > 0 && (you read the image)
24
- ```
25
-
26
- ## Diagnosing the "renders empty, zero console errors" page
27
-
28
- `customElements.whenDefined(name)` never rejects — if `name` is never imported, its Promise never resolves, so a `Promise.all([...]).then(bootstrap)` gate hangs forever on one dead await. Shell chrome still renders (tag-keyed CSS), the page body is just empty, and nothing errors. Check every awaited tag actually has a registering import before suspecting anything else.
29
-
30
- ## Accessibility (the adia-ui-specific checks)
31
-
32
- Standard a11y applies (labelled landmarks, keyboard paths, AA contrast). The kit-specific traps:
33
-
34
- - **Overlays** — drive `<modal-ui>` / `<drawer-ui>` via the `.open` property; a hardcoded `open` attribute on a `showModal` overlay bricks the whole page, and only a live click/`elementFromPoint` probe catches it.
35
- - **Roles** — a presentational `text-ui variant="heading"` needs a real heading role or `<h*>` wrapper; don't use deprecated `aria-grabbed`.