@adia-ai/adia-ui-forge 0.8.9 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adia-forge",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "author": {
6
6
  "name": "Kim",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog — adia-forge
2
2
 
3
+ ## [0.8.11] — 2026-07-23
4
+
5
+ ### Fixed
6
+ - **`adia-author`: dist-bundle regen joins the structural-gate sequence** (`skills/adia-author/SKILL.md`, `references/authoring-cycle.md`) — a new/changed component CSS `@import` or barrel export drifts `dist/` bundles, and the skill's verify sequence never said so; gh#390's PR failed CI's `check:css-bundles-fresh`/`check:js-bundles-fresh` exactly this way. The gate sequence and the barrel-registration step now both name `build:bundle-css`/`build:bundle-js` + the two freshness checks.
7
+ - **`adia-release`: `release-pack.mjs --mode handoff` validates `--gh-notes-file` at parse time** — the flag was only checked at Step 10 (GH releases), AFTER tags and npm publish were irreversible; the v0.8.10 cut died there live. Selftest case added.
8
+ - **`adia-release`: mid-Step-4 resume path documented** (`references/cut-procedure.md` §4-resume) — once any CHANGELOG promotion lands, re-invoking the orchestrator hard-errors on the idempotency guard ("already has ## [X.Y.Z]") forever; the doc now names the standalone-pieces sequence (bump → lockfile → lockstep → 4f → 4e → Step 5/5.7) instead of leaving the operator to reverse-engineer it mid-cut.
9
+ - **`adia-release`: stub-package ownership rule** (`references/changelog-discipline.md` §Stubs) — `insert-stub.mjs` inserts, never promotes; a hand-written `[Unreleased]` in a `--stub-packages` target survives as an orphaned second block and fails the loud guard (v0.8.10 lost a cycle to this across 6 packages). Rule: the tool owns stub packages; hand-written content means the package belongs in `--substantive-packages`.
10
+ - **`release-pretag-docs-gate`: a `cd <path> && …` command prefix now resolves the gate against THAT checkout, not the session cwd** (`bin/release-pretag-docs-gate`) — a session pinned to a stale worktree (own copy of the gate script, branch without the release's CHANGELOG sections) false-FAILed the v0.8.10 handoff even though the command explicitly cd'd to the clean primary checkout. Selftest fixtures added for the prefix resolution.
11
+
12
+ ### Maintenance
13
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
14
+
15
+ ## [0.8.10] — 2026-07-20
16
+
17
+ ### Added
18
+ - **`evals/evals.json` behavioral test-case files for 8 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, with real judgment applied — the forge side required genuine authoring since its corpus phrases are terse fragments, not natural-language prompts (independently reviewed, sampled).
19
+
20
+ ### Fixed
21
+ - **`evals/routing-corpus.json` unified onto one schema across all skills** (gh#355) — converged forge's `{positives,negatives}` shape and factory's `{phrases}` shape onto the `{phrases:[...]}` form `scripts/skills/run-skill-evals.mjs` actually reads. `run-skill-evals.mjs` extended to aggregate the global corpus with every per-skill corpus (per-skill wins on id collision) instead of reading only the 97-phrase global file; added a `selftest` subcommand. Does NOT touch `routing_eval.py`/`release_gate.py` — those live in an externally-installed marketplace plugin, out of this repo's reach; gh#369 is the separate, real fix for G7's actual coverage check.
22
+
23
+ ### Maintenance
24
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
25
+
3
26
  ## [0.8.9] — 2026-07-19
4
27
 
5
28
  ### Fixed
@@ -89,6 +89,33 @@ def classify(command):
89
89
  return None
90
90
 
91
91
 
92
+ CD_PREFIX = re.compile(r"""^\s*cd\s+(?:--\s+)?(['"]?)([^'";&|\n]+)\1\s*(?:&&|;)""")
93
+
94
+
95
+ def resolve_start_dir(command, cwd):
96
+ """A command that opens with `cd <path> && …` targets THAT checkout, not
97
+ the session's cwd. Live false FAIL (v0.8.10 handoff, 2026-07-20): the
98
+ session sat pinned in a stale worktree (its own copy of the gate script +
99
+ a branch with no [0.8.10] CHANGELOG sections) while the command cd'd to
100
+ the primary checkout on post-merge main — the gate validated the stale
101
+ worktree and denied a genuinely clean release. Prefer the cd target when
102
+ it is a real directory; otherwise fall back to the event cwd."""
103
+ m = CD_PREFIX.match(command or "")
104
+ if m:
105
+ # Mirror the shell: ~ expands only when the operand is UNQUOTED —
106
+ # `cd "~"` targets a literal ./~ (and typically fails), so resolving
107
+ # $HOME here would let a quoted-tilde push bypass the gate whenever
108
+ # $HOME lacks the gate script (review finding, PR #394).
109
+ target = m.group(2).strip()
110
+ if not m.group(1):
111
+ target = os.path.expanduser(target)
112
+ if not os.path.isabs(target) and cwd:
113
+ target = os.path.join(cwd, target)
114
+ if os.path.isdir(target):
115
+ return target
116
+ return cwd
117
+
118
+
92
119
  def find_repo_gate(start):
93
120
  """Walk up from `start` to the git root looking for the gate script —
94
121
  a release command launched from a subdirectory must not bypass the
@@ -125,10 +152,11 @@ def hook_mode():
125
152
  sys.exit(0)
126
153
  if event.get("tool_name") != "Bash":
127
154
  sys.exit(0)
128
- version = classify((event.get("tool_input") or {}).get("command", ""))
155
+ command = (event.get("tool_input") or {}).get("command", "")
156
+ version = classify(command)
129
157
  if not version:
130
158
  sys.exit(0)
131
- root, gate = find_repo_gate(event.get("cwd"))
159
+ root, gate = find_repo_gate(resolve_start_dir(command, event.get("cwd")))
132
160
  if not gate:
133
161
  sys.exit(0) # consumer repo — nothing to enforce here
134
162
  if version == AMBIGUOUS:
@@ -214,6 +242,27 @@ def selftest():
214
242
  if gate is not None:
215
243
  print("selftest FAIL: consumer repo must yield no gate", file=sys.stderr)
216
244
  sys.exit(1)
245
+ # resolve_start_dir: a `cd <path> && …` prefix must win over the session
246
+ # cwd (the v0.8.10 pinned-worktree false FAIL); anything else falls back.
247
+ with tempfile.TemporaryDirectory() as td:
248
+ real = os.path.join(td, "checkout")
249
+ os.makedirs(real)
250
+ cases_dir = [
251
+ (f"cd {real} && node release-pack.mjs --mode handoff --version 0.9.0", "/elsewhere", real),
252
+ (f'cd "{real}" && git push origin v0.9.0', "/elsewhere", real),
253
+ (f"cd {td}/missing && node release-pack.mjs --mode handoff --version 0.9.0", "/elsewhere", "/elsewhere"),
254
+ ("node release-pack.mjs --mode handoff --version 0.9.0", "/elsewhere", "/elsewhere"),
255
+ ("", "/elsewhere", "/elsewhere"),
256
+ # Quoted tilde: bash cd's to a literal ./~, NOT $HOME — the gate
257
+ # must not resolve $HOME either (quoted-tilde bypass, PR #394).
258
+ ('cd "~" && git push origin v0.9.0', "/elsewhere", "/elsewhere"),
259
+ ]
260
+ for cmd, cwd, want in cases_dir:
261
+ got = resolve_start_dir(cmd, cwd)
262
+ if got != want:
263
+ print(f"selftest FAIL: resolve_start_dir({cmd!r}, {cwd!r}) = {got!r}, want {want!r}", file=sys.stderr)
264
+ sys.exit(1)
265
+
217
266
  print("selftest OK")
218
267
 
219
268
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-forge",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "keywords": [
6
6
  "adia-ui",
@@ -0,0 +1,23 @@
1
+ {
2
+ "skill": "adia-a2ui",
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) plus the SKILL.md description's own trigger/NOT-fence language.",
4
+ "cases": [
5
+ { "id": "t01", "prompt": "Validate this A2UI document against the schema", "expect": "trigger" },
6
+ { "id": "t02", "prompt": "Harvest a chunk from this HTML demo for the corpus", "expect": "trigger" },
7
+ { "id": "t03", "prompt": "Zettel coverage dropped after the last corpus change, find out why", "expect": "trigger" },
8
+ { "id": "t04", "prompt": "Tune the STRONG_MATCH threshold for the retrieval scorer", "expect": "trigger" },
9
+ { "id": "t05", "prompt": "Run check_anti_patterns on this rendered gallery HTML", "expect": "trigger" },
10
+ { "id": "t06", "prompt": "Add a new MCP tool to the a2ui server for refine_composition", "expect": "trigger" },
11
+ { "id": "t07", "prompt": "Diagnose this eval gap — coverage regressed and I need the root cause", "expect": "trigger" },
12
+ { "id": "t08", "prompt": "Lift a semantic fail that's scoring under sixty in the nightly eval", "expect": "trigger" },
13
+ { "id": "t09", "prompt": "Why did the composer emit composition-match instead of composition-synthesized for this prompt?", "expect": "trigger" },
14
+ { "id": "t10", "prompt": "This content shape can't be expressed by any component's A2UI contract — audit the catalog", "expect": "trigger" },
15
+ { "id": "n01", "prompt": "Build a settings page from existing primitives for our app", "expect": "no-trigger", "owner": "adia-compose" },
16
+ { "id": "n02", "prompt": "Add a slot to button-ui and update its yaml contract", "expect": "no-trigger", "owner": "adia-author" },
17
+ { "id": "n03", "prompt": "Score the generated UI quality in apps/genui against the rubric", "expect": "no-trigger", "owner": "adia-gen-review" },
18
+ { "id": "n04", "prompt": "Run a broad visual QA sweep across site and playgrounds before we cut", "expect": "no-trigger", "owner": "adia-dogfood" },
19
+ { "id": "n05", "prompt": "Fix the @adia-ai/llm SSE adapter so it emits a terminal done chunk", "expect": "no-trigger", "owner": "adia-llm-internals" },
20
+ { "id": "n06", "prompt": "Mount gen-root and wire data resolvers for end users at runtime", "expect": "no-trigger", "owner": "adia-genui" },
21
+ { "id": "n07", "prompt": "Edit the getting-started docs page on the site for consistency", "expect": "no-trigger", "owner": "adia-site-docs" }
22
+ ]
23
+ }
@@ -1,38 +1,139 @@
1
1
  {
2
- "positives": [
3
- "validate this A2UI document",
4
- "harvest a chunk from this HTML demo",
5
- "zettel coverage dropped after the last change",
6
- "should this repeated subtree become its own chunk",
7
- "tune the STRONG_MATCH threshold",
8
- "run check_anti_patterns on this rendered HTML",
9
- "refine composition with an OAuth row",
10
- "MRR dropped in the chunk retrieval eval",
11
- "add an MCP tool to the a2ui server",
12
- "audit the training data corpus for drift",
13
- "diagnose this eval gap and regression",
14
- "run the MCP pipeline: generate_ui then validate_schema",
15
- "lift a semantic fail under sixty",
16
- "why did the composer emit composition-match instead of composition-synthesized"
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "adia-a2ui routing accuracy corpus",
4
+ "version": "2.1.0",
5
+ "purpose": "Routing-eval corpus for adia-a2ui. Each phrase declares the skill (expected), a forbidden skill (expected_not, for phrases the source data only ever asserted as \"not this skill\"), or neither. Scored by scripts/skills/run-skill-evals.mjs (TF-IDF token overlap over per-skill description+triggers).",
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
+ "scope": "adia-a2ui routing \u2014 does this phrase activate adia-a2ui?",
8
+ "phrases": [
9
+ {
10
+ "id": "adia-a2ui-pos-01",
11
+ "phrase": "validate this A2UI document",
12
+ "expected": "adia-a2ui"
13
+ },
14
+ {
15
+ "id": "adia-a2ui-pos-02",
16
+ "phrase": "harvest a chunk from this HTML demo",
17
+ "expected": "adia-a2ui"
18
+ },
19
+ {
20
+ "id": "adia-a2ui-pos-03",
21
+ "phrase": "zettel coverage dropped after the last change",
22
+ "expected": "adia-a2ui"
23
+ },
24
+ {
25
+ "id": "adia-a2ui-pos-04",
26
+ "phrase": "should this repeated subtree become its own chunk",
27
+ "expected": "adia-a2ui"
28
+ },
29
+ {
30
+ "id": "adia-a2ui-pos-05",
31
+ "phrase": "tune the STRONG_MATCH threshold",
32
+ "expected": "adia-a2ui"
33
+ },
34
+ {
35
+ "id": "adia-a2ui-pos-06",
36
+ "phrase": "run check_anti_patterns on this rendered HTML",
37
+ "expected": "adia-a2ui"
38
+ },
39
+ {
40
+ "id": "adia-a2ui-pos-07",
41
+ "phrase": "refine composition with an OAuth row",
42
+ "expected": "adia-a2ui"
43
+ },
44
+ {
45
+ "id": "adia-a2ui-pos-08",
46
+ "phrase": "MRR dropped in the chunk retrieval eval",
47
+ "expected": "adia-a2ui"
48
+ },
49
+ {
50
+ "id": "adia-a2ui-pos-09",
51
+ "phrase": "add an MCP tool to the a2ui server",
52
+ "expected": "adia-a2ui"
53
+ },
54
+ {
55
+ "id": "adia-a2ui-pos-10",
56
+ "phrase": "audit the training data corpus for drift",
57
+ "expected": "adia-a2ui"
58
+ },
59
+ {
60
+ "id": "adia-a2ui-pos-11",
61
+ "phrase": "diagnose this eval gap and regression",
62
+ "expected": "adia-a2ui"
63
+ },
64
+ {
65
+ "id": "adia-a2ui-pos-12",
66
+ "phrase": "run the MCP pipeline: generate_ui then validate_schema",
67
+ "expected": "adia-a2ui"
68
+ },
69
+ {
70
+ "id": "adia-a2ui-pos-13",
71
+ "phrase": "lift a semantic fail under sixty",
72
+ "expected": "adia-a2ui"
73
+ },
74
+ {
75
+ "id": "adia-a2ui-pos-14",
76
+ "phrase": "why did the composer emit composition-match instead of composition-synthesized",
77
+ "expected": "adia-a2ui"
78
+ },
79
+ {
80
+ "id": "adia-a2ui-neg-01",
81
+ "phrase": "build a settings page from existing primitives",
82
+ "expected_not": "adia-a2ui"
83
+ },
84
+ {
85
+ "id": "adia-a2ui-neg-02",
86
+ "phrase": "add a slot to button-ui and update its yaml contract",
87
+ "expected_not": "adia-a2ui"
88
+ },
89
+ {
90
+ "id": "adia-a2ui-neg-03",
91
+ "phrase": "cut a release and bump the version tag",
92
+ "expected_not": "adia-a2ui"
93
+ },
94
+ {
95
+ "id": "adia-a2ui-neg-04",
96
+ "phrase": "score the generated UI quality in apps/genui",
97
+ "expected_not": "adia-a2ui"
98
+ },
99
+ {
100
+ "id": "adia-a2ui-neg-05",
101
+ "phrase": "run a broad visual QA sweep across site and playgrounds",
102
+ "expected_not": "adia-a2ui"
103
+ },
104
+ {
105
+ "id": "adia-a2ui-neg-06",
106
+ "phrase": "fix the @adia-ai/llm SSE adapter",
107
+ "expected_not": "adia-a2ui"
108
+ },
109
+ {
110
+ "id": "adia-a2ui-neg-07",
111
+ "phrase": "explain how React state management works",
112
+ "expected_not": "adia-a2ui"
113
+ },
114
+ {
115
+ "id": "adia-a2ui-neg-08",
116
+ "phrase": "compose a settings screen from catalog primitives",
117
+ "expected_not": "adia-a2ui"
118
+ },
119
+ {
120
+ "id": "adia-a2ui-neg-09",
121
+ "phrase": "mount gen-root and wire data resolvers for end users at runtime",
122
+ "expected_not": "adia-a2ui"
123
+ },
124
+ {
125
+ "id": "adia-a2ui-neg-10",
126
+ "phrase": "edit the getting-started docs page on the site",
127
+ "expected_not": "adia-a2ui"
128
+ }
17
129
  ],
18
- "negatives": [
19
- "build a settings page from existing primitives",
20
- "add a slot to button-ui and update its yaml contract",
21
- "cut a release and bump the version tag",
22
- "score the generated UI quality in apps/genui",
23
- "run a broad visual QA sweep across site and playgrounds",
24
- "fix the @adia-ai/llm SSE adapter",
25
- "explain how React state management works",
26
- "compose a settings screen from catalog primitives",
27
- "mount gen-root and wire data resolvers for end users at runtime",
28
- "edit the getting-started docs page on the site"
29
- ],
30
- "_measured": {
130
+ "_measured_historical": {
31
131
  "as_of": "2026-07-18",
32
132
  "scorer": "routing_eval.py (nonoun-plugins/forge)",
33
133
  "f1": 0.783,
34
134
  "precision": 1.0,
35
135
  "recall": 0.643,
36
- "exit_code": 0
136
+ "exit_code": 0,
137
+ "note": "measured by the external routing_eval.py (nonoun-plugins/forge) against the pre-conversion positives/negatives shape; historical record only, not regenerated by run-skill-evals.mjs."
37
138
  }
38
139
  }
@@ -101,6 +101,8 @@ npm run smoke:engines # green
101
101
  node scripts/dev/audit-native-primitive-leak.mjs # 0 critical leaks
102
102
  node scripts/dev/audit-shell-composition.mjs # 0 critical defects
103
103
  node scripts/dev/audit-template-child-conflict.mjs # 0 critical (gh#284 shape — non-null template + slots.default)
104
+ npm run build:bundle-css && npm run build:bundle-js # regenerate dist bundles — any component CSS/JS change drifts them
105
+ npm run check:css-bundles-fresh && npm run check:js-bundles-fresh # both must be clean (CI gates; gh#390's PR failed here)
104
106
  ```
105
107
 
106
108
  A failed gate is the artifact: fix at the source, re-run the narrowest gate,
@@ -0,0 +1,22 @@
1
+ {
2
+ "skill": "adia-author",
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) plus the SKILL.md description's own trigger/NOT-fence language.",
4
+ "cases": [
5
+ { "id": "t01", "prompt": "Add a new <toggle-ui> primitive component from scratch", "expect": "trigger" },
6
+ { "id": "t02", "prompt": "Add a new prop to table-ui for sticky headers", "expect": "trigger" },
7
+ { "id": "t03", "prompt": "Fix the CSS in card-ui to handle the new bleed variant", "expect": "trigger" },
8
+ { "id": "t04", "prompt": "Update the input-ui yaml to add a placeholder attribute", "expect": "trigger" },
9
+ { "id": "t05", "prompt": "Build the chat-shell composition with a new sidebar slot", "expect": "trigger" },
10
+ { "id": "t06", "prompt": "This billing-summary block keeps repeating across apps — extract it to a shared web-modules module", "expect": "trigger" },
11
+ { "id": "t07", "prompt": "Audit the four-axis contract for table-ui — token usage and lifecycle symmetry", "expect": "trigger" },
12
+ { "id": "t08", "prompt": "Author a demo for the billing-overview composite, an examples.html", "expect": "trigger" },
13
+ { "id": "t09", "prompt": "Add a pane behaviour to admin-shell per the bespoke shell-tier convention", "expect": "trigger" },
14
+ { "id": "n01", "prompt": "Compose this Figma mock into AdiaUI components for our consumer app", "expect": "no-trigger", "owner": "adia-compose" },
15
+ { "id": "n02", "prompt": "Cut a release of the next version and publish the npm packages", "expect": "no-trigger", "owner": "adia-release" },
16
+ { "id": "n03", "prompt": "Tune the zettel composition coverage, the eval is at 38%", "expect": "no-trigger", "owner": "adia-a2ui" },
17
+ { "id": "n04", "prompt": "Deploy the API service to the hosting platform", "expect": "no-trigger", "owner": "adia-deploy" },
18
+ { "id": "n05", "prompt": "The gemini adapter is dropping usage tokens on streamed responses", "expect": "no-trigger", "owner": "adia-llm-internals" },
19
+ { "id": "n06", "prompt": "Extend the LLM bridge in @adia-ai/llm to add a new provider", "expect": "no-trigger", "owner": "adia-llm-internals" },
20
+ { "id": "n07", "prompt": "Explain how React hooks work in general", "expect": "no-trigger" }
21
+ ]
22
+ }
@@ -1,43 +1,164 @@
1
1
  {
2
- "positives": [
3
- "add a new button-ui primitive component",
4
- "build a new <toggle-ui> component from scratch",
5
- "create a new primitive web component in packages/web-components",
6
- "add a new prop to table-ui",
7
- "fix the CSS in card-ui to handle the new bleed variant",
8
- "update the input-ui yaml to add a placeholder attribute",
9
- "build the chat-shell composition with the new sidebar slot",
10
- "author a new web-module shell at packages/web-modules/editor/editor-shell",
11
- "add a pane behaviour to admin-shell per the bespoke shell-tier convention",
12
- "promote this inline content to a shared web-modules module",
13
- "this content keeps repeating across apps, extract to a shared module",
14
- "lift this billing-summary block from apps/saas to web-modules",
15
- "audit the four-axis contract for table-ui",
16
- "check the token usage in card-ui for drift",
17
- "lifecycle audit on dropdown-ui \u2014 symmetric connected/disconnected?",
18
- "author a demo for the billing-overview composite",
19
- "compose the examples.html for dashboard-layout",
20
- "write the demo for <integrations-page-ui> in packages/web-modules/settings"
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "name": "adia-author routing accuracy corpus",
4
+ "version": "2.1.0",
5
+ "purpose": "Routing-eval corpus for adia-author. Each phrase declares the skill (expected), a forbidden skill (expected_not, for phrases the source data only ever asserted as \"not this skill\"), or neither. Scored by scripts/skills/run-skill-evals.mjs (TF-IDF token overlap over per-skill description+triggers).",
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
+ "scope": "adia-author routing \u2014 does this phrase activate adia-author?",
8
+ "phrases": [
9
+ {
10
+ "id": "adia-author-pos-01",
11
+ "phrase": "add a new button-ui primitive component",
12
+ "expected": "adia-author"
13
+ },
14
+ {
15
+ "id": "adia-author-pos-02",
16
+ "phrase": "build a new <toggle-ui> component from scratch",
17
+ "expected": "adia-author"
18
+ },
19
+ {
20
+ "id": "adia-author-pos-03",
21
+ "phrase": "create a new primitive web component in packages/web-components",
22
+ "expected": "adia-author"
23
+ },
24
+ {
25
+ "id": "adia-author-pos-04",
26
+ "phrase": "add a new prop to table-ui",
27
+ "expected": "adia-author"
28
+ },
29
+ {
30
+ "id": "adia-author-pos-05",
31
+ "phrase": "fix the CSS in card-ui to handle the new bleed variant",
32
+ "expected": "adia-author"
33
+ },
34
+ {
35
+ "id": "adia-author-pos-06",
36
+ "phrase": "update the input-ui yaml to add a placeholder attribute",
37
+ "expected": "adia-author"
38
+ },
39
+ {
40
+ "id": "adia-author-pos-07",
41
+ "phrase": "build the chat-shell composition with the new sidebar slot",
42
+ "expected": "adia-author"
43
+ },
44
+ {
45
+ "id": "adia-author-pos-08",
46
+ "phrase": "author a new web-module shell at packages/web-modules/editor/editor-shell",
47
+ "expected": "adia-author"
48
+ },
49
+ {
50
+ "id": "adia-author-pos-09",
51
+ "phrase": "add a pane behaviour to admin-shell per the bespoke shell-tier convention",
52
+ "expected": "adia-author"
53
+ },
54
+ {
55
+ "id": "adia-author-pos-10",
56
+ "phrase": "promote this inline content to a shared web-modules module",
57
+ "expected": "adia-author"
58
+ },
59
+ {
60
+ "id": "adia-author-pos-11",
61
+ "phrase": "this content keeps repeating across apps, extract to a shared module",
62
+ "expected": "adia-author"
63
+ },
64
+ {
65
+ "id": "adia-author-pos-12",
66
+ "phrase": "lift this billing-summary block from apps/saas to web-modules",
67
+ "expected": "adia-author"
68
+ },
69
+ {
70
+ "id": "adia-author-pos-13",
71
+ "phrase": "audit the four-axis contract for table-ui",
72
+ "expected": "adia-author"
73
+ },
74
+ {
75
+ "id": "adia-author-pos-14",
76
+ "phrase": "check the token usage in card-ui for drift",
77
+ "expected": "adia-author"
78
+ },
79
+ {
80
+ "id": "adia-author-pos-15",
81
+ "phrase": "lifecycle audit on dropdown-ui \u2014 symmetric connected/disconnected?",
82
+ "expected": "adia-author"
83
+ },
84
+ {
85
+ "id": "adia-author-pos-16",
86
+ "phrase": "author a demo for the billing-overview composite",
87
+ "expected": "adia-author"
88
+ },
89
+ {
90
+ "id": "adia-author-pos-17",
91
+ "phrase": "compose the examples.html for dashboard-layout",
92
+ "expected": "adia-author"
93
+ },
94
+ {
95
+ "id": "adia-author-pos-18",
96
+ "phrase": "write the demo for <integrations-page-ui> in packages/web-modules/settings",
97
+ "expected": "adia-author"
98
+ },
99
+ {
100
+ "id": "adia-author-neg-01",
101
+ "phrase": "compose this Figma mock into AdiaUI components for our consumer app",
102
+ "expected_not": "adia-author"
103
+ },
104
+ {
105
+ "id": "adia-author-neg-02",
106
+ "phrase": "cut a release of the next version and publish the npm packages",
107
+ "expected_not": "adia-author"
108
+ },
109
+ {
110
+ "id": "adia-author-neg-03",
111
+ "phrase": "tune the zettel composition coverage; eval is at 38%",
112
+ "expected_not": "adia-author"
113
+ },
114
+ {
115
+ "id": "adia-author-neg-04",
116
+ "phrase": "build a user profile card with avatar and edit actions",
117
+ "expected_not": "adia-author"
118
+ },
119
+ {
120
+ "id": "adia-author-neg-05",
121
+ "phrase": "deploy the api service to the hosting platform",
122
+ "expected_not": "adia-author"
123
+ },
124
+ {
125
+ "id": "adia-author-neg-06",
126
+ "phrase": "explain how React hooks work",
127
+ "expected_not": "adia-author"
128
+ },
129
+ {
130
+ "id": "adia-author-neg-07",
131
+ "phrase": "the gemini adapter is dropping usage tokens on streamed responses",
132
+ "expected": "adia-llm-internals"
133
+ },
134
+ {
135
+ "id": "adia-author-neg-08",
136
+ "phrase": "fix the openai stopReason mapping in the llm client",
137
+ "expected_not": "adia-author"
138
+ },
139
+ {
140
+ "id": "adia-author-neg-09",
141
+ "phrase": "extend the LLM bridge to add a new provider",
142
+ "expected_not": "adia-author"
143
+ },
144
+ {
145
+ "id": "adia-author-neg-10",
146
+ "phrase": "modify createAdapter in @adia-ai/llm to add chunk-shape support",
147
+ "expected_not": "adia-author"
148
+ },
149
+ {
150
+ "id": "adia-author-neg-11",
151
+ "phrase": "set up the LLM-bridge surface for a new tool-call provider",
152
+ "expected_not": "adia-author"
153
+ }
21
154
  ],
22
- "negatives": [
23
- "compose this Figma mock into AdiaUI components for our consumer app",
24
- "cut a release of the next version and publish the npm packages",
25
- "tune the zettel composition coverage; eval is at 38%",
26
- "build a user profile card with avatar and edit actions",
27
- "deploy the api service to the hosting platform",
28
- "explain how React hooks work",
29
- "the gemini adapter is dropping usage tokens on streamed responses",
30
- "fix the openai stopReason mapping in the llm client",
31
- "extend the LLM bridge to add a new provider",
32
- "modify createAdapter in @adia-ai/llm to add chunk-shape support",
33
- "set up the LLM-bridge surface for a new tool-call provider"
34
- ],
35
- "_measured": {
155
+ "_measured_historical": {
36
156
  "as_of": "2026-07-18",
37
157
  "scorer": "routing_eval.py (nonoun-plugins/forge)",
38
158
  "f1": 0.971,
39
159
  "precision": 1.0,
40
160
  "recall": 0.944,
41
- "exit_code": 0
161
+ "exit_code": 0,
162
+ "note": "measured by the external routing_eval.py (nonoun-plugins/forge) against the pre-conversion positives/negatives shape; historical record only, not regenerated by run-skill-evals.mjs."
42
163
  }
43
164
  }
@@ -200,7 +200,11 @@ node scripts/build/components.mjs --verify # "clean — N files up-to-date"
200
200
 
201
201
  A primitive also needs BOTH barrel registrations — the CSS `@import` in
202
202
  `styles/components.css` AND the JS `export` in `components/index.js`
203
- (`scripts/audit/check-components-js-barrel.mjs` gates the second).
203
+ (`scripts/audit/check-components-js-barrel.mjs` gates the second). Either
204
+ registration drifts the built `dist/` bundles — regenerate them in the same
205
+ change (`npm run build:bundle-css && npm run build:bundle-js`) and commit the
206
+ `dist/` updates, or CI's `check:{css,js}-bundles-fresh` gates fail on the PR
207
+ (gh#390's PR shipped without this and failed exactly there).
204
208
 
205
209
  ## Step 5 — Run the project's verification gates
206
210
 
@@ -0,0 +1,22 @@
1
+ {
2
+ "skill": "adia-deploy",
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) plus the SKILL.md description's own trigger/NOT-fence language.",
4
+ "cases": [
5
+ { "id": "t01", "prompt": "Deploy the latest build to ui-kit.exe.xyz", "expect": "trigger" },
6
+ { "id": "t02", "prompt": "Diagnose why the site returns Port 8000 unbound", "expect": "trigger" },
7
+ { "id": "t03", "prompt": "The site is throwing a 502, check the VM service", "expect": "trigger" },
8
+ { "id": "t04", "prompt": "Restart the adia-ui service on the exe.dev VM", "expect": "trigger" },
9
+ { "id": "t05", "prompt": "Provision a fresh exe.dev VM for a new host", "expect": "trigger" },
10
+ { "id": "t06", "prompt": "Rotate the API keys on the production VM", "expect": "trigger" },
11
+ { "id": "t07", "prompt": "Push a site-v* tag to deploy the current build, review the dry-run delete summary first", "expect": "trigger" },
12
+ { "id": "t08", "prompt": "Did we deploy the site after the last lockstep cut, or is it behind npm?", "expect": "trigger" },
13
+ { "id": "t09", "prompt": "Roll back the last site deploy, the new build is broken", "expect": "trigger" },
14
+ { "id": "n01", "prompt": "Cut a release of the next version and publish the npm packages", "expect": "no-trigger", "owner": "adia-release" },
15
+ { "id": "n02", "prompt": "Verify that this consumer app screen renders correctly before shipping", "expect": "no-trigger", "owner": "adia-verify" },
16
+ { "id": "n03", "prompt": "Add a new prop to button-ui", "expect": "no-trigger", "owner": "adia-author" },
17
+ { "id": "n04", "prompt": "Run a dogfood sweep on the demo pages", "expect": "no-trigger", "owner": "adia-dogfood" },
18
+ { "id": "n05", "prompt": "Tune the zettel retrieval coverage, the eval dropped to 38%", "expect": "no-trigger", "owner": "adia-a2ui" },
19
+ { "id": "n06", "prompt": "Why does accordion-ui crash under SSR in Astro?", "expect": "no-trigger", "owner": "adia-ssr" },
20
+ { "id": "n07", "prompt": "Fix the streaming adapter bug in the @adia-ai/llm package", "expect": "no-trigger", "owner": "adia-llm-internals" }
21
+ ]
22
+ }