@adia-ai/adia-ui-factory 0.8.9 → 0.8.10

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 (41) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.mcp.json +1 -1
  3. package/CHANGELOG.md +14 -0
  4. package/package.json +1 -1
  5. package/skills/adia-audit/evals/evals.json +20 -0
  6. package/skills/adia-audit/evals/routing-corpus.json +144 -28
  7. package/skills/adia-charts/SKILL.md +127 -0
  8. package/skills/adia-charts/evals/evals.json +20 -0
  9. package/skills/adia-charts/evals/routing-corpus.json +155 -0
  10. package/skills/adia-charts/references/chart-type-catalog.md +65 -0
  11. package/skills/adia-charts/references/composition-and-theming.md +113 -0
  12. package/skills/adia-compose/evals/evals.json +21 -0
  13. package/skills/adia-compose/evals/routing-corpus.json +63 -67
  14. package/skills/adia-data/evals/evals.json +20 -0
  15. package/skills/adia-data/evals/routing-corpus.json +40 -54
  16. package/skills/adia-genui/evals/evals.json +19 -0
  17. package/skills/adia-genui/evals/routing-corpus.json +47 -57
  18. package/skills/adia-host/evals/evals.json +19 -0
  19. package/skills/adia-host/evals/routing-corpus.json +37 -51
  20. package/skills/adia-llm/evals/evals.json +19 -0
  21. package/skills/adia-llm/evals/routing-corpus.json +48 -58
  22. package/skills/adia-migrate/evals/evals.json +19 -0
  23. package/skills/adia-migrate/evals/routing-corpus.json +45 -54
  24. package/skills/adia-orient/evals/evals.json +19 -0
  25. package/skills/adia-orient/evals/routing-corpus.json +81 -89
  26. package/skills/adia-patterns/SKILL.md +11 -0
  27. package/skills/adia-patterns/evals/evals.json +19 -0
  28. package/skills/adia-patterns/evals/routing-corpus.json +40 -47
  29. package/skills/adia-project/evals/evals.json +19 -0
  30. package/skills/adia-project/evals/routing-corpus.json +44 -56
  31. package/skills/adia-shells/evals/evals.json +19 -0
  32. package/skills/adia-shells/evals/routing-corpus.json +49 -58
  33. package/skills/adia-tables/SKILL.md +123 -0
  34. package/skills/adia-tables/evals/evals.json +20 -0
  35. package/skills/adia-tables/evals/routing-corpus.json +177 -0
  36. package/skills/adia-tables/references/advanced-patterns.md +152 -0
  37. package/skills/adia-tables/references/base-table.md +170 -0
  38. package/skills/adia-tokens/evals/evals.json +18 -0
  39. package/skills/adia-tokens/evals/routing-corpus.json +124 -22
  40. package/skills/adia-verify/evals/evals.json +19 -0
  41. package/skills/adia-verify/evals/routing-corpus.json +46 -55
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adia-factory",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "Author and verify apps built ON the adia-ui (@adia-ai) light-DOM web-component framework \u2014 orient, scaffold, compose, wire, verify, and migrate across SPA and SSR rendering modes. Wires the a2ui MCP for catalog retrieval, UI generation, and validation.",
5
5
  "author": {
6
6
  "name": "Kim",
package/.mcp.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "a2ui": {
4
4
  "command": "npx",
5
- "args": ["-y", "@adia-ai/a2ui-mcp@0.8.9"]
5
+ "args": ["-y", "@adia-ai/a2ui-mcp@0.8.10"]
6
6
  }
7
7
  }
8
8
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog — adia-factory
2
2
 
3
+ ## [0.8.10] — 2026-07-20
4
+
5
+ ### Added
6
+ - **`adia-charts` knowledge skill** (`skills/adia-charts/`; gh#381) — which component to use for which chart/graph/sparkline/gauge/heatmap need, data binding, legend wiring, and theming, grounded in `chart-ui`/`chart-legend-ui`/`heatmap-ui`'s real prop surface. Sibling to `adia-patterns`/`adia-tokens`/`adia-shells`. `chart-legend-ui[for]` auto-mirrors `chart-ui` only (verified `heatmap-ui` never populates `.legendData`/dispatches `legend-update`, despite a stale docstring elsewhere claiming otherwise); `heatmap-ui` is included as a genuine chart-family member (`chart.yaml` itself routes density-grid asks there).
7
+ - **`adia-tables` knowledge skill** (`skills/adia-tables/`; gh#382) — contained vs. uncontained/bleed chrome, `[raw]` (a separate axis from data-driven rendering — see the `@adia-ai/web-components` gh#385 fix), striped rows (opt-in, not default — corrects a stale assumption in the original ticket), column resize/sort (opt-out for JS `.columns`, opt-in for declarative `<col-def>` — the two forms have opposite defaults), and the inline-edit-grid + tree/hierarchical-row patterns. `list-window-ui` named as the escape hatch for 1,000+-row collections.
8
+ - **`evals/evals.json` behavioral test-case files for 15 skills** (gh#369) — the file `release_gate.py`'s G7 coverage check actually reads (a schema distinct from `evals/routing-corpus.json`). Derived from each skill's already-vetted `routing-corpus.json` phrases where genuinely good behavioral tests, with real judgment applied rather than a mechanical paste (independently reviewed, sampled across both plugins).
9
+
10
+ ### Fixed
11
+ - **`evals/routing-corpus.json` unified onto one schema across all skills** (gh#355) — converged the two mutually-incompatible per-skill corpus shapes (forge's `{positives,negatives}` vs. factory's `{phrases}`) onto the `{phrases:[{id,phrase,expected,expected_shape?,rationale?}]}` shape `scripts/skills/run-skill-evals.mjs` already reads, since that's the one in-repo runner that actually exercises these corpora. Fixed 4 missing `.agents/skills/` symlinks that blocked discovery entirely, independent of schema (`adia-site-docs`, `adia-ssr`, `adia-audit`, `adia-patterns`). Coverage: 97 reachable phrases (8 skills invisible) → 572 phrases across all 22 skills existing at the time.
12
+ - **`adia-patterns`: routes are a client-rendered SPA — never plain-fetch** (`skills/adia-patterns/SKILL.md`; PR #362) — a non-browser fetch of any `ui-kit.exe.xyz` route returns the identical loading shell whether the path is valid or not, so `WebFetch`/`curl` can't distinguish a live route from a dead one. Documents the file-resolution alternative (`node_modules` install, or a monorepo checkout).
13
+
14
+ ### Maintenance
15
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
16
+
3
17
  ## [0.8.9] — 2026-07-19
4
18
 
5
19
  ### Maintenance
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-factory",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "Author and verify apps built ON the adia-ui (@adia-ai) light-DOM web-component framework \u2014 orient, scaffold, compose, wire, verify, and migrate across SPA and SSR rendering modes. Wires the a2ui MCP for catalog retrieval, UI generation, and validation.",
5
5
  "keywords": [
6
6
  "adia-ui",
@@ -0,0 +1,20 @@
1
+ {
2
+ "skill": "adia-audit",
3
+ "note": "Trigger-routing suite (gh#369). expect=trigger: the skill should fire on the prompt in a fresh session. expect=no-trigger: a near-miss owned elsewhere (owner named per case) or generic knowledge with no AdiaUI skill involved. Cases derived from evals/routing-corpus.json's phrases array (gh#355 vetted corpus, with expected_shape/rationale) plus the SKILL.md description's own trigger/NOT-fence language.",
4
+ "cases": [
5
+ { "id": "t01", "prompt": "Audit this AdiaUI app before I start making changes", "expect": "trigger" },
6
+ { "id": "t02", "prompt": "I inherited a repo that uses @adia-ai — what state is it in?", "expect": "trigger" },
7
+ { "id": "t03", "prompt": "Is this app on the latest @adia-ai version, or has it drifted?", "expect": "trigger" },
8
+ { "id": "t04", "prompt": "The dashboard renders unstyled and broken, what's wrong?", "expect": "trigger" },
9
+ { "id": "t05", "prompt": "This screen doesn't match the reference design, why?", "expect": "trigger" },
10
+ { "id": "t06", "prompt": "Components render empty even though the data is set — root-cause it", "expect": "trigger" },
11
+ { "id": "t07", "prompt": "Check this repo for hand-rolled things the library now ships natively", "expect": "trigger" },
12
+ { "id": "t08", "prompt": "Give me a health report on our AdiaUI consumer app", "expect": "trigger" },
13
+ { "id": "n01", "prompt": "We're starting a new internal claims tool on adia-ui, plan it", "expect": "no-trigger", "owner": "adia-orient" },
14
+ { "id": "n02", "prompt": "Run the migration sweep to bump @adia-ai from 0.6 to 0.8", "expect": "no-trigger", "owner": "adia-migrate" },
15
+ { "id": "n03", "prompt": "QA this screen in the browser and check a11y", "expect": "no-trigger", "owner": "adia-verify" },
16
+ { "id": "n04", "prompt": "Build the settings screen from this plan", "expect": "no-trigger", "owner": "adia-compose" },
17
+ { "id": "n05", "prompt": "Cut a release and write the migration guide", "expect": "no-trigger", "owner": "adia-release" },
18
+ { "id": "n06", "prompt": "Audit our npm dependencies for security vulnerabilities", "expect": "no-trigger" }
19
+ ]
20
+ }
@@ -1,42 +1,158 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "name": "adia-audit routing accuracy corpus",
4
- "version": "1.0.0",
4
+ "version": "2.1.0",
5
5
  "purpose": "Routing-eval corpus for adia-audit (adia-ui-factory plugin). Each phrase declares whether adia-audit SHOULD be the routing target. Scored by the estate's TF-IDF routing-eval runner against the skill's description (heuristic token overlap).",
6
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
7
  "license": "internal",
8
- "scope": "adia-audit routing does this phrase activate adia-audit (diagnose/recon/root-cause an EXISTING @adia-ai consumer repo), and does it correctly stay OUT of adia-orient (classify a greenfield to plan a build), adia-migrate (the mechanical sweep AFTER a confirmed diagnosis), adia-verify (browser QA of a built surface), and adia-compose (author a new screen)?",
9
-
8
+ "scope": "adia-audit routing \u2014 does this phrase activate adia-audit (diagnose/recon/root-cause an EXISTING @adia-ai consumer repo), and does it correctly stay OUT of adia-orient (classify a greenfield to plan a build), adia-migrate (the mechanical sweep AFTER a confirmed diagnosis), adia-verify (browser QA of a built surface), and adia-compose (author a new screen)?",
9
+ "phrases": [
10
+ {
11
+ "id": "audit-health-01",
12
+ "phrase": "audit this AdiaUI app",
13
+ "expected": "adia-audit",
14
+ "expected_shape": "audit-health",
15
+ "rationale": "Canonical audit request on an existing consumer repo."
16
+ },
17
+ {
18
+ "id": "audit-health-02",
19
+ "phrase": "review this @adia-ai codebase before we touch it",
20
+ "expected": "adia-audit",
21
+ "expected_shape": "brownfield-recon",
22
+ "rationale": "Recon-before-edit on an inherited repo."
23
+ },
24
+ {
25
+ "id": "audit-health-03",
26
+ "phrase": "I inherited a repo that uses @adia-ai \u2014 what state is it in",
27
+ "expected": "adia-audit",
28
+ "expected_shape": "brownfield-recon",
29
+ "rationale": "Inherited-repo health check."
30
+ },
31
+ {
32
+ "id": "audit-current-01",
33
+ "phrase": "is this app on the latest @adia-ai version",
34
+ "expected": "adia-audit",
35
+ "expected_shape": "is-it-current",
36
+ "rationale": "Version-currency question \u2014 the recon 3-tuple."
37
+ },
38
+ {
39
+ "id": "audit-current-02",
40
+ "phrase": "is our AdiaUI setup up to date or drifted",
41
+ "expected": "adia-audit",
42
+ "expected_shape": "is-it-current",
43
+ "rationale": "Drift-detection framing."
44
+ },
45
+ {
46
+ "id": "audit-migrate-01",
47
+ "phrase": "what should we migrate in this AdiaUI app",
48
+ "expected": "adia-audit",
49
+ "expected_shape": "what-to-migrate",
50
+ "rationale": "Diagnosis-first: the audit produces the ranked what, adia-migrate executes it."
51
+ },
52
+ {
53
+ "id": "audit-wrong-01",
54
+ "phrase": "the dashboard renders unstyled and broken, what's wrong",
55
+ "expected": "adia-audit",
56
+ "expected_shape": "wrong-output-root-cause",
57
+ "rationale": "Wrong-output symptom \u2192 the correction loop."
58
+ },
59
+ {
60
+ "id": "audit-wrong-02",
61
+ "phrase": "this screen doesn't match the reference, why",
62
+ "expected": "adia-audit",
63
+ "expected_shape": "wrong-output-root-cause",
64
+ "rationale": "Mismatch-vs-reference \u2192 root-cause triage."
65
+ },
66
+ {
67
+ "id": "audit-wrong-03",
68
+ "phrase": "the admin shell topbar looks mispositioned",
69
+ "expected": "adia-audit",
70
+ "expected_shape": "wrong-output-root-cause",
71
+ "rationale": "The Light-DOM zeroth-question archetype."
72
+ },
73
+ {
74
+ "id": "audit-wrong-04",
75
+ "phrase": "components render empty even though the data is set",
76
+ "expected": "adia-audit",
77
+ "expected_shape": "wrong-output-root-cause",
78
+ "rationale": "Silent no-op symptom \u2014 attribute/scheme drift."
79
+ },
80
+ {
81
+ "id": "audit-gap-01",
82
+ "phrase": "why does npm run dev fail to resolve @adia-ai imports",
83
+ "expected": "adia-audit",
84
+ "expected_shape": "audit-health",
85
+ "rationale": "Class-0 manifest-gap symptom."
86
+ },
87
+ {
88
+ "id": "audit-gap-02",
89
+ "phrase": "check this repo for hand-rolled things the library now ships",
90
+ "expected": "adia-audit",
91
+ "expected_shape": "audit-health",
92
+ "rationale": "Class-3 capability drift."
93
+ },
94
+ {
95
+ "id": "audit-report-01",
96
+ "phrase": "give me a health report on our AdiaUI consumer app",
97
+ "expected": "adia-audit",
98
+ "expected_shape": "audit-health",
99
+ "rationale": "The diagnostic-report deliverable."
100
+ },
101
+ {
102
+ "id": "audit-recon-01",
103
+ "phrase": "before I edit this brownfield surface, what's the repo's adoption state",
104
+ "expected": "adia-audit",
105
+ "expected_shape": "brownfield-recon",
106
+ "rationale": "Recon-earns-remediation, the core posture."
107
+ },
108
+ {
109
+ "id": "adv-orient-01",
110
+ "phrase": "we're starting a new internal claims tool on adia-ui, plan it",
111
+ "expected": null,
112
+ "expected_shape": "adia-orient",
113
+ "rationale": "GREENFIELD classification/planning \u2014 adia-orient, not a brownfield audit."
114
+ },
115
+ {
116
+ "id": "adv-migrate-01",
117
+ "phrase": "run the migration sweep to bump @adia-ai from 0.6 to 0.8",
118
+ "expected": null,
119
+ "expected_shape": "adia-migrate",
120
+ "rationale": "The mechanical sweep AFTER a confirmed plan \u2014 adia-migrate executes; audit only diagnoses."
121
+ },
122
+ {
123
+ "id": "adv-verify-01",
124
+ "phrase": "QA this screen in the browser and check a11y",
125
+ "expected": null,
126
+ "expected_shape": "adia-verify",
127
+ "rationale": "Browser QA of a built surface \u2014 adia-verify, not repo diagnosis."
128
+ },
129
+ {
130
+ "id": "adv-compose-01",
131
+ "phrase": "build the settings screen from this plan",
132
+ "expected": null,
133
+ "expected_shape": "adia-compose",
134
+ "rationale": "Authoring a new surface \u2014 the audit hands off to a builder, never authors."
135
+ },
136
+ {
137
+ "id": "adv-release-01",
138
+ "phrase": "cut a release and write the migration guide",
139
+ "expected": null,
140
+ "expected_shape": "adia-forge:adia-release",
141
+ "rationale": "Framework release engineering \u2014 a different plugin entirely."
142
+ },
143
+ {
144
+ "id": "adv-generic-01",
145
+ "phrase": "audit our npm dependencies for security vulnerabilities",
146
+ "expected": null,
147
+ "expected_shape": "none",
148
+ "rationale": "Generic dependency audit unrelated to @adia-ai consumer health."
149
+ }
150
+ ],
10
151
  "minimums_per_spec": {
11
152
  "trigger_phrases": 14,
12
153
  "adversarial_phrases": 6,
13
154
  "task_shapes_covered": "audit-health, wrong-output-root-cause, is-it-current, what-to-migrate, brownfield-recon",
14
155
  "adversarial_fraction": "30%"
15
156
  },
16
-
17
- "phrases": [
18
- { "id": "audit-health-01", "phrase": "audit this AdiaUI app", "should_route_to_audit": true, "expected_shape": "audit-health", "rationale": "Canonical audit request on an existing consumer repo." },
19
- { "id": "audit-health-02", "phrase": "review this @adia-ai codebase before we touch it", "should_route_to_audit": true, "expected_shape": "brownfield-recon", "rationale": "Recon-before-edit on an inherited repo." },
20
- { "id": "audit-health-03", "phrase": "I inherited a repo that uses @adia-ai — what state is it in", "should_route_to_audit": true, "expected_shape": "brownfield-recon", "rationale": "Inherited-repo health check." },
21
- { "id": "audit-current-01", "phrase": "is this app on the latest @adia-ai version", "should_route_to_audit": true, "expected_shape": "is-it-current", "rationale": "Version-currency question — the recon 3-tuple." },
22
- { "id": "audit-current-02", "phrase": "is our AdiaUI setup up to date or drifted", "should_route_to_audit": true, "expected_shape": "is-it-current", "rationale": "Drift-detection framing." },
23
- { "id": "audit-migrate-01", "phrase": "what should we migrate in this AdiaUI app", "should_route_to_audit": true, "expected_shape": "what-to-migrate", "rationale": "Diagnosis-first: the audit produces the ranked what, adia-migrate executes it." },
24
- { "id": "audit-wrong-01", "phrase": "the dashboard renders unstyled and broken, what's wrong", "should_route_to_audit": true, "expected_shape": "wrong-output-root-cause", "rationale": "Wrong-output symptom → the correction loop." },
25
- { "id": "audit-wrong-02", "phrase": "this screen doesn't match the reference, why", "should_route_to_audit": true, "expected_shape": "wrong-output-root-cause", "rationale": "Mismatch-vs-reference → root-cause triage." },
26
- { "id": "audit-wrong-03", "phrase": "the admin shell topbar looks mispositioned", "should_route_to_audit": true, "expected_shape": "wrong-output-root-cause", "rationale": "The Light-DOM zeroth-question archetype." },
27
- { "id": "audit-wrong-04", "phrase": "components render empty even though the data is set", "should_route_to_audit": true, "expected_shape": "wrong-output-root-cause", "rationale": "Silent no-op symptom — attribute/scheme drift." },
28
- { "id": "audit-gap-01", "phrase": "why does npm run dev fail to resolve @adia-ai imports", "should_route_to_audit": true, "expected_shape": "audit-health", "rationale": "Class-0 manifest-gap symptom." },
29
- { "id": "audit-gap-02", "phrase": "check this repo for hand-rolled things the library now ships", "should_route_to_audit": true, "expected_shape": "audit-health", "rationale": "Class-3 capability drift." },
30
- { "id": "audit-report-01", "phrase": "give me a health report on our AdiaUI consumer app", "should_route_to_audit": true, "expected_shape": "audit-health", "rationale": "The diagnostic-report deliverable." },
31
- { "id": "audit-recon-01", "phrase": "before I edit this brownfield surface, what's the repo's adoption state", "should_route_to_audit": true, "expected_shape": "brownfield-recon", "rationale": "Recon-earns-remediation, the core posture." },
32
-
33
- { "id": "adv-orient-01", "phrase": "we're starting a new internal claims tool on adia-ui, plan it", "should_route_to_audit": false, "expected_shape": "adia-orient", "rationale": "GREENFIELD classification/planning — adia-orient, not a brownfield audit." },
34
- { "id": "adv-migrate-01", "phrase": "run the migration sweep to bump @adia-ai from 0.6 to 0.8", "should_route_to_audit": false, "expected_shape": "adia-migrate", "rationale": "The mechanical sweep AFTER a confirmed plan — adia-migrate executes; audit only diagnoses." },
35
- { "id": "adv-verify-01", "phrase": "QA this screen in the browser and check a11y", "should_route_to_audit": false, "expected_shape": "adia-verify", "rationale": "Browser QA of a built surface — adia-verify, not repo diagnosis." },
36
- { "id": "adv-compose-01", "phrase": "build the settings screen from this plan", "should_route_to_audit": false, "expected_shape": "adia-compose", "rationale": "Authoring a new surface — the audit hands off to a builder, never authors." },
37
- { "id": "adv-release-01", "phrase": "cut a release and write the migration guide", "should_route_to_audit": false, "expected_shape": "adia-forge:adia-release", "rationale": "Framework release engineering — a different plugin entirely." },
38
- { "id": "adv-generic-01", "phrase": "audit our npm dependencies for security vulnerabilities", "should_route_to_audit": false, "expected_shape": "none", "rationale": "Generic dependency audit unrelated to @adia-ai consumer health." }
39
- ],
40
-
41
157
  "evaluator_notes": "adia-audit's tightest confusables are adia-orient (greenfield vs brownfield) and adia-migrate (diagnose vs execute). The description leads with EXISTING/brownfield and fences both explicitly."
42
158
  }
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: adia-charts
3
+ description: >-
4
+ Which adia-ui component renders a chart, graph, sparkline, gauge, or
5
+ heatmap, and how to wire its data/legend/theming. Use for "add a chart",
6
+ "show a graph", "visualize this data", "add a sparkline/gauge/heatmap", or
7
+ "wire a chart legend". NOT for the surrounding screen (adia-compose),
8
+ color tokens (adia-tokens), or data fetching (adia-data).
9
+ disable-model-invocation: false
10
+ user-invocable: false
11
+ ---
12
+
13
+ # adia-charts — chart & graph component usage
14
+
15
+ `<chart-ui>` is the single declarative SVG chart primitive — 18 types behind one `type`
16
+ attribute, one data shape, one event contract. `<chart-legend-ui>` and `<heatmap-ui>` are its
17
+ two chart-family siblings. This pack answers "which component / prop / wiring" for chart-shaped
18
+ asks; it never composes the screen around the chart.
19
+
20
+ `<chat-thread-ui>` (the chat-message scroll primitive) is unrelated to this pack despite the
21
+ name collision with "chart" — it belongs to the chat/messaging family (`chat-thread.yaml`
22
+ keywords: chat, message, conversation), not the chart family. Don't route chat-shaped asks here.
23
+
24
+ ## Which component for which need
25
+
26
+ | Need | Component | `type` / notes |
27
+ | --- | --- | --- |
28
+ | any of bar/line/pie/donut/radar/area/scatter/gauge/funnel/treemap/sankey/composed | **chart-ui** | `type="…"` — see [chart-type-catalog.md](references/chart-type-catalog.md) for the full 18-type map |
29
+ | a keyboard-toggleable series legend beside a chart | **chart-legend-ui** | `[for]` id-ref auto-mirrors **chart-ui only** (reads `.legendData`/`legend-update`, which heatmap-ui never populates or dispatches); `items=` for standalone |
30
+ | calendar/contribution grid or a density matrix | **heatmap-ui** | `type="day-grid"` \| `matrix` \| `density` — NOT chart-ui; chart.yaml explicitly routes density-grid asks here. Its legend equivalent is the built-in Less/More strip (`no-legend` prop to hide it), not `chart-legend-ui` |
31
+ | a single prominent KPI number (+ delta, + optional inline mini-chart) | **stat-ui** | not itself a chart; composes a `<chart-ui type="sparkline" slot="chart">` via its `chart` slot + `[bleed]` |
32
+ | a labeled completion bar/percentage, not a plotted series | **progress-ui** | boundary case — see stat.yaml's own rule: "stat for standalone metrics, progress for completion bars" |
33
+
34
+ Full type-by-type mapping (data shape, x/y semantics, when each of the 18 `chart-ui` types
35
+ fits) is in [chart-type-catalog.md](references/chart-type-catalog.md) — consult it before
36
+ picking a `type` value for anything beyond the five common cases in the table above.
37
+
38
+ ## Data binding — the shared shape (except Sankey)
39
+
40
+ Most `chart-ui` types consume an array of plain objects, keyed by the `x` and `y` attributes —
41
+ **not** the Chart.js `{labels, datasets}` envelope:
42
+
43
+ ```html
44
+ <chart-ui type="bar" x="month" y="revenue"></chart-ui>
45
+ <script>
46
+ document.querySelector('chart-ui').data = [
47
+ { month: 'Jan', revenue: 3200 },
48
+ { month: 'Feb', revenue: 4100 },
49
+ ];
50
+ </script>
51
+ ```
52
+
53
+ `type="sankey"` is the exception: it ignores `x`/`y` and expects flow-link rows shaped
54
+ `{ source, target, value }` instead. See
55
+ [chart-type-catalog.md](references/chart-type-catalog.md).
56
+
57
+ - `.data` (JS property) is the canonical entry point; a declarative `data='[…]'` JSON-array
58
+ attribute is also accepted and hydrated once at connect — useful for static-HTML demos.
59
+ - `y` is comma-separated for multi-series types (`y="revenue,users"` → `stacked-bar` /
60
+ `grouped-bar` / `multi-line` / `composed`); single-series types read only the first key.
61
+ - Passing a non-array (the Chart.js envelope, `null`, an object) is silently coerced to `[]` —
62
+ a blank chart with a one-shot console warning, not a thrown error. If a chart renders empty,
63
+ check the data shape first.
64
+ - Past ~5,000 rows, `chart-ui` re-renders the full SVG string on every `.data` write and
65
+ perf degrades — downsample (LTTB, bucket aggregation) at the data layer before setting
66
+ `.data`, or raise the budget via `--chart-perf-budget` for a deliberate large render.
67
+
68
+ ## Composition patterns
69
+
70
+ - **Chart + legend, auto-wired**: give the chart an `id`, point the legend's `[for]` at it —
71
+ toggling a legend row hides/dims that series in the chart, no manual event wiring needed.
72
+ ```html
73
+ <chart-ui id="rev" type="multi-line" x="month" y="revenue,users"></chart-ui>
74
+ <chart-legend-ui for="rev" shape="line" position="bottom"></chart-legend-ui>
75
+ ```
76
+ - **Standalone legend**: `items='[{"key":"revenue","label":"Revenue","slot":0}, …]'` when no
77
+ chart-ui sibling exists, or the legend represents a chart rendered elsewhere.
78
+ - **KPI card with inline trend**: `<stat-ui bleed>` + a `<chart-ui slot="chart" type="sparkline">`
79
+ child — the value/label/change stack left, the chart bleeds the card's right column.
80
+ - **Dashboard grid**: `<stat-ui>` cards for headline KPIs + `<chart-ui>` cards for trend detail,
81
+ laid out via `Grid`/`Card` — see chart.yaml's own `chart-dashboard` example for the canonical
82
+ a2ui shape (KPI row + two chart cards). Screen-level grid/layout choices are `adia-compose`'s
83
+ job, not this pack's.
84
+ - **Empty state**: a `slot="empty"` child (typically `<empty-state-ui>`) renders in place of the
85
+ SVG when `.data` is empty/unset; visibility is CSS-toggled via `[data-has-data]` — no
86
+ imperative show/hide needed.
87
+ - **Loading**: `loading` boolean prop swaps in a `skeleton-ui` placeholder that preserves the
88
+ chart's footprint (parity with `table-ui[loading]` / `stat-ui[loading]`).
89
+ - **Hover/tooltip**: `chart-ui` and `heatmap-ui` both emit the canonical `chart-hover` /
90
+ `chart-leave` / `chart-select` event trio (heatmap re-emits `cell-hover`/`cell-click` under
91
+ these same names) — wire a shared `tooltip-ui[follows="pointer"][for]` once instead of a
92
+ per-chart-kind listener. Full event payload shapes and the a11y/keyboard contract are in
93
+ [composition-and-theming.md](references/composition-and-theming.md).
94
+
95
+ ## Theming & responsive — framework-level conventions
96
+
97
+ - **Never a raw color.** `color="accent|success|warning|danger|info"` picks the intent palette;
98
+ per-series identity colors come from the 10-slot categorical ramp (`--chart-0`…`--chart-9`,
99
+ aliasing `--a-data-0`…`--a-data-9`) — the same law `adia-tokens` states for chart identity vs.
100
+ semantic-state tokens. Recolor one named series by overriding `--color-{key}` at any ancestor;
101
+ never hand-write a hex or `oklch()` value into chart CSS.
102
+ - **Number formatting** is a prop, not per-chart math: `format="abbr|decimal|currency|percent"`
103
+ (currency's `$` prefix is itself a token, `--chart-currency-prefix`, so locale retuning never
104
+ touches markup).
105
+ - **Responsive by container, not viewport.** A chart derives width from its actual rendered
106
+ container width (`ResizeObserver`-driven) and height from a 4:3 aspect ratio unless an explicit
107
+ height is set; `--chart-max-height` (default `28rem`) caps runaway heights on wide viewports.
108
+ Font/label sizing auto-classes to `sm`/`md`/`lg` off the smallest rendered dimension — the
109
+ `size` prop overrides the auto-class when a fixed density is wanted regardless of container.
110
+ - **Never wrap in a fixed-pixel container to "make it responsive.**" Size the parent (`Grid`
111
+ column, `Card` section, `%`/`fr` width) and let `chart-ui` read that.
112
+
113
+ Token roster, per-series override mechanics, keyboard/a11y contract, and the full event-payload
114
+ shapes: [composition-and-theming.md](references/composition-and-theming.md).
115
+
116
+ ## Consult table
117
+
118
+ | Ask | Answer from |
119
+ | --- | --- |
120
+ | "which chart-ui type for X" | [chart-type-catalog.md](references/chart-type-catalog.md) |
121
+ | "how do I color/theme a chart" | Theming section above, then [composition-and-theming.md](references/composition-and-theming.md) |
122
+ | "wire a legend to a chart" | Composition patterns above |
123
+ | "chart renders blank" | Data binding section — check the `.data` shape first |
124
+ | "chart-ui vs heatmap-ui vs stat-ui" | Which-component table above |
125
+ | "build the whole dashboard screen" | `adia-compose` — this pack answers per-chart usage, not screen composition |
126
+ | "which token/color role" (beyond the chart identity ramp) | `adia-tokens` |
127
+ | "fetch/hydrate the chart's data" | `adia-data` |
@@ -0,0 +1,20 @@
1
+ {
2
+ "skill": "adia-charts",
3
+ "note": "Trigger-routing suite (gh#369). expect=trigger: the skill should fire on the prompt in a fresh session. expect=no-trigger: a near-miss owned elsewhere (owner named per case) or generic knowledge with no AdiaUI skill involved. Cases derived from evals/routing-corpus.json's phrases array (gh#355 vetted corpus, with rationale) plus the SKILL.md description's own trigger/NOT-fence language.",
4
+ "cases": [
5
+ { "id": "t01", "prompt": "Add a bar chart showing monthly revenue", "expect": "trigger" },
6
+ { "id": "t02", "prompt": "What component do I use for a donut chart?", "expect": "trigger" },
7
+ { "id": "t03", "prompt": "Show a sparkline inside a KPI card", "expect": "trigger" },
8
+ { "id": "t04", "prompt": "Add a calendar heatmap like GitHub's contribution graph", "expect": "trigger" },
9
+ { "id": "t05", "prompt": "My chart-ui data isn't showing anything on the page", "expect": "trigger" },
10
+ { "id": "t06", "prompt": "Wire a legend so clicking a series hides it in the chart", "expect": "trigger" },
11
+ { "id": "t07", "prompt": "How do I recolor just one series in a multi-line chart?", "expect": "trigger" },
12
+ { "id": "t08", "prompt": "Listen for hover events on chart datapoints", "expect": "trigger" },
13
+ { "id": "n01", "prompt": "Build the analytics dashboard screen with charts and stat cards", "expect": "no-trigger", "owner": "adia-compose" },
14
+ { "id": "n02", "prompt": "Which color role should a warning badge use?", "expect": "no-trigger", "owner": "adia-tokens" },
15
+ { "id": "n03", "prompt": "Fetch the chart's data from our backend API", "expect": "no-trigger", "owner": "adia-data" },
16
+ { "id": "n04", "prompt": "Add a chat thread showing the conversation with the assistant", "expect": "no-trigger" },
17
+ { "id": "n05", "prompt": "Add a progress bar showing 40 percent complete", "expect": "no-trigger" },
18
+ { "id": "n06", "prompt": "The page renders blank after I added a chart, check the console errors", "expect": "no-trigger", "owner": "adia-verify" }
19
+ ]
20
+ }
@@ -0,0 +1,155 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "adia-charts-routing-corpus",
4
+ "version": "1.0.0",
5
+ "purpose": "Routing floor for the adia-charts knowledge pack: 'which chart component / how do I wire it' asks reach it; screen composition, data hydration, token-role, and chat-primitive asks route past it.",
6
+ "scoring_notes": "Heuristic TF-IDF proxy (scripts/skills/run-skill-evals.mjs); the real harness routes on descriptions. Treat misroutes as description-tightening signals.",
7
+ "license": "internal",
8
+ "scope": "adia-ui-factory plugin, consumer-side. Covers chart-ui, chart-legend-ui, and heatmap-ui (the chart family); explicitly excludes chat-thread-ui (chat/messaging primitive, unrelated despite the name collision with 'chart').",
9
+ "phrases": [
10
+ {
11
+ "id": "charts-which-01",
12
+ "phrase": "add a bar chart showing monthly revenue",
13
+ "expected": "adia-charts",
14
+ "expected_shape": "which-component",
15
+ "rationale": "Flagship ask — chart type to component mapping."
16
+ },
17
+ {
18
+ "id": "charts-which-02",
19
+ "phrase": "what component do I use for a donut chart",
20
+ "expected": "adia-charts",
21
+ "expected_shape": "which-component",
22
+ "rationale": "Type-to-component lookup."
23
+ },
24
+ {
25
+ "id": "charts-which-03",
26
+ "phrase": "show a sparkline inside a KPI card",
27
+ "expected": "adia-charts",
28
+ "expected_shape": "which-component",
29
+ "rationale": "stat-ui + chart-ui[type=sparkline] composition, still this pack's territory."
30
+ },
31
+ {
32
+ "id": "charts-which-04",
33
+ "phrase": "add a calendar heatmap like GitHub contributions",
34
+ "expected": "adia-charts",
35
+ "expected_shape": "which-component",
36
+ "rationale": "heatmap-ui is a chart-family sibling, not chart-ui itself, but the ask is chart-shaped."
37
+ },
38
+ {
39
+ "id": "charts-which-05",
40
+ "phrase": "which chart type works for a signup-to-purchase conversion funnel",
41
+ "expected": "adia-charts",
42
+ "expected_shape": "which-component",
43
+ "rationale": "type=funnel lookup from the catalog."
44
+ },
45
+ {
46
+ "id": "charts-which-06",
47
+ "phrase": "add a gauge showing progress toward a target number",
48
+ "expected": "adia-charts",
49
+ "expected_shape": "which-component",
50
+ "rationale": "type=gauge lookup; distinct from progress-ui's completion-bar territory."
51
+ },
52
+ {
53
+ "id": "charts-data-01",
54
+ "phrase": "my chart-ui data isn't showing anything on the page",
55
+ "expected": "adia-charts",
56
+ "expected_shape": "data-binding",
57
+ "rationale": "Blank-chart triage — data shape check per chart.js's own shape-warning."
58
+ },
59
+ {
60
+ "id": "charts-data-02",
61
+ "phrase": "how do I pass an array of data objects to chart-ui",
62
+ "expected": "adia-charts",
63
+ "expected_shape": "data-binding",
64
+ "rationale": "The x/y-keyed row shape, not the Chart.js envelope."
65
+ },
66
+ {
67
+ "id": "charts-compose-01",
68
+ "phrase": "wire a legend so clicking a series hides it in the chart",
69
+ "expected": "adia-charts",
70
+ "expected_shape": "composition-legend",
71
+ "rationale": "chart-legend-ui [for] auto-mirror + toggle wiring."
72
+ },
73
+ {
74
+ "id": "charts-theme-01",
75
+ "phrase": "how do I recolor just one series in a multi-line chart",
76
+ "expected": "adia-charts",
77
+ "expected_shape": "theming",
78
+ "rationale": "--color-{key} per-series override mechanics."
79
+ },
80
+ {
81
+ "id": "charts-theme-02",
82
+ "phrase": "make the chart values display as currency",
83
+ "expected": "adia-charts",
84
+ "expected_shape": "theming",
85
+ "rationale": "format=currency prop + --chart-currency-prefix token."
86
+ },
87
+ {
88
+ "id": "charts-responsive-01",
89
+ "phrase": "the chart looks huge and stretched on a wide screen",
90
+ "expected": "adia-charts",
91
+ "expected_shape": "responsive",
92
+ "rationale": "Container-based sizing + --chart-max-height cap."
93
+ },
94
+ {
95
+ "id": "charts-events-01",
96
+ "phrase": "listen for hover events on chart datapoints",
97
+ "expected": "adia-charts",
98
+ "expected_shape": "events",
99
+ "rationale": "chart-hover/chart-leave/chart-select payload contract."
100
+ },
101
+ {
102
+ "id": "charts-adv-01",
103
+ "phrase": "build the analytics dashboard screen with charts and stat cards",
104
+ "expected": "adia-compose",
105
+ "rationale": "Adversarial — screen/grid composition consumes the answer; the ask is a build.",
106
+ "expected_alternative_raw": "adia-compose (adia-ui-factory)"
107
+ },
108
+ {
109
+ "id": "charts-adv-02",
110
+ "phrase": "which color role should a warning badge use",
111
+ "expected": "adia-tokens",
112
+ "rationale": "Adversarial — a token-role ask with no chart in it at all.",
113
+ "expected_alternative_raw": "adia-tokens (adia-ui-factory)"
114
+ },
115
+ {
116
+ "id": "charts-adv-03",
117
+ "phrase": "fetch the chart's data from our backend API",
118
+ "expected": "adia-data",
119
+ "rationale": "Adversarial — data hydration/fetch is adia-data's territory; this pack only covers the .data shape once it arrives.",
120
+ "expected_alternative_raw": "adia-data (adia-ui-factory)"
121
+ },
122
+ {
123
+ "id": "charts-adv-04",
124
+ "phrase": "add a chat thread showing the conversation with the assistant",
125
+ "expected": null,
126
+ "rationale": "Adversarial — chat-thread-ui is a chat/messaging primitive, unrelated to the chart family despite the name collision; resolved explicitly out of scope for this pack (gh#381).",
127
+ "expected_alternative_raw": "chat/messaging surface (chat-shell / chat-thread-ui) — not this pack"
128
+ },
129
+ {
130
+ "id": "charts-adv-05",
131
+ "phrase": "add a progress bar showing 40 percent complete",
132
+ "expected": null,
133
+ "rationale": "Adversarial — a completion bar is progress-ui's territory, not a chart type; stat.yaml's own rule draws this exact boundary.",
134
+ "expected_alternative_raw": "progress-ui (not a chart-family primitive)"
135
+ },
136
+ {
137
+ "id": "charts-adv-06",
138
+ "phrase": "the page renders blank after I added a chart",
139
+ "expected": "adia-verify",
140
+ "rationale": "Adversarial — a broken render is the browser gate's territory, not a chart-usage question.",
141
+ "expected_alternative_raw": "adia-verify (adia-ui-factory)"
142
+ }
143
+ ],
144
+ "minimums_per_spec": {
145
+ "trigger_phrases": 13,
146
+ "adversarial_phrases": 6,
147
+ "task_shapes_covered": "which-component, data-binding, composition-legend, theming, responsive, events",
148
+ "adversarial_fraction": "32%"
149
+ },
150
+ "evaluator_notes": {
151
+ "known_limitations": "The chat-thread-ui exclusion (charts-adv-04) is the corpus's only defense against the reporter's original ambiguity (gh#381 linked chat-thread alongside chart/chart-legend) — treat any future misroute here as a description regression, not noise.",
152
+ "promotion_criteria": "F1 >= 0.85 across 3+ runs",
153
+ "review_cadence": "on any description edit; on /eval-run findings"
154
+ }
155
+ }