@adia-ai/adia-ui-forge 0.1.3 → 0.8.1

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 (259) hide show
  1. package/.claude-plugin/plugin.json +4 -7
  2. package/CHANGELOG.md +35 -34
  3. package/README.md +35 -40
  4. package/agents/a2ui-engineer.md +22 -53
  5. package/agents/component-author.md +29 -0
  6. package/agents/framework-verifier.md +26 -0
  7. package/agents/release-engineer.md +21 -81
  8. package/agents/routing-corpus.json +293 -64
  9. package/bin/demo-postwrite-pattern-gate +94 -0
  10. package/bin/forge-lint +17 -2
  11. package/bin/sidecar-prewrite-guard +104 -0
  12. package/commands/deploy.md +9 -0
  13. package/commands/dogfood.md +10 -0
  14. package/commands/gen-review.md +9 -0
  15. package/commands/release.md +10 -0
  16. package/hooks/hooks.json +15 -0
  17. package/package.json +3 -6
  18. package/references/contracts/a2ui-mcp-surface.md +35 -0
  19. package/references/contracts/migration-guide-format.md +34 -0
  20. package/references/shared/content-trust.md +19 -74
  21. package/skills/adia-a2ui/SKILL.md +99 -0
  22. package/skills/{adia-ui-a2ui → adia-a2ui}/evals/routing-corpus.json +10 -10
  23. package/skills/adia-a2ui/references/anti-patterns.md +27 -0
  24. package/skills/adia-a2ui/references/chunk-authoring.md +71 -0
  25. package/skills/adia-a2ui/references/corpus-discipline.md +68 -0
  26. package/skills/adia-a2ui/references/eval-diagnostics.md +86 -0
  27. package/skills/adia-a2ui/references/format-extension-decisions.md +66 -0
  28. package/skills/adia-a2ui/references/leverage-rules.md +52 -0
  29. package/skills/adia-a2ui/references/mcp-pipeline-ops.md +83 -0
  30. package/skills/adia-a2ui/references/mcp-tool-reference.md +59 -0
  31. package/skills/adia-a2ui/references/pipeline-overview.md +115 -0
  32. package/skills/adia-a2ui/references/semantic-fail-lifting.md +74 -0
  33. package/skills/adia-a2ui/references/strategy-engines.md +109 -0
  34. package/skills/adia-a2ui/references/zettel-calibration.md +104 -0
  35. package/skills/adia-author/SKILL.md +112 -0
  36. package/skills/adia-author/evals/routing-corpus.json +222 -0
  37. package/skills/{adia-ui-authoring → adia-author}/references/anti-patterns.md +33 -4
  38. package/skills/{adia-ui-authoring → adia-author}/references/authoring-cycle.md +9 -11
  39. package/skills/adia-author/references/canonical-pattern-index.md +243 -0
  40. package/skills/{adia-ui-authoring → adia-author}/references/code-style.md +19 -21
  41. package/skills/adia-author/references/common-gotchas.md +129 -0
  42. package/skills/adia-author/references/composite-demo-protocol.md +271 -0
  43. package/skills/{adia-ui-authoring → adia-author}/references/css-patterns.md +19 -6
  44. package/skills/{adia-ui-authoring → adia-author}/references/lifecycle-patterns.md +1 -0
  45. package/skills/{adia-ui-authoring → adia-author}/references/llm-bridge.md +3 -5
  46. package/skills/{adia-ui-authoring → adia-author}/references/module-promotion.md +20 -38
  47. package/skills/{adia-ui-authoring → adia-author}/references/primitive-audit.md +2 -4
  48. package/skills/{adia-ui-authoring → adia-author}/references/shell-patterns.md +12 -18
  49. package/skills/{adia-ui-authoring → adia-author}/references/token-contract.md +5 -7
  50. package/skills/{adia-ui-authoring → adia-author}/references/worked-example.md +3 -3
  51. package/skills/{adia-ui-authoring → adia-author}/references/yaml-contract.md +3 -3
  52. package/skills/{adia-ui-authoring → adia-author}/scripts/build-canonical-pattern-index.mjs +3 -3
  53. package/skills/adia-deploy/SKILL.md +128 -0
  54. package/skills/{adia-ui-ops → adia-deploy}/references/deploy-playbooks.md +47 -30
  55. package/skills/adia-dogfood/SKILL.md +124 -0
  56. package/skills/adia-dogfood/references/admin-shell-anatomy.md +77 -0
  57. package/skills/adia-dogfood/references/app-shell-pitfalls.md +66 -0
  58. package/skills/adia-dogfood/references/card-anatomy-sweep.md +66 -0
  59. package/skills/adia-dogfood/references/html-attr-sweep.md +63 -0
  60. package/skills/adia-dogfood/references/native-leak-annotations.md +73 -0
  61. package/skills/adia-dogfood/references/visual-probe-triage.md +80 -0
  62. package/skills/{adia-ui-dogfood → adia-dogfood}/scripts/analyze.mjs +30 -14
  63. package/skills/adia-gen-review/SKILL.md +127 -0
  64. package/skills/adia-gen-review/references/corpus-html-patterns.md +279 -0
  65. package/skills/adia-gen-review/references/loop-protocol.md +216 -0
  66. package/skills/adia-gen-review/references/rubric-cosmetic.md +100 -0
  67. package/skills/adia-gen-review/references/rubric-decompose.md +101 -0
  68. package/skills/adia-gen-review/references/rubric-score.md +214 -0
  69. package/skills/{adia-ui-gen-review → adia-gen-review}/references/scores.schema.json +2 -2
  70. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-coverage-audit.mjs +4 -4
  71. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-decompose.mjs +10 -6
  72. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-status.mjs +5 -5
  73. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/validate-cycle-scores.mjs +5 -5
  74. package/skills/adia-llm-internals/SKILL.md +77 -0
  75. package/skills/{adia-ui-llm → adia-llm-internals}/references/adapter-contract.md +4 -2
  76. package/skills/{adia-ui-llm → adia-llm-internals}/references/add-a-provider.md +4 -5
  77. package/skills/{adia-ui-llm → adia-llm-internals}/references/bridge-facade.md +10 -3
  78. package/skills/{adia-ui-llm → adia-llm-internals}/references/browser-proxy-boundary.md +1 -1
  79. package/skills/{adia-ui-llm → adia-llm-internals}/references/model-registry.md +5 -3
  80. package/skills/{adia-ui-llm → adia-llm-internals}/references/streaming-sse.md +2 -2
  81. package/skills/adia-release/SKILL.md +72 -0
  82. package/skills/adia-release/references/changelog-discipline.md +119 -0
  83. package/skills/adia-release/references/cut-procedure.md +247 -0
  84. package/skills/adia-release/references/gates-catalog.md +222 -0
  85. package/skills/adia-release/references/independent-package-release.md +52 -0
  86. package/skills/adia-release/references/migration-guide-authoring.md +86 -0
  87. package/skills/adia-release/references/notes-authoring.md +90 -0
  88. package/skills/adia-release/references/recovery-paths.md +106 -0
  89. package/skills/{adia-ui-release → adia-release}/scripts/bump.mjs +28 -3
  90. package/skills/{adia-ui-release → adia-release}/scripts/dispatch-publish.mjs +10 -7
  91. package/skills/{adia-ui-release → adia-release}/scripts/insert-stub.mjs +1 -1
  92. package/skills/{adia-ui-release → adia-release}/scripts/package-paths.mjs +6 -0
  93. package/skills/{adia-ui-release → adia-release}/scripts/promote-unreleased.mjs +1 -1
  94. package/skills/{adia-ui-release → adia-release}/scripts/release-pack.mjs +38 -31
  95. package/skills/{adia-ui-release → adia-release}/scripts/tag-lockstep.mjs +7 -3
  96. package/skills/adia-site-docs/SKILL.md +68 -0
  97. package/skills/adia-site-docs/evals/audit-report.md +30 -0
  98. package/skills/adia-site-docs/evals/routing-corpus.json +176 -0
  99. package/skills/adia-site-docs/intent.md +72 -0
  100. package/agents/README.md +0 -209
  101. package/agents/author.md +0 -56
  102. package/agents/repo-steward.md +0 -56
  103. package/agents/spec-architect.md +0 -53
  104. package/agents/tech-lead.md +0 -57
  105. package/agents/verifier.md +0 -55
  106. package/bin/lib/audit-axes.mjs +0 -555
  107. package/bin/lib/dry-run-irreversible.mjs +0 -236
  108. package/bin/lib/run-skill-evals.mjs +0 -487
  109. package/bin/lib/teach-router.mjs +0 -250
  110. package/commands/adia-forge-a2ui.md +0 -10
  111. package/commands/adia-forge-author.md +0 -10
  112. package/commands/adia-forge-dogfood.md +0 -8
  113. package/commands/adia-forge-llm.md +0 -8
  114. package/commands/adia-forge-orient.md +0 -10
  115. package/commands/adia-forge-release.md +0 -8
  116. package/commands/adia-forge-review.md +0 -10
  117. package/references/shared/pev-rationale.md +0 -64
  118. package/references/shared/skill-conventions.md +0 -133
  119. package/skills/adia-ui-a2ui/CHANGELOG.md +0 -32
  120. package/skills/adia-ui-a2ui/SKILL.md +0 -243
  121. package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +0 -75
  122. package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +0 -100
  123. package/skills/adia-ui-a2ui/references/anti-patterns.md +0 -24
  124. package/skills/adia-ui-a2ui/references/chunk-authoring.md +0 -88
  125. package/skills/adia-ui-a2ui/references/corpus-discipline.md +0 -56
  126. package/skills/adia-ui-a2ui/references/eval-diagnostics.md +0 -127
  127. package/skills/adia-ui-a2ui/references/fragment-graph.md +0 -91
  128. package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +0 -106
  129. package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +0 -398
  130. package/skills/adia-ui-a2ui/references/pipeline-overview.md +0 -175
  131. package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +0 -120
  132. package/skills/adia-ui-a2ui/references/strategy-engines.md +0 -111
  133. package/skills/adia-ui-a2ui/references/teach-protocol.md +0 -220
  134. package/skills/adia-ui-a2ui/references/zettel-calibration.md +0 -93
  135. package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +0 -96
  136. package/skills/adia-ui-a2ui/scripts/teach-route.mjs +0 -157
  137. package/skills/adia-ui-a2ui/skill.json +0 -38
  138. package/skills/adia-ui-authoring/CHANGELOG.md +0 -32
  139. package/skills/adia-ui-authoring/SKILL.md +0 -256
  140. package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +0 -101
  141. package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +0 -109
  142. package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +0 -113
  143. package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +0 -138
  144. package/skills/adia-ui-authoring/evals/routing-corpus.json +0 -245
  145. package/skills/adia-ui-authoring/references/canonical-pattern-index.md +0 -179
  146. package/skills/adia-ui-authoring/references/common-gotchas.md +0 -93
  147. package/skills/adia-ui-authoring/references/composite-demo-protocol.md +0 -1084
  148. package/skills/adia-ui-authoring/references/teach-protocol.md +0 -428
  149. package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +0 -148
  150. package/skills/adia-ui-authoring/skill.json +0 -45
  151. package/skills/adia-ui-dogfood/CHANGELOG.md +0 -17
  152. package/skills/adia-ui-dogfood/README.md +0 -62
  153. package/skills/adia-ui-dogfood/SKILL.md +0 -866
  154. package/skills/adia-ui-dogfood/skill.json +0 -40
  155. package/skills/adia-ui-forge/SKILL.md +0 -88
  156. package/skills/adia-ui-forge/evals/routing-corpus.json +0 -30
  157. package/skills/adia-ui-gen-review/CHANGELOG.md +0 -108
  158. package/skills/adia-ui-gen-review/SKILL.md +0 -266
  159. package/skills/adia-ui-gen-review/references/loop-protocol.md +0 -712
  160. package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +0 -144
  161. package/skills/adia-ui-gen-review/references/rubric-decompose.md +0 -117
  162. package/skills/adia-ui-gen-review/references/rubric-score.md +0 -249
  163. package/skills/adia-ui-gen-review/references/teach-protocol.md +0 -214
  164. package/skills/adia-ui-gen-review/skill.json +0 -23
  165. package/skills/adia-ui-llm/CHANGELOG.md +0 -25
  166. package/skills/adia-ui-llm/SKILL.md +0 -165
  167. package/skills/adia-ui-llm/evals/adversarial-corpus.json +0 -75
  168. package/skills/adia-ui-llm/evals/routing-corpus.json +0 -30
  169. package/skills/adia-ui-llm/evals/teach-routing-cases.json +0 -73
  170. package/skills/adia-ui-llm/references/teach-protocol.md +0 -78
  171. package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +0 -93
  172. package/skills/adia-ui-llm/scripts/teach-route.mjs +0 -119
  173. package/skills/adia-ui-llm/skill.json +0 -33
  174. package/skills/adia-ui-ops/CHANGELOG.md +0 -291
  175. package/skills/adia-ui-ops/SKILL.md +0 -401
  176. package/skills/adia-ui-ops/references/INDEX.md +0 -158
  177. package/skills/adia-ui-ops/references/audit-cadence.md +0 -263
  178. package/skills/adia-ui-ops/references/audit-patterns/archive-link-sweep.md +0 -96
  179. package/skills/adia-ui-ops/references/audit-patterns/audit-history-ledger.md +0 -162
  180. package/skills/adia-ui-ops/references/audit-patterns/browser-bundle-node-imports.md +0 -154
  181. package/skills/adia-ui-ops/references/audit-patterns/changelog-unreleased-bloat.md +0 -75
  182. package/skills/adia-ui-ops/references/audit-patterns/coverage-gaps.md +0 -187
  183. package/skills/adia-ui-ops/references/audit-patterns/entry-file-coverage.md +0 -122
  184. package/skills/adia-ui-ops/references/audit-patterns/format-hygiene.md +0 -217
  185. package/skills/adia-ui-ops/references/audit-patterns/lockstep-versioning.md +0 -113
  186. package/skills/adia-ui-ops/references/audit-patterns/memory-fragmentation.md +0 -180
  187. package/skills/adia-ui-ops/references/audit-patterns/orphan-detection.md +0 -202
  188. package/skills/adia-ui-ops/references/audit-patterns/pointer-validation.md +0 -180
  189. package/skills/adia-ui-ops/references/audit-patterns/redundancy-detection.md +0 -210
  190. package/skills/adia-ui-ops/references/audit-patterns/spec-dating-sweep.md +0 -91
  191. package/skills/adia-ui-ops/references/audit-patterns/stale-content.md +0 -182
  192. package/skills/adia-ui-ops/references/audit-patterns/staleness-tooling.md +0 -156
  193. package/skills/adia-ui-ops/references/audit-patterns/token-waste-detection.md +0 -196
  194. package/skills/adia-ui-ops/references/doc-types/adr-pattern.md +0 -210
  195. package/skills/adia-ui-ops/references/doc-types/architecture-md.md +0 -190
  196. package/skills/adia-ui-ops/references/doc-types/changelog.md +0 -183
  197. package/skills/adia-ui-ops/references/doc-types/decisions-log.md +0 -146
  198. package/skills/adia-ui-ops/references/doc-types/plan-roadmap.md +0 -182
  199. package/skills/adia-ui-ops/references/doc-types/postmortem-pattern.md +0 -206
  200. package/skills/adia-ui-ops/references/genres/prose-and-writing.md +0 -149
  201. package/skills/adia-ui-ops/references/guidance/context-budget.md +0 -137
  202. package/skills/adia-ui-ops/references/guidance/llm-doc-writing.md +0 -116
  203. package/skills/adia-ui-ops/references/guidance/reliability-dial.md +0 -186
  204. package/skills/adia-ui-ops/references/recipes/adr-introduction.md +0 -211
  205. package/skills/adia-ui-ops/references/recipes/audit-existing-repo.md +0 -234
  206. package/skills/adia-ui-ops/references/recipes/cold-start-harvest.md +0 -263
  207. package/skills/adia-ui-ops/references/recipes/concurrent-learnings-merge.md +0 -158
  208. package/skills/adia-ui-ops/references/recipes/continuous-learning-loop.md +0 -169
  209. package/skills/adia-ui-ops/references/recipes/external-reference-verification.md +0 -158
  210. package/skills/adia-ui-ops/references/recipes/findings-index-readout.md +0 -126
  211. package/skills/adia-ui-ops/references/recipes/greenfield-setup.md +0 -252
  212. package/skills/adia-ui-ops/references/recipes/harvest-repo-brain.md +0 -169
  213. package/skills/adia-ui-ops/references/recipes/import-repo-brain-harvest.md +0 -153
  214. package/skills/adia-ui-ops/references/recipes/memory-organization.md +0 -182
  215. package/skills/adia-ui-ops/references/recipes/recommend-then-validate.md +0 -199
  216. package/skills/adia-ui-ops/references/recipes/self-healing-hooks.md +0 -366
  217. package/skills/adia-ui-ops/references/recipes/skill-stewardship-loop.md +0 -113
  218. package/skills/adia-ui-ops/references/standards/agents-md-spec.md +0 -138
  219. package/skills/adia-ui-ops/references/standards/claude-md-convention.md +0 -123
  220. package/skills/adia-ui-ops/references/standards/cross-tool-matrix.md +0 -85
  221. package/skills/adia-ui-ops/references/standards/readme-conventions.md +0 -232
  222. package/skills/adia-ui-ops/references/teach-protocol.md +0 -215
  223. package/skills/adia-ui-ops/scripts/audit-ops-roster.mjs +0 -104
  224. package/skills/adia-ui-ops/skill.json +0 -65
  225. package/skills/adia-ui-release/CHANGELOG.md +0 -66
  226. package/skills/adia-ui-release/SKILL.md +0 -323
  227. package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +0 -144
  228. package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +0 -155
  229. package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +0 -114
  230. package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +0 -139
  231. package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +0 -124
  232. package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +0 -125
  233. package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +0 -142
  234. package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +0 -97
  235. package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +0 -147
  236. package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +0 -22
  237. package/skills/adia-ui-release/evals/evals.json +0 -164
  238. package/skills/adia-ui-release/references/changelog-discipline.md +0 -250
  239. package/skills/adia-ui-release/references/cycle-happy-path.md +0 -520
  240. package/skills/adia-ui-release/references/exe-deploy.md +0 -149
  241. package/skills/adia-ui-release/references/gates-catalog.md +0 -778
  242. package/skills/adia-ui-release/references/independent-package-release.md +0 -129
  243. package/skills/adia-ui-release/references/ledger-discipline.md +0 -232
  244. package/skills/adia-ui-release/references/migration-guide-authoring.md +0 -174
  245. package/skills/adia-ui-release/references/multi-agent-baseline.md +0 -207
  246. package/skills/adia-ui-release/references/notes-authoring.md +0 -212
  247. package/skills/adia-ui-release/references/recovery-paths.md +0 -262
  248. package/skills/adia-ui-release/references/rollup-notes.md +0 -208
  249. package/skills/adia-ui-release/references/teach-protocol.md +0 -468
  250. package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +0 -196
  251. package/skills/adia-ui-release/scripts/make-ledger.mjs +0 -200
  252. package/skills/adia-ui-release/skill.json +0 -77
  253. package/skills/dogfood-sweep/CHANGELOG.md +0 -37
  254. package/skills/dogfood-sweep/README.md +0 -105
  255. package/skills/dogfood-sweep/SKILL.md +0 -1000
  256. package/skills/dogfood-sweep/analyze.mjs +0 -600
  257. package/skills/dogfood-sweep/skill.json +0 -31
  258. /package/skills/{adia-ui-authoring → adia-author}/references/api-contract.md +0 -0
  259. /package/skills/{adia-ui-release → adia-release}/scripts/assert-monorepo-root.mjs +0 -0
@@ -0,0 +1,86 @@
1
+ # Eval diagnostics — gap diagnosis + regression triage
2
+
3
+ **Diagnostics run before code changes — always.** The #1 anti-pattern is
4
+ "tweak and hope": changing a prompt or adding a chunk without knowing why the
5
+ score is low burns real-LLM eval runs and teaches nothing.
6
+
7
+ ## Phase 0 — author a stub-mode diagnostic (zero LLM cost)
8
+
9
+ For each failing intent, capture four signals:
10
+
11
+ 1. **Search ranking** — what `searchChunks()` returns for the intent query.
12
+ 2. **Composition output** — what the pipeline emitted (HTML or plan).
13
+ 3. **Tag inventory** — every custom-element-like tag in the emitted HTML.
14
+ 4. **Coverage delta** — expected_components vs found_components.
15
+
16
+ Template (runnable with `llmAdapter: null`):
17
+
18
+ ```js
19
+ async function diagnose(intent) {
20
+ const search = searchChunks(intent.intent, { limit: 10 });
21
+ const comp = await composeFromIntent({ intent: intent.intent, llmAdapter: null });
22
+ const tags = [...comp.html.matchAll(/<([a-z]+-[a-z-]+)[\s>]/gi)]
23
+ .map(m => m[1]).filter((v, i, a) => a.indexOf(v) === i);
24
+ const found = intent.expected_components.filter(tag =>
25
+ new RegExp(`<${kebab(tag)}-ui[\\s>]`).test(comp.html));
26
+ return { search, tags, found,
27
+ missing: intent.expected_components.filter(t => !found.includes(t)) };
28
+ }
29
+ ```
30
+
31
+ ## Phase 1 — classify failures
32
+
33
+ | Bucket | Symptom | Root cause | Cost |
34
+ | --- | --- | --- | --- |
35
+ | A. Holdout misalignment | Top-1 retrieved ≠ expected_chunk | Holdout drifted from corpus | minutes |
36
+ | B. Coverage gap | Chunk retrieved but HTML lacks expected tags | Chunk HTML doesn't contain those components | hours (new chunks) |
37
+ | C. Wrong shell | Retrieval OK, LLM picks wrong page shell | Prompt ambiguity / missing domain→shell mapping | hours (prompt tuning) |
38
+ | D. Broken render | HTML emitted but console errors / blank | Missing registrations or bad markup | hours (harvester bug) |
39
+ | E. Measurement bug | Output looks right, score low | Scorer regex/casing/substring bug | minutes |
40
+ | F. Embedding drift | Async top-1 ≠ sync top-1 | Cosine boosts flip rankings non-deterministically | minutes |
41
+
42
+ **Fix order: A → E → F → C → B → D.** Fix measurement before content (else
43
+ scores can't be trusted); fix determinism before adding content (else evals
44
+ fluctuate).
45
+
46
+ ## Phase 2 — fixes per bucket
47
+
48
+ - **A. Holdout alignment** — map each intent's `expected_chunk` to the actual
49
+ top-1; update `packages/a2ui/corpus/evals/holdout-compose-from-chunks.jsonl`.
50
+ - **E. Measurement traps** — PascalCase→kebab (`AgentTrace` → `agent-trace`,
51
+ not `agenttrace`); substring false positives (`pane` vs `panel`,
52
+ `textarea-ui` contains `text-ui` — word boundaries); case sensitivity (`/i`).
53
+ - **F. Embedding drift** — prefer sync keyword search for deterministic
54
+ fast-path tiers; keep async cosine for the synthesis tier only (embeddings
55
+ are a tie-breaker by design — see zettel-calibration).
56
+ - **C. Wrong shell** — check the `SYSTEM_PROMPT` domain→shell mapping in
57
+ `chunk-synthesizer.js`; add explicit examples for the failing domain and a
58
+ negative constraint ("NEVER default to dashboard-admin-page for
59
+ non-dashboard intents").
60
+ - **B. Coverage gap** — author a block chunk the HTML-first way
61
+ ([chunk-authoring](chunk-authoring.md)): demo page in a harvest root (e.g.
62
+ `catalog/ui-patterns/app/<name>/`), `data-chunk` + `data-chunk-kind="block"`
63
+ markers, real component tags so coverage scoring matches, then
64
+ `npm run harvest:chunks`.
65
+ - **D. Broken render** — `packages/a2ui/mcp/scripts/render-fidelity.mjs`
66
+ output (console errors, blank viewport, undefined elements); verify
67
+ registrations in `packages/web-components/index.js`; check the harvester
68
+ didn't strip `data-chunk-slot` from page shells.
69
+
70
+ ## Verification
71
+
72
+ ```bash
73
+ npm run eval:compose-from-chunks # stub first: fast, free
74
+ npm run eval:compose-from-chunks -- --real-llm --report-file # then real LLM
75
+ ```
76
+
77
+ Stop only when all intents pass and the average is stable across 3 runs, and
78
+ the SKILL.md floors hold.
79
+
80
+ ## The eval suite's dimensions
81
+
82
+ `packages/a2ui/mcp/scripts/test-evals.mjs` scores 5 weighted dimensions:
83
+ structural_validity 30% · intent_alignment 25% · component_coverage 20% ·
84
+ card_model_compliance 15% · anti_pattern_count 10%. `--save-baseline`
85
+ (`npm run test:evals:baseline`) stores scores; later runs flag any dimension
86
+ dropping >5 points or aggregate >3 (exit code 2 = regression).
@@ -0,0 +1,66 @@
1
+ # Format-extension decisions — when a component's contract can't express something
2
+
3
+ A component's A2UI JSON contract sometimes can't carry a content shape the
4
+ authored HTML has — a table cell with mixed prose and inline `<code>`, a
5
+ label needing an icon, a slot needing arbitrary nested markup. Read this
6
+ before extending any component's declarative contract to close a gap like
7
+ that; it doesn't cover corpus/chunk decisions (see
8
+ [leverage-rules](leverage-rules.md)) — it's about the component's own
9
+ prop/construct surface.
10
+
11
+ ## The three-tier ladder, in order of preference
12
+
13
+ 1. **Extend an existing declarative registry the component already has** —
14
+ e.g. `table-ui`'s `components/table/cell-types.js` (`badge`, `progress`,
15
+ `link`, …). Add a new named type; the component dispatches rendering
16
+ through the registry it already owns. **Smallest blast radius**: no new
17
+ A2UI construct, no runtime/validator changes, no registry entry in
18
+ `packages/a2ui/runtime/registry.js`. **Ceiling**: only covers formats the
19
+ registry's render contract can express (inline-safe content, not
20
+ arbitrary nested block markup). Building the new registry entry is a
21
+ web-components primitive edit — hand off to `adia-author` for the
22
+ implementation half; this reference only decides the tier.
23
+ 2. **New A2UI primitive(s)**, each slot/cell a normal construct subtree (any
24
+ registered component nestable inside it) — matches how `Column`/`Row`
25
+ already compose. **Most expressive** — no ceiling on what can nest.
26
+ **Largest blast radius**: new constructs need transpiler synthesis,
27
+ runtime rendering support, and validator rules; changes what the
28
+ containing component MEANS in the A2UI graph model. Reserve for cases
29
+ tier 1 genuinely can't reach.
30
+ 3. **Raw-HTML/markup passthrough**, wired through an existing visual-only
31
+ escape hatch (e.g. `table-ui[raw]`) registered as an A2UI construct
32
+ carrying sanitized markup as a string prop. **Fastest to ship** — reuses
33
+ infrastructure verbatim. **Weakest fit for a generative pipeline**: an
34
+ LLM composing pages would need to emit raw HTML strings instead of
35
+ constructs, undermining the JSON-graph value the A2UI format exists for.
36
+ Acceptable ONLY as a narrowly-scoped escape hatch (e.g. a docs-migration
37
+ pipeline), never as a pattern taught to the generation engines.
38
+
39
+ **Default to tier 1.** Climb to tier 2 or 3 only when a concrete case proves
40
+ tier 1's ceiling — don't pre-emptively build the more expressive, more
41
+ invasive tier for a gap tier 1 can still close.
42
+
43
+ ## Worked precedent — TKT-0008 (table-ui rich cells, 2026-07-13)
44
+
45
+ `table-ui`'s `{columns, data}` contract only carried plain-string cells;
46
+ docs reference tables with inline `<code>` in cells (e.g. `` `variant` `` in
47
+ a props table) fell back to a preserved-HTML `Code` block instead of a
48
+ `Table` component — the table never reached the A2UI graph. All three tiers
49
+ were scoped (rich-cell vocabulary / new `TableRow`/`TableCell` primitives /
50
+ raw-HTML passthrough via the existing `table-ui[raw]` prop); tier 1 was
51
+ ratified and built: a new `markdown` cell type in `cell-types.js`, rendered
52
+ via `core/markdown.js`'s `inline()` (exported for this reuse — the exact
53
+ client-side counterpart to the docs-transpiler's own `convertInline()`).
54
+ Measured result: the targeted failure class (`structural:tables` in the
55
+ strict re-verification sweep) dropped 39→7 pages out of 98 measured; the
56
+ residual 7 carry cells genuinely outside tier 1's reach (block content,
57
+ component tags) and are an open tier-2/3 follow-up
58
+ (`docs/tickets/TKT-0008-table-ui-cannot-express-rich-cells.md`).
59
+
60
+ ## Why this generalizes
61
+
62
+ The same ladder applies to any AdiaUI primitive with a per-item/per-cell
63
+ render dispatch (table columns, list-item variants, chart series formats,
64
+ …): check for an existing registry FIRST, size the ceiling honestly against
65
+ the concrete case at hand, and only pay the blast-radius cost of a new
66
+ construct or a raw-passthrough when the registry provably can't reach it.
@@ -0,0 +1,52 @@
1
+ # Leverage rules — when a repeated subtree earns its own corpus entry
2
+
3
+ Historical note first: the zettel **fragment mechanism is retired**
4
+ (`$fragment` refs now render as visible drift placeholders — see
5
+ `compose/strategies/zettel/composer.js`). The leverage discipline below
6
+ outlived the mechanism: it now governs whether a repeated subtree gets split
7
+ into its own `data-chunk` block vs staying inline in its parent chunk, and it
8
+ is the calibration for any future extraction tier.
9
+
10
+ ## The leverage rule
11
+
12
+ **Do not extract a reusable unit unless it has leverage ≥ 3** — at least 3
13
+ consumers would use it. Two exceptions:
14
+
15
+ 1. **Singleton closing a semantic gap** — a distinct domain primitive (e.g. a
16
+ keyboard-shortcut row) justifies extraction at leverage 1 because the
17
+ concept itself needs to be retrievable.
18
+ 2. **Intra-composition multi-use** — one composition instantiating the same
19
+ subtree N ≥ ~10 times justifies extraction; reuse is measured per instance,
20
+ not per referencing composition. Historical evidence: `calendar-day-cell`
21
+ used 35× inside one calendar composition lifted corpus reuse 26.4% → 33.5%
22
+ on its own.
23
+
24
+ Sub-leverage extraction bloats the corpus, slows retrieval, and adds
25
+ maintenance without improving reuse. Common candidates that DO clear the bar:
26
+ card headers, key-value rows, icon+text rows, labeled progress bars, stat
27
+ tiles, notification rows.
28
+
29
+ ## Keyword preservation (the extraction-drift lesson)
30
+
31
+ Extraction SHRINKS the parent's keyword surface: before, the parent contained
32
+ the subtree's text; after, it only references the child. Historically,
33
+ extracting a card-header from the login-form pattern dropped its retrieval
34
+ score 28 → 24 because "login / sign in / email password" tokens left with the
35
+ extract; explicitly re-adding those keywords to the parent restored 28.
36
+
37
+ **Rule: every parent that loses a subtree must be re-enriched with the
38
+ semantic tokens that left.** In today's corpus this means the parent chunk's
39
+ `data-chunk-keywords` (and re-harvest). Without it, retrieval degrades
40
+ silently.
41
+
42
+ ## Threshold discipline after extraction
43
+
44
+ If a known-good intent starts scoring below a retrieval threshold after a
45
+ corpus split, DO NOT lower the threshold. In order:
46
+
47
+ 1. Verify the parent's keywords were preserved (above).
48
+ 2. Check the new entry's name/description doesn't cannibalize the parent's
49
+ semantic space (retrieval collision — see
50
+ [semantic-fail-lifting](semantic-fail-lifting.md) Strategy B).
51
+ 3. Only then consider threshold work, with
52
+ [zettel-calibration](zettel-calibration.md) history read first.
@@ -0,0 +1,83 @@
1
+ # MCP pipeline operations — generate → validate → render → feedback
2
+
3
+ Operator workflows against the a2ui MCP server. Tool schemas + wrappers:
4
+ [mcp-tool-reference](mcp-tool-reference.md).
5
+
6
+ ## Full pipeline — one command
7
+
8
+ ```bash
9
+ node scripts/mcp-pipeline.cjs "dashboard with 4 stat cards and a revenue chart"
10
+ ```
11
+
12
+ Pipes `intent → generate_ui → validate_schema → a2ui-to-html →
13
+ check_anti_patterns` and prints the scores. Fastest whole-stack confirmation
14
+ after a change.
15
+
16
+ ## Step-by-step (inspect intermediates)
17
+
18
+ ```bash
19
+ node scripts/mcp-call.cjs generate_ui '{"intent":"dashboard with 4 stat cards","mode":"instant"}'
20
+ node scripts/mcp-call.cjs validate_schema '{"messages":"<paste-messages-json>"}'
21
+ echo '<paste-messages-json>' | node scripts/a2ui-to-html.cjs
22
+ node scripts/mcp-call.cjs check_anti_patterns '{"html":"<paste-rendered-html>"}'
23
+ ```
24
+
25
+ `validate_schema` is fast and deterministic — batch it over
26
+ `packages/a2ui/corpus/chunks/*.json` templates to surface corpus drift without
27
+ re-running the generator.
28
+
29
+ ## Compose from the chunk corpus
30
+
31
+ When the intent matches a known page-shape (auth flow, dashboard layout, error
32
+ shell), prefer `compose_from_chunks` over `generate_ui`:
33
+
34
+ ```bash
35
+ node scripts/mcp-call.cjs compose_from_chunks '{"intent":"sign-in card with email + password + OAuth"}'
36
+ ```
37
+
38
+ Tier 1 returns a matched chunk's HTML when the retrieval score ≥ 8; otherwise
39
+ the LLM picks a `{page, slot_bindings}` plan from a pre-filtered ~30-entry
40
+ catalog and the chunk composer materializes it, validating slot-name +
41
+ chunk-kind contracts. Returns `{state_id, html, plan, candidates}`.
42
+
43
+ ## Multi-turn refinement (state_id chain)
44
+
45
+ ```bash
46
+ # Turn 1 → returns state_id "abc123"
47
+ node scripts/mcp-call.cjs compose_from_chunks '{"intent":"sign-in card with email + password"}'
48
+ # Turn 2 → updateComponents messages + new state_id
49
+ node scripts/mcp-call.cjs refine_composition '{"state_id":"abc123","intent":"add OAuth row with Google + GitHub"}'
50
+ ```
51
+
52
+ Two-pass synthesis (locator → modifier), validator-driven retry
53
+ (`maxAttempts=2`). Each refinement chains through `parent_state_id`; walk
54
+ history with `get_state`. The state cache is in-memory and bounded — after an
55
+ MCP server restart, re-run `compose_from_chunks` for a fresh `state_id`.
56
+
57
+ ## Reporting issues
58
+
59
+ When the engine breaks expectations, fire `report_issue` with the most recent
60
+ `state_id` (reporter: `llm` for agent self-fire, `user` for a human request).
61
+ The record lands in the engine-internal telemetry store — scratch data for
62
+ diagnosis. Anything worth durable tracking (a recurring pattern, a fix
63
+ proposal) belongs in a GitHub issue or the PR description of the fixing
64
+ change.
65
+
66
+ ## Validation checks
67
+
68
+ `validate_schema` runs a weighted checklist (target aggregate ≥ 80). Common
69
+ failures when the corpus drifts: `hasRootComponent` (missing `id: "root"`),
70
+ `cardContentModel` (section without Column wrapper, or heading inside section
71
+ instead of header), `headingHierarchy` (skipped levels), `flatAdjacency`
72
+ (nested components instead of sibling id references). Full list + weights:
73
+ `packages/a2ui/mcp/TOOLS.md`.
74
+
75
+ ## Feedback loop
76
+
77
+ Score runs with `submit_feedback` keyed on the `executionId` from
78
+ `generate_ui`. The analyzer
79
+ (`packages/a2ui/retrieval/feedback/feedback-analyzer.js`) aggregates
80
+ `corpus/feedback/*.jsonl` into per-intent trends, promotion candidates
81
+ (≥95 score + ≥4 rating across 3+ runs → `npm run feedback:promote`), and the
82
+ gap registry (`packages/a2ui/corpus/gaps/registry.json`).
83
+ `npm run feedback:report` surfaces the current state.
@@ -0,0 +1,59 @@
1
+ # MCP tool reference — the a2ui server's tool surface
2
+
3
+ **Schema SoT is `packages/a2ui/mcp/TOOLS.md` (30 tools), generated alongside
4
+ `server.js` — read it for input/output shapes; never restate schemas here
5
+ (they drift).** Tools register in `packages/a2ui/mcp/server.js` +
6
+ `packages/a2ui/mcp/tools/{corpus,discovery,feedback,refine,synthesis,
7
+ validation,zettel}.js`. Any tool change updates TOOLS.md in the same commit.
8
+
9
+ ## Stability rule (load-bearing)
10
+
11
+ Changing an existing tool's input/output contract is a breaking change for
12
+ every external MCP client. The full producer-side rule — dry-run schema diff,
13
+ explicit operator proceed, `@adia-ai/a2ui-mcp` version bump, factory pin
14
+ update, and the consumer-load-bearing subset whose contracts are
15
+ frozen-unless-versioned — lives in
16
+ [../../../references/contracts/a2ui-mcp-surface.md](../../../references/contracts/a2ui-mcp-surface.md).
17
+ Adding tools is additive and safe; removing or renaming is breaking.
18
+
19
+ ## Tool map by job
20
+
21
+ | Group | Tools | Registered in |
22
+ | --- | --- | --- |
23
+ | Generation | `generate_ui`, `refine_ui` (monolithic repair) | `synthesis.js`, `refine.js` |
24
+ | Chunk synthesis + multi-turn | `compose_from_chunks`, `refine_composition`, `get_state`, `report_issue` | `synthesis.js` |
25
+ | Chunk retrieval | `search_chunks`, `get_chunk`, `lookup_chunk` | `corpus.js` |
26
+ | Catalog inspection | `lookup_component`, `get_component_map`, `get_traits`, `get_wiring_catalog`, `server_status` | `discovery.js` |
27
+ | Composition/zettel inspection | `search_patterns`, `get_fragment`, `get_composition`, `get_graph`, `resolve_composition`, `zettel_stats` | `zettel.js` |
28
+ | Intent + context | `classify_intent`, `assemble_context` | `discovery.js` |
29
+ | Validation + conversion | `validate_schema`, `check_anti_patterns`, `convert_html` | `validation.js` |
30
+ | Feedback + evaluation | `submit_feedback`, `get_quality_metrics`, `get_training_gaps`, `run_eval` | `feedback.js` |
31
+ | Authoring (write path) | `import_pattern` | `zettel.js` |
32
+
33
+ Selection heuristics:
34
+
35
+ - **Fresh creation from a known page-shape** → `compose_from_chunks`
36
+ (retrieval-first); generic/novel intent → `generate_ui`.
37
+ - **Modifying an existing surface** ("change", "add to", "remove") →
38
+ `refine_composition` with the prior `state_id` — never re-generate.
39
+ - **Catalog literacy** → `lookup_component` / `get_component_map`; the MCP is
40
+ the live catalog — don't memorize component names.
41
+ - **Trust gate on any LLM-emitted A2UI** → `validate_schema` then
42
+ `check_anti_patterns` on the rendered HTML.
43
+
44
+ ## Local wrappers (all verified in `scripts/`)
45
+
46
+ - `scripts/mcp-pipeline.cjs "<intent>"` — full pipeline one-shot with a
47
+ combined report.
48
+ - `scripts/mcp-call.cjs <tool> '<json-args>'` — single-tool call for stepping
49
+ through / inspecting intermediates.
50
+ - `scripts/a2ui-to-html.cjs [file|stdin]` — renders A2UI message arrays to
51
+ HTML between `validate_schema` and `check_anti_patterns`.
52
+
53
+ ## When adding a tool
54
+
55
+ 1. Register in the matching `mcp/tools/<group>.js` file (zod input schema +
56
+ description that names its trigger phrases and its non-goals).
57
+ 2. Update `TOOLS.md` in the same commit (generated with the server build —
58
+ `npm run build:mcp-server`).
59
+ 3. Verify: `npm run mcp:smoke`, then a real-client round-trip.
@@ -0,0 +1,115 @@
1
+ # Pipeline overview — generator + retrieval + engines (mode: modify pipeline internals)
2
+
3
+ All paths repo-relative. Specs worth reading before structural changes:
4
+ `.claude/docs/specs/a2ui-v0.9-catalog-guide.md` (protocol + catalog format),
5
+ `.claude/docs/specs/genui-multiturn-architecture.md` (state cache, refiner,
6
+ op format), `.claude/docs/specs/genui-chunk-marker.md` (chunk attributes),
7
+ `.claude/docs/conventions/gen-ui-pipeline.md` (harvester wiring + embedding
8
+ lifecycle), `.claude/docs/specs/package-architecture.md` (package relations).
9
+
10
+ ## Key files (verified 2026-07)
11
+
12
+ ### Engine orchestration
13
+
14
+ | File | Role |
15
+ | --- | --- |
16
+ | `packages/a2ui/compose/core/generator.js` | `generate_ui` orchestrator — instant / pro / thinking / stream modes; multi-turn via `executionId` |
17
+ | `packages/a2ui/compose/strategies/registry.js` | Engine registry — `registerEngine(name, factory)`. Reserved names: `monolithic`, `zettel`, `mcp`, `monolithic-*` |
18
+ | `packages/a2ui/compose/strategies/zettel/` | Zettel + chunk-zettel engines — see [strategy-engines](strategy-engines.md) for the per-file map |
19
+ | `packages/a2ui/compose/strategies/free-form-composer/` | Free-form engine (`index.js`, `system-prompt.js`, `transpile.js`) |
20
+ | `packages/a2ui/compose/strategies/_shared/chunk-loader.js` | Shared chunk loading for engines |
21
+ | `packages/a2ui/compose/shared/validate-and-repair.js` | Shared closed-loop validate→repair, adopted by every LLM-calling engine (thinking/pro fully; free-form validate-only) — see [strategy-engines](strategy-engines.md) §Closed-loop validation |
22
+ | `packages/a2ui/compose/transpiler/transpiler.js` | HTML → A2UI transpile pass (used by harvester + convert_html) |
23
+
24
+ ### Corpus + retrieval
25
+
26
+ | File | Role |
27
+ | --- | --- |
28
+ | `packages/a2ui/corpus/scripts/chunk-library.js` | Chunk catalog API — `getChunk()`, `searchChunks()` (keyword), `searchChunksAsync()` (keyword + cosine), `listChunksByKind()`, `lookupChunksByPrimary()`. Reads `corpus/chunks/` + `_index.json` |
29
+ | `packages/a2ui/compose/strategies/zettel/composition-library.js` | Composition loader + `searchAll()` scoring (normalizes harvested chunks to composition shape) |
30
+ | `scripts/build/harvest-chunks.mjs` | `[data-chunk]` boundary walker over `site/pages/`, `apps/`, `playgrounds/`, `catalog/` — writes `corpus/chunks/<name>.json` + `_index.json`. Run via `npm run harvest:chunks` |
31
+ | `packages/a2ui/retrieval/intent/intent-categorizer.js` | Free-text intent → UI-category taxonomy |
32
+ | `packages/a2ui/retrieval/feedback/feedback-analyzer.js` | Aggregates JSONL feedback (`corpus/feedback/*.jsonl`); promotion + gap candidates |
33
+ | `packages/a2ui/retrieval/feedback/gap-registry.js` | Persistent gap tracking → `packages/a2ui/corpus/gaps/registry.json` |
34
+ | `packages/a2ui/retrieval/anti-patterns.js` | The `check_anti_patterns` rule source |
35
+ | `packages/a2ui/compose/core/reference.js` | Thin wrappers over retrieval exports (`searchBlocks`, `searchBlocksSemantic`, …) |
36
+
37
+ ### LLM bridge + MCP
38
+
39
+ | File | Role |
40
+ | --- | --- |
41
+ | `packages/llm/llm-bridge.js` | `createAdapter()` — real LLM or stub fallback |
42
+ | `scripts/load-env.mjs` | Shared .env loader for Node scripts |
43
+ | `packages/a2ui/mcp/server.js` + `mcp/tools/*.js` | MCP stdio server + tool registrations — see [mcp-tool-reference](mcp-tool-reference.md) |
44
+
45
+ ## Critical rules
46
+
47
+ 1. **Relative imports in `packages/llm/*.js`** — never `@llm/` Vite aliases;
48
+ they don't resolve in Node and break published consumers.
49
+ 2. **`load-env.mjs` before any a2ui import in Node** — without it,
50
+ `createAdapter()` silently returns `StubLLMAdapter` (canned 6-component
51
+ card). Feedback or diagnosis on stub output is noise.
52
+ 3. **Metadata IS the search index.** Descriptions + keywords are what retrieval
53
+ matches. Enriching descriptions from structure (headings, labels, button
54
+ text) took meaningful-description rate 40% → 95%. When search degrades,
55
+ inspect chunk metadata before touching thresholds.
56
+ 4. **Instant-mode gate lives in `monolithic/generate-instant.js`** — words ≥3
57
+ chars pass; `GATE_STOPS` filters boilerplate. Grep the set before concluding
58
+ "the gate rejects valid intents".
59
+ 5. **A2UI describes LAYOUT, not behavior.** Generation emits component trees +
60
+ props + slot bindings; never JS or per-canvas CSS. Behavior delegates to
61
+ traits or pre-built apps. "Make the generator emit JS/CSS" is a won't-fix.
62
+ 6. **Renderer guards `textContent` against container wipe** —
63
+ `packages/a2ui/runtime/renderer.js` whitelists pure-text leaves
64
+ (`TEXT_TAG_OK`); everything else routes through the `text=` attribute so
65
+ slotted children survive. Preserve this when touching the renderer.
66
+ 7. **Registry ↔ catalog parity.** A component in the runtime registry but
67
+ missing from catalog schemas silently drops from generated compositions —
68
+ `npm run check:registry-catalog-coherence` guards it; run it after catalog
69
+ changes.
70
+ 8. **Multi-turn emits A2UI `updateComponents` messages, not new compositions.**
71
+ The chunk-refiner mutates the binding plan via four ops (`rebindSlot` /
72
+ `appendToSlot` / `removeFromSlot` / `replacePage`); state chains via
73
+ `parent_state_id`. Spec: `genui-multiturn-architecture.md`.
74
+ 9. **Issue telemetry goes through `ctx.issueAccumulator`** (suppressed when
75
+ `ctx.evalMode` is true so evals stay clean). New engine failure paths plumb
76
+ the accumulator; never write records to disk directly. Durable issue
77
+ tracking belongs in GitHub issues / PR descriptions, not the engine store.
78
+ 10. **A new LLM-calling engine adopts `validate-and-repair.js` as its final
79
+ stage** — full schema/catalog/anti-pattern conformance, orthogonal to
80
+ whatever narrower plan/grounding validation the engine already runs
81
+ (chunk-zettel's slot bindings, free-form's ingredient grounding). It
82
+ is NOT automatic: a raw-HTML-wrapper engine (chunk-zettel today, see
83
+ TKT-0009) gets zero value from it — check the engine's actual output
84
+ shape is a real component graph before wiring it in.
85
+ 11. **Escalation across engine tiers is the dispatcher's call, never the
86
+ engine's own** — `registry.js`'s adapter wrappers (not
87
+ `generate-instant.js`/`generate-pro.js` themselves) decide whether a
88
+ hard-fail escalates to a stronger tier, capped at one hop. See
89
+ `generateInstantAdapter`'s comment for the worked example.
90
+ 12. **`harvest-chunks.mjs` validates every templated chunk at admission
91
+ time** (validate-only, via the same shared module) — report-only by
92
+ default; `--strict` refuses to write on any invalid chunk but is NOT
93
+ the default for `npm run harvest:chunks` (TKT-0010: 27% of the corpus
94
+ currently fails, mostly a schema-generation gap around `data-*`/`span`
95
+ attributes, not corpus-content defects — see the ticket before
96
+ assuming a chunk is actually broken).
97
+
98
+ ## Test + run commands (all verified in root package.json)
99
+
100
+ ```bash
101
+ npm run test:a2ui # smoke checks, no LLM (22/22, +1 skipped OK)
102
+ npm run test:a2ui:full # + thinking mode (calls API)
103
+ npm run test:evals # 5-dimension quality evals (mcp/evals/evals.json); --save-baseline via test:evals:baseline
104
+ npm run generate "login form" # instant-mode CLI (mcp/scripts/generate.mjs)
105
+ npm run smoke:engines # all registered engines
106
+ npm run smoke:register-engine # in-process registration (11/11)
107
+ npm run eval:diff -- --engine zettel # floors in SKILL.md
108
+ npm run harvest:chunks # re-harvest corpus (dry: harvest:chunks:dry)
109
+ npm run smoke:chunks # stub-LLM chunk smoke (re-harvests as side effect!)
110
+ npm run eval:chunk-synthesis # hold-out intents against real LLM
111
+ npm run build:embeddings:chunks
112
+ npm run smoke:refine && npm run smoke:state-cache && npm run smoke:issues
113
+ npm run eval:refine-synthesis # multi-turn refinement quality
114
+ npm run feedback:report && npm run feedback:promote
115
+ ```
@@ -0,0 +1,74 @@
1
+ # Semantic fail lifting — sub-60 triage procedure
2
+
3
+ Use when `npm run eval:diff -- --engine zettel --semantic` reports intents
4
+ with `semanticScore < 60` (or <70 for the watch list): the judge says the
5
+ emitted UI doesn't match what was asked for.
6
+
7
+ ## The judge's three axes (`packages/a2ui/validator/semantic/index.js:32`)
8
+
9
+ - **dominantPattern** (weight 0.5) — does the root/primary component match the
10
+ intent type (chat, form, calendar, data-display, nav…)?
11
+ - **requiredCapabilities** (weight 0.35) — are the specific controls the
12
+ intent requires present?
13
+ - **forbiddenNoise** (weight 0.15) — are off-topic components prominent?
14
+
15
+ A sub-60 score almost always means dominantPattern scored < 40.
16
+
17
+ ## Triage
18
+
19
+ 1. Read the latest eval run's zettel report — rows with `semanticScore < 70`,
20
+ ascending.
21
+ 2. Per row, read `semanticAxes.dominantPattern.{expected, observed}` and
22
+ `semanticAxes.requiredCapabilities.missing`.
23
+ 3. Bucket each failure:
24
+ - **Thin composition** — the retrieved entry exists but is too sparse
25
+ (calendar with nav + weekday labels but no grid).
26
+ - **Wrong composition winning** — retrieval collision; another entry steals
27
+ the intent via keyword overlap.
28
+ - **No matching composition exists** — coverage gap; author a new one.
29
+
30
+ ## Fix strategies, in order of preference
31
+
32
+ ### A. Use a domain-specific primitive as the root
33
+
34
+ The judge weights root identity heavily: a Card wrapping 38 Badges + 43 Texts
35
+ reads as "data-display" even with a 7-column grid inside. Swapping to the
36
+ semantically correct primitive fixes it instantly. Historical lifts:
37
+ calendar → `CalendarPicker` root (32→65); chat → `Chat` with
38
+ `Text[role=user|assistant]` children (52→70+); command palette → `Command` >
39
+ `ActionItem` (42→70+). Check the live catalog before authoring children
40
+ (`lookup_component` / `get_component_map` MCP tools) — invented child
41
+ components (`ChatMessage`, `CommandItem`) score zero and trip
42
+ `noInventedComponents`.
43
+
44
+ ### B. Resolve retrieval collisions by keyword surgery — both sides
45
+
46
+ When an unrelated entry wins retrieval, don't just enrich the correct entry —
47
+ **strip the overlapping keywords from the losing entry too**. Historical
48
+ example: `empty-state` kept winning "error state with retry" (sem=32) even
49
+ after a dedicated error-state entry existed, until "error state" and "retry"
50
+ were removed from empty-state's keywords; then the right entry won at sem=91.
51
+
52
+ ### C. Author the missing coverage
53
+
54
+ Indicators: multiple intents fail pointing at the same wrong candidate, and no
55
+ existing entry's purpose matches `dominantPattern.expected`. Author it the
56
+ HTML-first way — a demo page with `data-chunk` markers, then
57
+ `npm run harvest:chunks` (see [chunk-authoring](chunk-authoring.md)). Put the
58
+ pattern's signature affordance as the dominant child (steps-timeline for a
59
+ wizard, textarea+richtext for an editor, accordion for settings) and give it a
60
+ rich keyword set (15–20 terms) with exact intent phrases and domain synonyms.
61
+
62
+ ## Verify loop
63
+
64
+ ```bash
65
+ node scripts/build/components.mjs --verify
66
+ npm run smoke:engines && npm run smoke:register-engine && npm run test:a2ui
67
+ node packages/a2ui/mcp/scripts/eval-diff.mjs --engine zettel --semantic
68
+ ```
69
+
70
+ The semantic judge is cached, content-hashed on
71
+ (rubricVersion, intent, a2ui-messages) — only changed generations re-judge.
72
+ Compare `avgSem` and the sub-60 list row by row; hold the zettel floors
73
+ (cov≥87, avg≥85, MRR≥0.94) and require `avgSem` ≥ baseline before calling a
74
+ lift done.
@@ -0,0 +1,109 @@
1
+ # Strategy engines — zettel file map, strategy labels, issue telemetry
2
+
3
+ ## File map (`packages/a2ui/compose/strategies/zettel/`, verified 2026-07)
4
+
5
+ ```text
6
+ generator-adapter.js ← zettel entry: retrieval → strong-match / chunk-synthesis bridge / atoms
7
+ generate.js ← thin wrapper for direct invocation
8
+ _smoke.js ← in-tree smoke (npm run zettel:smoke)
9
+ composition-library.js ← loads corpus/chunks/*.json, normalizes to composition shape, searchAll()
10
+ composer.js ← resolveComposition(): defensive copy + strip pass (see fragment note)
11
+ session-store.js ← multi-turn artifact tracking (in-memory analytics; no iteration branch)
12
+ chunk-synthesizer.js ← page-shell + slot-binding synthesis (chunk-corpus, 2-tier)
13
+ chunk-composer.js ← resolves a chunk plan into A2UI messages; slot/kind validation
14
+ chunk-refiner.js ← multi-turn refinement (locator → modifier two-pass)
15
+ state-cache.js ← bounded LRU keyed by state_id
16
+ issue-reporter.js ← runtime telemetry (see below)
17
+ ```
18
+
19
+ **Fragments are retired.** `fragment-library.js` / `synthesizer.js` no longer
20
+ exist; `composition-library.js` is the renamed successor and the harvested
21
+ chunk corpus is the only retrieval substrate. `composer.js` is a passthrough:
22
+ any lingering `$fragment` ref renders as a visible placeholder to surface
23
+ corpus drift. Never author new `$fragment` refs.
24
+
25
+ ## Two engines under one directory
26
+
27
+ - **`zettel`** (`generator-adapter.js`): `searchAll()` over compositions →
28
+ strong match emits verbatim; weak/no match bridges to chunk-synthesis when an
29
+ LLM adapter is present; no LLM → `fragment-candidates` (atoms for downstream
30
+ assembly).
31
+ - **`chunk-zettel`**: chunk-corpus synthesis + `chunk-refiner.js` for
32
+ history-aware iteration. The zettel session-iteration branch was retired —
33
+ turn≥2 on `zettel` takes the same path as turn 1 (fresh retrieval). True
34
+ modify-an-existing-canvas work goes through `chunk-zettel` + `state_id`.
35
+
36
+ Both register independently in `strategies/registry.js`.
37
+
38
+ ## Strategy labels (public contract — emitted to the eval harness)
39
+
40
+ | Label | Trigger | LLM call? |
41
+ | --- | --- | --- |
42
+ | `composition-match` | Fresh retrieval, `searchAll` score ≥ `STRONG_MATCH_THRESHOLD` (40) | No |
43
+ | `composition-synthesized` | Weak retrieval, chunk-synthesis bridge succeeded | Yes |
44
+ | `synthesis-failed` | LLM tried + failed validation | Yes (failed) |
45
+ | `fragment-candidates` | Weak retrieval + no LLM available → atoms only | No |
46
+
47
+ The eval harness scores per-label distribution; a calibration tweak that shifts
48
+ the distribution shifts the score. Don't rename labels without a coordinated
49
+ migration — eval, MCP tools, and dialog-recorder pattern-match on the strings.
50
+
51
+ ## Issue reporter — three call paths (`issue-reporter.js`)
52
+
53
+ | Path | Trigger | `reporter` | Suppression |
54
+ | --- | --- | --- | --- |
55
+ | LLM self-fire | `report_issue` MCP tool | `llm` | none |
56
+ | Consumer-fire | Human requests a record | `user` | none |
57
+ | Engine auto-fire | Internal failure (scope-drift, synthesis-failed) | `auto` | when `ctx.evalMode` is true |
58
+
59
+ Records land in an engine-internal store (`DEFAULT_STORAGE_ROOT` in
60
+ `issue-reporter.js`); traces >200KB spill to a sidecar `.trace.json`. The store
61
+ is scratch telemetry — durable tracking of recurring patterns belongs in GitHub
62
+ issues / PR descriptions. Type taxonomy: `bug` / `training-gap` /
63
+ `protocol-gap` / `ux-feedback`; severity `nit` < `drift` < `blocker`; owner
64
+ `synthesis | retrieval | validator | chunk-corpus | mcp-protocol | unknown`.
65
+
66
+ ## Closed-loop validation — chunk-zettel is deliberately NOT wired in
67
+
68
+ Every LLM-calling engine outside this directory (`generate-pro`,
69
+ `generate-thinking`) routes its final candidate through the shared
70
+ `packages/a2ui/compose/shared/validate-and-repair.js` — full schema +
71
+ Ajv catalog + anti-pattern conformance, orthogonal to whatever narrower
72
+ check the engine already runs. `chunk-zettel` (`chunk-synthesizer.js`'s
73
+ `composeFromIntent`) does NOT get this: its result is a raw HTML
74
+ **string**, wrapped by the caller (`registry.js`, `generator-adapter.js`)
75
+ into a single node with an unregistered `component: 'article'` type —
76
+ running full schema validation against that would report `invalid` on
77
+ every single output, unconditionally, regardless of actual quality. See
78
+ TKT-0009 for the three-direction decision this is waiting on before any
79
+ change lands. `chunk-zettel`'s own `validatePlan` (chunk-existence/slot
80
+ checks) remains its complete validation contract for now.
81
+
82
+ Separately, `harvest-chunks.mjs` (corpus admission) now runs every
83
+ templated chunk through the same shared module (validate-only) at
84
+ harvest time — report-only by default (`npm run harvest:chunks:dry`
85
+ shows the results); `--strict` enforcement is deferred to TKT-0010
86
+ (27% of the corpus currently fails, mostly a schema-generation gap
87
+ around `data-*`/`span` attributes rather than corpus-content defects).
88
+
89
+ ## Pitfalls
90
+
91
+ - **`STRONG_MATCH_THRESHOLD` was raised 22 → 40 post-incident.** Lowering it
92
+ reverts to repetitive verbatim output. If retrieval feels cold, profile the
93
+ score distribution via `searchAll()` debugging first — don't lower the gate.
94
+ - **`state-cache` is per-process** — multi-turn breaks across MCP server
95
+ restarts; the client must re-run `compose_from_chunks` for a fresh
96
+ `state_id`. Nothing durable belongs in state-cache.
97
+ - **`issueAccumulator` must be passed via `opts`** to refinement engines — a
98
+ newly wired engine that skips it silently drops auto-fired issues.
99
+ - **`PRE_SEARCH_LIMIT = 30` is kind-aware, not linear** — see
100
+ [zettel-calibration](zettel-calibration.md) before judging it over-permissive.
101
+
102
+ ## Verification
103
+
104
+ ```bash
105
+ npm run zettel:smoke # fast, no LLM
106
+ npm run smoke:engines
107
+ npm run eval:diff -- --engine zettel # slow, real LLM; floors in SKILL.md
108
+ npm run eval:diff -- --engine chunk-zettel
109
+ ```