@adia-ai/adia-ui-forge 0.8.5 → 0.8.7

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 (58) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +13 -4
  4. package/agents/a2ui-builder.corpus.json +35 -0
  5. package/agents/a2ui-builder.md +37 -0
  6. package/agents/component-author.corpus.json +40 -0
  7. package/agents/component-author.md +10 -1
  8. package/agents/framework-reviewer.corpus.json +35 -0
  9. package/agents/{framework-verifier.md → framework-reviewer.md} +16 -7
  10. package/agents/release-builder.corpus.json +39 -0
  11. package/agents/release-builder.md +39 -0
  12. package/agents/routing-corpus.json +39 -39
  13. package/bin/sidecar-prewrite-guard +17 -0
  14. package/bin/site-postwrite-derivation-gate +180 -0
  15. package/commands/release.md +5 -3
  16. package/hooks/hooks.json +4 -0
  17. package/package.json +1 -1
  18. package/references/contracts/a2ui-mcp-surface.md +1 -1
  19. package/skills/adia-a2ui/SKILL.md +27 -6
  20. package/skills/adia-a2ui/evals/routing-corpus.json +36 -29
  21. package/skills/adia-a2ui/references/zettel-calibration.md +5 -5
  22. package/skills/adia-author/SKILL.md +15 -8
  23. package/skills/adia-author/evals/routing-corpus.json +39 -218
  24. package/skills/adia-author/references/authoring-cycle.md +19 -0
  25. package/skills/adia-author/references/code-style.md +0 -1
  26. package/skills/adia-author/references/llm-bridge.md +7 -0
  27. package/skills/adia-author/references/worked-example.md +18 -2
  28. package/skills/adia-deploy/SKILL.md +33 -18
  29. package/skills/adia-deploy/evals/routing-corpus.json +33 -142
  30. package/skills/adia-dogfood/SKILL.md +11 -4
  31. package/skills/adia-dogfood/evals/routing-corpus.json +30 -142
  32. package/skills/adia-dogfood/references/admin-shell-anatomy.md +1 -1
  33. package/skills/adia-dogfood/references/visual-probe-triage.md +1 -5
  34. package/skills/adia-gen-review/SKILL.md +18 -7
  35. package/skills/adia-gen-review/evals/routing-corpus.json +30 -142
  36. package/skills/adia-gen-review/scripts/gen-review-decompose.mjs +5 -0
  37. package/skills/adia-llm-internals/SKILL.md +10 -6
  38. package/skills/adia-llm-internals/evals/routing-corpus.json +33 -142
  39. package/skills/adia-llm-internals/references/bridge-facade.md +2 -2
  40. package/skills/adia-llm-internals/references/streaming-sse.md +1 -1
  41. package/skills/adia-release/SKILL.md +40 -17
  42. package/skills/adia-release/evals/routing-corpus.json +35 -0
  43. package/skills/adia-release/references/changelog-discipline.md +14 -8
  44. package/skills/adia-release/references/cut-procedure.md +48 -28
  45. package/skills/adia-release/references/independent-package-release.md +1 -1
  46. package/skills/adia-release/scripts/insert-stub.mjs +1 -1
  47. package/skills/adia-release/scripts/release-pack.mjs +42 -14
  48. package/skills/adia-site-docs/SKILL.md +6 -1
  49. package/skills/adia-site-docs/evals/routing-corpus.json +35 -173
  50. package/skills/adia-ssr/SKILL.md +32 -14
  51. package/skills/adia-ssr/evals/routing-corpus.json +32 -136
  52. package/skills/adia-ssr/references/consumer-workarounds.md +33 -15
  53. package/skills/adia-ssr/references/failure-shapes.md +49 -7
  54. package/skills/adia-ssr/references/guard-patterns.md +41 -0
  55. package/skills/adia-ssr/references/status-ledger.md +5 -7
  56. package/skills/adia-ssr/references/test-without-linkedom.md +28 -12
  57. package/agents/a2ui-engineer.md +0 -26
  58. package/agents/release-engineer.md +0 -26
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python3
2
+ """site-postwrite-derivation-gate — PostToolUse check: site source edits name their stale derivatives.
3
+
4
+ The docs site renders converted routes from GENERATED artifacts: site/site.js
5
+ probes site-a2ui/pages/<slug>.a2ui.json per route and renders it via
6
+ <a2ui-root>.doc — the HTML fragment under site/pages/** is only the 404
7
+ fallback. An editor who changes the fragment and stops there has changed
8
+ NOTHING users see (shipped exactly that way 2026-07, caught only by manual
9
+ review). site/sitemap.json likewise feeds site/llms.txt and the patterns
10
+ index. This hook feeds the regeneration obligation back at write-time; the
11
+ hard gate is the repo-wide site-a2ui verify wired in CI.
12
+
13
+ Quiet on: fragments with no sitemap route, routes the ledger has not
14
+ converted (the fragment IS what renders), anything under site-a2ui/ and the
15
+ generated pages sidecar-prewrite-guard owns, and any internal error
16
+ (fail-open — this hook must never block editing with a crash).
17
+
18
+ Usage:
19
+ site-postwrite-derivation-gate --hook # PostToolUse mode: event JSON on stdin
20
+ site-postwrite-derivation-gate selftest # prove matcher + resolution on fixtures
21
+ """
22
+ import json
23
+ import sys
24
+
25
+ SITEMAP_MARKER = "site/sitemap.json"
26
+ FRAGMENT_MARKER = "site/pages/"
27
+
28
+ # Generated files under site/pages/ are sidecar-prewrite-guard territory.
29
+ GENERATED_EXCLUDE = ("site/pages/patterns/index.html",)
30
+
31
+
32
+ def classify(path):
33
+ """→ ("sitemap"|"fragment", repo-root prefix, "/"-rooted repo path) or (None, None, None)."""
34
+ if not path or "site-a2ui/" in path:
35
+ return None, None, None
36
+ if path.endswith(SITEMAP_MARKER):
37
+ return "sitemap", path[: -len(SITEMAP_MARKER)], "/" + SITEMAP_MARKER
38
+ idx = path.find(FRAGMENT_MARKER)
39
+ if idx == -1 or not path.endswith(".html") or path[idx:] in GENERATED_EXCLUDE:
40
+ return None, None, None
41
+ return "fragment", path[:idx], "/" + path[idx:]
42
+
43
+
44
+ def find_route(sitemap, rel):
45
+ """Walk sections/items for the entry whose `content` equals rel; → route path or None."""
46
+ stack = [sitemap.get("sections") or []]
47
+ while stack:
48
+ node = stack.pop()
49
+ if isinstance(node, list):
50
+ stack.extend(node)
51
+ elif isinstance(node, dict):
52
+ if node.get("content") == rel and node.get("path"):
53
+ return node["path"]
54
+ stack.extend(v for k, v in node.items() if k in ("sections", "items", "children"))
55
+ return None
56
+
57
+
58
+ def resolve_fragment(root, rel):
59
+ """→ feedback reason for a stale-artifact edit, or None to stay quiet.
60
+
61
+ Raises on I/O / parse trouble — the caller fail-opens.
62
+ """
63
+ with open(root + "site/sitemap.json", encoding="utf-8") as f:
64
+ route = find_route(json.load(f), rel)
65
+ if not route:
66
+ return None # not a routed page
67
+ with open(root + "site-a2ui/ledger.json", encoding="utf-8") as f:
68
+ rows = json.load(f).get("pages") or []
69
+ row = next((r for r in rows if r.get("route") == route), None)
70
+ if not row or row.get("status") != "converted":
71
+ return None # legacy-rendered: the fragment IS what users see
72
+ slug = row.get("slug") or route.lstrip("/").replace("/", "__")
73
+ return (
74
+ f"site-postwrite-derivation-gate · {rel} is the SOURCE for {route}, which renders "
75
+ f"from GENERATED site-a2ui/pages/{slug}.a2ui.json — the artifact is now stale and "
76
+ f"users still see the OLD content. Regenerate: `node scripts/build/site-a2ui.mjs "
77
+ f"--page {route}` (repo-wide check: `npm run verify:site-a2ui`)."
78
+ )
79
+
80
+
81
+ SITEMAP_REASON = (
82
+ "site-postwrite-derivation-gate · site/sitemap.json feeds GENERATED surfaces that are "
83
+ "now stale: site/llms.txt (`npm run build:llms`) and the patterns/templates index "
84
+ "(`npm run build:patterns-index`). If you changed routes or content paths, also verify "
85
+ "site-a2ui route coverage: `node scripts/build/site-a2ui.mjs --verify`."
86
+ )
87
+
88
+
89
+ def hook_mode():
90
+ try:
91
+ event = json.load(sys.stdin)
92
+ except Exception:
93
+ return 0
94
+ tool_input = event.get("tool_input") or {}
95
+ kind, root, rel = classify(tool_input.get("file_path") or "")
96
+ if not kind:
97
+ return 0
98
+ if kind == "sitemap":
99
+ print(json.dumps({"decision": "block", "reason": SITEMAP_REASON}))
100
+ return 0
101
+ try:
102
+ reason = resolve_fragment(root, rel)
103
+ except Exception:
104
+ return 0 # fail-open: never block editing on our own error
105
+ if reason:
106
+ print(json.dumps({"decision": "block", "reason": reason}))
107
+ return 0
108
+
109
+
110
+ def selftest():
111
+ import os
112
+ import tempfile
113
+
114
+ scope_cases = [
115
+ ("/repo/site/pages/architecture/ontology.html", "fragment"),
116
+ ("site/pages/guides/testing.html", "fragment"),
117
+ ("/repo/site/sitemap.json", "sitemap"),
118
+ ("/repo/site/pages/patterns/index.html", None), # generated: prewrite guard owns it
119
+ ("/repo/site-a2ui/pages/site__x__y.a2ui.json", None),
120
+ ("/repo/site-a2ui/ledger.json", None),
121
+ ("/repo/site/site.js", None),
122
+ ("/repo/site/pages/architecture/notes.txt", None),
123
+ ("/repo/apps/tasks/app/index.html", None),
124
+ ]
125
+ for path, expected in scope_cases:
126
+ if classify(path)[0] != expected:
127
+ print(f"selftest: FAIL scope {path} → {classify(path)[0]} expected {expected}")
128
+ return 1
129
+ with tempfile.TemporaryDirectory() as tmp:
130
+ root = tmp + os.sep
131
+ os.makedirs(root + "site")
132
+ os.makedirs(root + "site-a2ui")
133
+ with open(root + "site/sitemap.json", "w", encoding="utf-8") as f:
134
+ json.dump(
135
+ {
136
+ "sections": [
137
+ {
138
+ "items": [
139
+ {"path": "/site/a/one", "content": "/site/pages/a/one.html"},
140
+ {"path": "/site/a/two", "content": "/site/pages/a/two.html"},
141
+ ]
142
+ }
143
+ ]
144
+ },
145
+ f,
146
+ )
147
+ with open(root + "site-a2ui/ledger.json", "w", encoding="utf-8") as f:
148
+ json.dump(
149
+ {
150
+ "pages": [
151
+ {"route": "/site/a/one", "slug": "site__a__one", "status": "converted"},
152
+ {"route": "/site/a/two", "slug": "site__a__two", "status": "failed"},
153
+ ]
154
+ },
155
+ f,
156
+ )
157
+ resolve_cases = [
158
+ ("/site/pages/a/one.html", True), # converted → nudge
159
+ ("/site/pages/a/two.html", False), # ledger row not converted → quiet
160
+ ("/site/pages/a/three.html", False), # no sitemap entry → quiet
161
+ ]
162
+ for rel, should_fire in resolve_cases:
163
+ fired = resolve_fragment(root, rel) is not None
164
+ if fired != should_fire:
165
+ print(f"selftest: FAIL resolve {rel} fired={fired} expected={should_fire}")
166
+ return 1
167
+ if "site__a__one.a2ui.json" not in resolve_fragment(root, "/site/pages/a/one.html"):
168
+ print("selftest: FAIL reason does not name the stale artifact")
169
+ return 1
170
+ print("selftest: PASS")
171
+ return 0
172
+
173
+
174
+ if __name__ == "__main__":
175
+ if "selftest" in sys.argv:
176
+ sys.exit(selftest())
177
+ if "--hook" in sys.argv:
178
+ sys.exit(hook_mode())
179
+ print(__doc__)
180
+ sys.exit(0)
@@ -1,10 +1,12 @@
1
1
  ---
2
- description: Cut, tag, publish, and deploy an @adia-ai release (11-package lockstep — 9 npm libraries + 2 Claude Code plugins). Stops for sign-off before every irreversible step.
2
+ description: Cut, tag, publish, and deploy an @adia-ai release (11-package lockstep — 9 npm libraries + 2 Claude Code plugins). This invocation IS the authorization for the whole cycle; only gate failures stop it.
3
3
  argument-hint: "[version or package]"
4
4
  ---
5
5
 
6
6
  Run a release. **$ARGUMENTS**
7
7
 
8
8
  Invoke **`adia-release`** and run its cut procedure end-to-end: pre-flight
9
- gates → cut → tag → publish → deploy → notes, stopping for operator sign-off
10
- at each irreversible step. The skill owns the discipline; don't restate it here.
9
+ gates → cut → tag → publish → deploy → notes. This command's invocation is
10
+ the operator's single authorization for the entire cycle (§Authorization,
11
+ operator ruling 2026-07-17) — run inline, don't re-ask per step; stop only
12
+ on a gate failure. The skill owns the discipline; don't restate it here.
package/hooks/hooks.json CHANGED
@@ -32,6 +32,10 @@
32
32
  {
33
33
  "type": "command",
34
34
  "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/demo-postwrite-pattern-gate\" --hook"
35
+ },
36
+ {
37
+ "type": "command",
38
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/site-postwrite-derivation-gate\" --hook"
35
39
  }
36
40
  ]
37
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-forge",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
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",
@@ -26,7 +26,7 @@ frozen-unless-versioned:
26
26
  | Tool | Consumer use |
27
27
  |---|---|
28
28
  | `generate_ui`, `refine_ui` | gen-UI generation loop (adia-genui) |
29
- | `validate_schema`, `check_anti_patterns` | the trust gate on LLM-emitted A2UI (screen-composer) |
29
+ | `validate_schema`, `check_anti_patterns` | the trust gate on LLM-emitted A2UI (screen-builder) |
30
30
  | `search_chunks`, `lookup_component`, `get_component_map`, `get_traits` | catalog literacy (adia-compose — "the MCP is the live catalog, don't memorize names") |
31
31
  | `convert_html` | migration aid (adia-migrate) |
32
32
  | `server_status` | connectivity probe (adia-verify) |
@@ -1,11 +1,16 @@
1
1
  ---
2
2
  name: adia-a2ui
3
3
  description: >-
4
- Maintains the A2UI pipeline (packages/a2ui/): chunk corpus, compose
5
- strategies, calibration, evals, the a2ui MCP. Use when asked to author/fix
6
- chunks, tune STRONG_MATCH, lift eval fails, change MCP tools, run pipeline
7
- ops, or when a component's A2UI contract can't express a content shape.
8
- NOT for app screens (adia-compose).
4
+ Maintains the A2UI pipeline (packages/a2ui/): the harvested chunk corpus,
5
+ compose strategies (zettel, chunk-zettel, free-form, monolithic), retrieval,
6
+ validator, calibration, evals, the a2ui MCP server. Use when asked to
7
+ author/harvest/fix chunks, tune STRONG_MATCH or zettel thresholds, validate
8
+ an A2UI document, diagnose an eval gap/regression or lift a semantic fail,
9
+ add or change MCP tools (generate_ui, compose_from_chunks,
10
+ check_anti_patterns, refine_composition), scan anti-patterns, run pipeline
11
+ ops, or when a component's A2UI contract can't express a content shape. NOT
12
+ for app screens (adia-compose), runtime gen-UI app features (adia-genui),
13
+ primitive authoring (adia-author), or gallery scoring (adia-gen-review).
9
14
  disable-model-invocation: false
10
15
  user-invocable: true
11
16
  ---
@@ -73,7 +78,7 @@ Unmatched work defaults to pipeline-overview and re-classifies from there.
73
78
  Full structural gate after any pipeline change:
74
79
 
75
80
  ```bash
76
- node scripts/build/components.mjs --verify # "clean — N files up-to-date" (127 component dirs)
81
+ node scripts/build/components.mjs --verify # "clean — N files up-to-date" (the N is the gate; dir count drifts, don't pin it)
77
82
  npm run verify:traits # 100% coverage
78
83
  npm run smoke:engines
79
84
  npm run smoke:register-engine # 11/11
@@ -109,3 +114,19 @@ intent → retrieval (chunk / composition search)
109
114
  Every change touches exactly one stage; identify which before patching. History
110
115
  for any constant or decision lives in git and PR descriptions
111
116
  (`git log -S STRONG_MATCH_THRESHOLD -- packages/a2ui`).
117
+
118
+ ## Pipeline Change Record — the output contract
119
+
120
+ Every change reports:
121
+
122
+ | Field | Value |
123
+ | --- | --- |
124
+ | Stage touched | retrieval \| strategy engine (zettel/chunk-zettel/free-form/monolithic) \| composer \| validator \| MCP surface |
125
+ | Narrowest gate run | the specific check for the touched stage, + result |
126
+ | Full sequence | `npm run smoke:engines` + `npm run test:a2ui` result |
127
+ | Floors before → after | cov/avg/MRR (zettel) or cov/avg/F1 (free-form) or cov/avg (monolithic) |
128
+ | Re-baseline | no / yes — if yes, the PR that ratified the new floor |
129
+
130
+ Done when every row is filled and the cited gates are green. NOT done: a
131
+ floor number changed with no before/after comparison, or a threshold tweak
132
+ with no root-cause note for why the floor moved.
@@ -1,31 +1,38 @@
1
1
  {
2
- "skill": "adia-a2ui",
3
- "description": "Routing corpus — does a phrase route to adia-a2ui (the A2UI/gen-ui pipeline maintainer skill) or to a sibling/off-topic?",
4
- "minimums_per_spec": {
5
- "trigger_phrases": 10,
6
- "adversarial_phrases": 5
7
- },
8
- "phrases": [
9
- { "id": "t1", "phrase": "validate this A2UI document", "should_route_to_a2ui": true },
10
- { "id": "t2", "phrase": "harvest a chunk from this HTML demo", "should_route_to_a2ui": true },
11
- { "id": "t3", "phrase": "zettel coverage dropped after the last change", "should_route_to_a2ui": true },
12
- { "id": "t4", "phrase": "should this repeated subtree become its own chunk", "should_route_to_a2ui": true },
13
- { "id": "t5", "phrase": "tune the STRONG_MATCH threshold", "should_route_to_a2ui": true },
14
- { "id": "t6", "phrase": "run check_anti_patterns on this rendered HTML", "should_route_to_a2ui": true },
15
- { "id": "t7", "phrase": "refine composition with an OAuth row", "should_route_to_a2ui": true },
16
- { "id": "t8", "phrase": "MRR dropped in the chunk retrieval eval", "should_route_to_a2ui": true },
17
- { "id": "t9", "phrase": "add an MCP tool to the a2ui server", "should_route_to_a2ui": true },
18
- { "id": "t10", "phrase": "audit the training data corpus for drift", "should_route_to_a2ui": true },
19
- { "id": "t11", "phrase": "diagnose this eval gap and regression", "should_route_to_a2ui": true },
20
- { "id": "t12", "phrase": "run the MCP pipeline: generate_ui then validate_schema", "should_route_to_a2ui": true },
21
- { "id": "t13", "phrase": "lift a semantic fail under sixty", "should_route_to_a2ui": true },
22
- { "id": "t14", "phrase": "why did the composer emit composition-match instead of composition-synthesized", "should_route_to_a2ui": true },
23
- { "id": "a1", "phrase": "build a settings page from existing primitives", "should_route_to_a2ui": false, "expected_alternative": "adia-author" },
24
- { "id": "a2", "phrase": "add a slot to button-ui and update its yaml contract", "should_route_to_a2ui": false, "expected_alternative": "adia-author" },
25
- { "id": "a3", "phrase": "cut a release and bump the version tag", "should_route_to_a2ui": false, "expected_alternative": "adia-release" },
26
- { "id": "a4", "phrase": "score the generated UI quality in apps/genui", "should_route_to_a2ui": false, "expected_alternative": "adia-gen-review" },
27
- { "id": "a5", "phrase": "run a broad visual QA sweep across site and playgrounds", "should_route_to_a2ui": false, "expected_alternative": "adia-dogfood" },
28
- { "id": "a6", "phrase": "fix the @adia-ai/llm SSE adapter", "should_route_to_a2ui": false, "expected_alternative": "adia-llm" },
29
- { "id": "a7", "phrase": "explain how React state management works", "should_route_to_a2ui": false, "expected_alternative": "off-topic" }
30
- ]
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"
17
+ ],
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": {
31
+ "as_of": "2026-07-18",
32
+ "scorer": "routing_eval.py (nonoun-plugins/forge)",
33
+ "f1": 0.783,
34
+ "precision": 1.0,
35
+ "recall": 0.643,
36
+ "exit_code": 0
37
+ }
31
38
  }
@@ -8,7 +8,7 @@ is calibrated against the held-out intent set or production telemetry.
8
8
 
9
9
  ## `STRONG_MATCH_THRESHOLD = 40`
10
10
 
11
- - **File**: `packages/a2ui/compose/strategies/zettel/generator-adapter.js:89`
11
+ - **File**: `packages/a2ui/compose/strategies/zettel/generator-adapter.js` (`grep -n STRONG_MATCH_THRESHOLD`)
12
12
  - **Raised**: 22 → 40 post-incident.
13
13
  - **Reason**: at 22, login-form / signup-form played verbatim too often →
14
14
  repetitive output. At 40, only near-perfect retrievals (chart-dashboard=48,
@@ -29,7 +29,7 @@ is calibrated against the held-out intent set or production telemetry.
29
29
 
30
30
  ## `STRONG_RETRIEVAL_SCORE = 8`
31
31
 
32
- - **File**: `chunk-synthesizer.js:31`
32
+ - **File**: `chunk-synthesizer.js` (`grep -n STRONG_RETRIEVAL_SCORE`)
33
33
  - **Scale**: corpus-size-**independent** absolute keyword score from
34
34
  `chunk-library.js#keywordScore()`: first name-word matches a token **+10**,
35
35
  full-query substring **+5**, whole-word token in name **+3**, substring /
@@ -46,7 +46,7 @@ is calibrated against the held-out intent set or production telemetry.
46
46
 
47
47
  ## `PRE_SEARCH_LIMIT = 30`
48
48
 
49
- - **Files**: `chunk-synthesizer.js:32`, `chunk-refiner.js:32`
49
+ - **Files**: `chunk-synthesizer.js` + `chunk-refiner.js` (`grep -n PRE_SEARCH_LIMIT`)
50
50
  - **Reason**: token-budget mitigation — pre-filter the catalog before the LLM
51
51
  sees it; the full catalog per prompt would burn tens of thousands of tokens.
52
52
  - **Synthesizer**: kind-aware allocation —
@@ -61,7 +61,7 @@ is calibrated against the held-out intent set or production telemetry.
61
61
 
62
62
  ## `SCOPE_DRIFT_RATIO = 1.5` + `SCOPE_DRIFT_MIN_ACTUAL = 20`
63
63
 
64
- - **File**: `chunk-synthesizer.js:38-39` (exported)
64
+ - **File**: `chunk-synthesizer.js` (exported; `grep -n SCOPE_DRIFT`)
65
65
  - Composed envelope's component count > 1.5× the sum of bound chunks' counts
66
66
  auto-fires a `scope-drift` issue — catches LLM creative expansion that
67
67
  hallucinates components beyond the bound chunks.
@@ -70,7 +70,7 @@ is calibrated against the held-out intent set or production telemetry.
70
70
 
71
71
  ## `DEFAULT_MAX_ATTEMPTS = 2`
72
72
 
73
- - **Files**: `chunk-refiner.js:31`, `chunk-synthesizer.js:33`
73
+ - **Files**: `chunk-refiner.js` + `chunk-synthesizer.js` (`grep -n DEFAULT_MAX_ATTEMPTS`)
74
74
  - Validator-driven retry budget. After 2 failed validations the engine emits
75
75
  `synthesis-failed`.
76
76
 
@@ -1,11 +1,18 @@
1
1
  ---
2
2
  name: adia-author
3
3
  description: >-
4
- Author or modify code inside the adia-ui monorepo — primitives, shells,
5
- demos, component yaml SoTs, the @adia-ai/llm bridge. Use when asked to add
6
- or edit a primitive, prop, slot, shell, or component CSS, promote inline
7
- UI to a module, or author a demo. NOT for composing app screens from
8
- primitives (adia-compose) or pipeline internals (adia-a2ui).
4
+ Author or modify AdiaUI framework source inside the monorepo — primitives
5
+ (packages/web-components), shells/composites (packages/web-modules), yaml
6
+ SoTs, demos. Use when asked to add a new primitive component, add or fix a prop/slot/
7
+ attribute/CSS variant, update a component's yaml, build or fix a shell
8
+ (chat-shell, admin-shell, editor-shell sidebar/pane/bespoke-tier
9
+ composition), promote or extract repeated inline content into a shared
10
+ module, audit a component's four-axis contract/token usage/lifecycle
11
+ (connected/disconnected symmetry) for drift, or author/write a demo or
12
+ examples.html for a component or composite. NOT for composing app screens
13
+ from primitives (adia-compose), A2UI pipeline internals (adia-a2ui),
14
+ @adia-ai/llm adapter/streaming/bridge internals (adia-llm-internals), or
15
+ site/pages docs pages (adia-site-docs).
9
16
  disable-model-invocation: false
10
17
  user-invocable: true
11
18
  ---
@@ -14,7 +21,9 @@ user-invocable: true
14
21
 
15
22
  Guard rails for code that lands INSIDE the adia-ui monorepo: primitives
16
23
  (`packages/web-components/`), shells and composites (`packages/web-modules/`),
17
- their `<name>.yaml` SoTs, the `@adia-ai/llm` bridge, and composite demos.
24
+ their `<name>.yaml` SoTs, and composite demos. `@adia-ai/llm` internals
25
+ (adapters, streaming, the bridge) are `adia-llm-internals`'s charter, not
26
+ this skill's — route there.
18
27
  Light-DOM is load-bearing: `slot=` attributes are decorative metadata,
19
28
  positioning is CSS by tag + ancestor + DOM order — never `::slotted()`,
20
29
  `::part()`, or shadow DOM. `.claude/docs/specs/component-token-contract.md`
@@ -30,7 +39,6 @@ wins any tie with this skill. Monorepo source read while authoring (yaml, CSS,
30
39
  | Shell / bespoke cluster child (`<admin-*>` `<chat-*>` `<editor-*>` `<simple-*>`) | [shell-patterns.md](references/shell-patterns.md) |
31
40
  | Promote repeated inline UI → shared module | [module-promotion.md](references/module-promotion.md) |
32
41
  | Contract / token / lifecycle drift audit on an existing component | [token-contract.md](references/token-contract.md) + [anti-patterns.md](references/anti-patterns.md) |
33
- | Extend `@adia-ai/llm` (provider, streaming, proxy) | [llm-bridge.md](references/llm-bridge.md) |
34
42
  | Demo for a composite/module — any `packages/web-modules/**/*.{examples,contents}.html` | [composite-demo-protocol.md](references/composite-demo-protocol.md) — NOT the primitive or promotion paths; they lack the canonical-survey discipline |
35
43
  | Convention question ("is this idiomatic?") | [code-style.md](references/code-style.md) — cite the rule, don't expand it inline |
36
44
 
@@ -82,7 +90,6 @@ citation mechanically on every web-modules demo write; the
82
90
  | Shell | render `packages/web-modules/<cluster>/<name>/<name>.html`; `node scripts/dev/audit-native-primitive-leak.mjs --include=<surface>`; `node scripts/dev/audit-shell-composition.mjs --include=<surface>` for `<admin-shell>` composites |
83
91
  | Inline → module promotion | source page renders identically post-refactor (visual sweep + DOM diff) + native-primitive-leak audit on the touched surface |
84
92
  | Drift audit | the findings report itself; gates run once a fix is applied |
85
- | LLM-bridge extension | a real client round-trip parses + returns (`npm run check:lockstep` + `npm run smoke:engines`) |
86
93
  | Composite demo | `npm run audit:demo-pattern-source:strict` + `npm run qa:design-coherence:strict` + (8b) `npm run qa:rendered-dom:emit -- --slug=<slug>` |
87
94
 
88
95
  Full structural-gate sequence after any primitive / shell / promotion work: