@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.
- package/.claude-plugin/plugin.json +4 -7
- package/CHANGELOG.md +35 -34
- package/README.md +35 -40
- package/agents/a2ui-engineer.md +22 -53
- package/agents/component-author.md +29 -0
- package/agents/framework-verifier.md +26 -0
- package/agents/release-engineer.md +21 -81
- package/agents/routing-corpus.json +293 -64
- package/bin/demo-postwrite-pattern-gate +94 -0
- package/bin/forge-lint +17 -2
- package/bin/sidecar-prewrite-guard +104 -0
- package/commands/deploy.md +9 -0
- package/commands/dogfood.md +10 -0
- package/commands/gen-review.md +9 -0
- package/commands/release.md +10 -0
- package/hooks/hooks.json +15 -0
- package/package.json +3 -6
- package/references/contracts/a2ui-mcp-surface.md +35 -0
- package/references/contracts/migration-guide-format.md +34 -0
- package/references/shared/content-trust.md +19 -74
- package/skills/adia-a2ui/SKILL.md +99 -0
- package/skills/{adia-ui-a2ui → adia-a2ui}/evals/routing-corpus.json +10 -10
- package/skills/adia-a2ui/references/anti-patterns.md +27 -0
- package/skills/adia-a2ui/references/chunk-authoring.md +71 -0
- package/skills/adia-a2ui/references/corpus-discipline.md +68 -0
- package/skills/adia-a2ui/references/eval-diagnostics.md +86 -0
- package/skills/adia-a2ui/references/format-extension-decisions.md +66 -0
- package/skills/adia-a2ui/references/leverage-rules.md +52 -0
- package/skills/adia-a2ui/references/mcp-pipeline-ops.md +83 -0
- package/skills/adia-a2ui/references/mcp-tool-reference.md +59 -0
- package/skills/adia-a2ui/references/pipeline-overview.md +115 -0
- package/skills/adia-a2ui/references/semantic-fail-lifting.md +74 -0
- package/skills/adia-a2ui/references/strategy-engines.md +109 -0
- package/skills/adia-a2ui/references/zettel-calibration.md +104 -0
- package/skills/adia-author/SKILL.md +112 -0
- package/skills/adia-author/evals/routing-corpus.json +222 -0
- package/skills/{adia-ui-authoring → adia-author}/references/anti-patterns.md +33 -4
- package/skills/{adia-ui-authoring → adia-author}/references/authoring-cycle.md +9 -11
- package/skills/adia-author/references/canonical-pattern-index.md +243 -0
- package/skills/{adia-ui-authoring → adia-author}/references/code-style.md +19 -21
- package/skills/adia-author/references/common-gotchas.md +129 -0
- package/skills/adia-author/references/composite-demo-protocol.md +271 -0
- package/skills/{adia-ui-authoring → adia-author}/references/css-patterns.md +19 -6
- package/skills/{adia-ui-authoring → adia-author}/references/lifecycle-patterns.md +1 -0
- package/skills/{adia-ui-authoring → adia-author}/references/llm-bridge.md +3 -5
- package/skills/{adia-ui-authoring → adia-author}/references/module-promotion.md +20 -38
- package/skills/{adia-ui-authoring → adia-author}/references/primitive-audit.md +2 -4
- package/skills/{adia-ui-authoring → adia-author}/references/shell-patterns.md +12 -18
- package/skills/{adia-ui-authoring → adia-author}/references/token-contract.md +5 -7
- package/skills/{adia-ui-authoring → adia-author}/references/worked-example.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/references/yaml-contract.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/scripts/build-canonical-pattern-index.mjs +3 -3
- package/skills/adia-deploy/SKILL.md +128 -0
- package/skills/{adia-ui-ops → adia-deploy}/references/deploy-playbooks.md +47 -30
- package/skills/adia-dogfood/SKILL.md +124 -0
- package/skills/adia-dogfood/references/admin-shell-anatomy.md +77 -0
- package/skills/adia-dogfood/references/app-shell-pitfalls.md +66 -0
- package/skills/adia-dogfood/references/card-anatomy-sweep.md +66 -0
- package/skills/adia-dogfood/references/html-attr-sweep.md +63 -0
- package/skills/adia-dogfood/references/native-leak-annotations.md +73 -0
- package/skills/adia-dogfood/references/visual-probe-triage.md +80 -0
- package/skills/{adia-ui-dogfood → adia-dogfood}/scripts/analyze.mjs +30 -14
- package/skills/adia-gen-review/SKILL.md +127 -0
- package/skills/adia-gen-review/references/corpus-html-patterns.md +279 -0
- package/skills/adia-gen-review/references/loop-protocol.md +216 -0
- package/skills/adia-gen-review/references/rubric-cosmetic.md +100 -0
- package/skills/adia-gen-review/references/rubric-decompose.md +101 -0
- package/skills/adia-gen-review/references/rubric-score.md +214 -0
- package/skills/{adia-ui-gen-review → adia-gen-review}/references/scores.schema.json +2 -2
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-coverage-audit.mjs +4 -4
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-decompose.mjs +10 -6
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-status.mjs +5 -5
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/validate-cycle-scores.mjs +5 -5
- package/skills/adia-llm-internals/SKILL.md +77 -0
- package/skills/{adia-ui-llm → adia-llm-internals}/references/adapter-contract.md +4 -2
- package/skills/{adia-ui-llm → adia-llm-internals}/references/add-a-provider.md +4 -5
- package/skills/{adia-ui-llm → adia-llm-internals}/references/bridge-facade.md +10 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/browser-proxy-boundary.md +1 -1
- package/skills/{adia-ui-llm → adia-llm-internals}/references/model-registry.md +5 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/streaming-sse.md +2 -2
- package/skills/adia-release/SKILL.md +72 -0
- package/skills/adia-release/references/changelog-discipline.md +119 -0
- package/skills/adia-release/references/cut-procedure.md +247 -0
- package/skills/adia-release/references/gates-catalog.md +222 -0
- package/skills/adia-release/references/independent-package-release.md +52 -0
- package/skills/adia-release/references/migration-guide-authoring.md +86 -0
- package/skills/adia-release/references/notes-authoring.md +90 -0
- package/skills/adia-release/references/recovery-paths.md +106 -0
- package/skills/{adia-ui-release → adia-release}/scripts/bump.mjs +28 -3
- package/skills/{adia-ui-release → adia-release}/scripts/dispatch-publish.mjs +10 -7
- package/skills/{adia-ui-release → adia-release}/scripts/insert-stub.mjs +1 -1
- package/skills/{adia-ui-release → adia-release}/scripts/package-paths.mjs +6 -0
- package/skills/{adia-ui-release → adia-release}/scripts/promote-unreleased.mjs +1 -1
- package/skills/{adia-ui-release → adia-release}/scripts/release-pack.mjs +38 -31
- package/skills/{adia-ui-release → adia-release}/scripts/tag-lockstep.mjs +7 -3
- package/skills/adia-site-docs/SKILL.md +68 -0
- package/skills/adia-site-docs/evals/audit-report.md +30 -0
- package/skills/adia-site-docs/evals/routing-corpus.json +176 -0
- package/skills/adia-site-docs/intent.md +72 -0
- package/agents/README.md +0 -209
- package/agents/author.md +0 -56
- package/agents/repo-steward.md +0 -56
- package/agents/spec-architect.md +0 -53
- package/agents/tech-lead.md +0 -57
- package/agents/verifier.md +0 -55
- package/bin/lib/audit-axes.mjs +0 -555
- package/bin/lib/dry-run-irreversible.mjs +0 -236
- package/bin/lib/run-skill-evals.mjs +0 -487
- package/bin/lib/teach-router.mjs +0 -250
- package/commands/adia-forge-a2ui.md +0 -10
- package/commands/adia-forge-author.md +0 -10
- package/commands/adia-forge-dogfood.md +0 -8
- package/commands/adia-forge-llm.md +0 -8
- package/commands/adia-forge-orient.md +0 -10
- package/commands/adia-forge-release.md +0 -8
- package/commands/adia-forge-review.md +0 -10
- package/references/shared/pev-rationale.md +0 -64
- package/references/shared/skill-conventions.md +0 -133
- package/skills/adia-ui-a2ui/CHANGELOG.md +0 -32
- package/skills/adia-ui-a2ui/SKILL.md +0 -243
- package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +0 -100
- package/skills/adia-ui-a2ui/references/anti-patterns.md +0 -24
- package/skills/adia-ui-a2ui/references/chunk-authoring.md +0 -88
- package/skills/adia-ui-a2ui/references/corpus-discipline.md +0 -56
- package/skills/adia-ui-a2ui/references/eval-diagnostics.md +0 -127
- package/skills/adia-ui-a2ui/references/fragment-graph.md +0 -91
- package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +0 -106
- package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +0 -398
- package/skills/adia-ui-a2ui/references/pipeline-overview.md +0 -175
- package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +0 -120
- package/skills/adia-ui-a2ui/references/strategy-engines.md +0 -111
- package/skills/adia-ui-a2ui/references/teach-protocol.md +0 -220
- package/skills/adia-ui-a2ui/references/zettel-calibration.md +0 -93
- package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +0 -96
- package/skills/adia-ui-a2ui/scripts/teach-route.mjs +0 -157
- package/skills/adia-ui-a2ui/skill.json +0 -38
- package/skills/adia-ui-authoring/CHANGELOG.md +0 -32
- package/skills/adia-ui-authoring/SKILL.md +0 -256
- package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +0 -101
- package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +0 -109
- package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +0 -113
- package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +0 -138
- package/skills/adia-ui-authoring/evals/routing-corpus.json +0 -245
- package/skills/adia-ui-authoring/references/canonical-pattern-index.md +0 -179
- package/skills/adia-ui-authoring/references/common-gotchas.md +0 -93
- package/skills/adia-ui-authoring/references/composite-demo-protocol.md +0 -1084
- package/skills/adia-ui-authoring/references/teach-protocol.md +0 -428
- package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +0 -148
- package/skills/adia-ui-authoring/skill.json +0 -45
- package/skills/adia-ui-dogfood/CHANGELOG.md +0 -17
- package/skills/adia-ui-dogfood/README.md +0 -62
- package/skills/adia-ui-dogfood/SKILL.md +0 -866
- package/skills/adia-ui-dogfood/skill.json +0 -40
- package/skills/adia-ui-forge/SKILL.md +0 -88
- package/skills/adia-ui-forge/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-gen-review/CHANGELOG.md +0 -108
- package/skills/adia-ui-gen-review/SKILL.md +0 -266
- package/skills/adia-ui-gen-review/references/loop-protocol.md +0 -712
- package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +0 -144
- package/skills/adia-ui-gen-review/references/rubric-decompose.md +0 -117
- package/skills/adia-ui-gen-review/references/rubric-score.md +0 -249
- package/skills/adia-ui-gen-review/references/teach-protocol.md +0 -214
- package/skills/adia-ui-gen-review/skill.json +0 -23
- package/skills/adia-ui-llm/CHANGELOG.md +0 -25
- package/skills/adia-ui-llm/SKILL.md +0 -165
- package/skills/adia-ui-llm/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-llm/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-llm/evals/teach-routing-cases.json +0 -73
- package/skills/adia-ui-llm/references/teach-protocol.md +0 -78
- package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +0 -93
- package/skills/adia-ui-llm/scripts/teach-route.mjs +0 -119
- package/skills/adia-ui-llm/skill.json +0 -33
- package/skills/adia-ui-ops/CHANGELOG.md +0 -291
- package/skills/adia-ui-ops/SKILL.md +0 -401
- package/skills/adia-ui-ops/references/INDEX.md +0 -158
- package/skills/adia-ui-ops/references/audit-cadence.md +0 -263
- package/skills/adia-ui-ops/references/audit-patterns/archive-link-sweep.md +0 -96
- package/skills/adia-ui-ops/references/audit-patterns/audit-history-ledger.md +0 -162
- package/skills/adia-ui-ops/references/audit-patterns/browser-bundle-node-imports.md +0 -154
- package/skills/adia-ui-ops/references/audit-patterns/changelog-unreleased-bloat.md +0 -75
- package/skills/adia-ui-ops/references/audit-patterns/coverage-gaps.md +0 -187
- package/skills/adia-ui-ops/references/audit-patterns/entry-file-coverage.md +0 -122
- package/skills/adia-ui-ops/references/audit-patterns/format-hygiene.md +0 -217
- package/skills/adia-ui-ops/references/audit-patterns/lockstep-versioning.md +0 -113
- package/skills/adia-ui-ops/references/audit-patterns/memory-fragmentation.md +0 -180
- package/skills/adia-ui-ops/references/audit-patterns/orphan-detection.md +0 -202
- package/skills/adia-ui-ops/references/audit-patterns/pointer-validation.md +0 -180
- package/skills/adia-ui-ops/references/audit-patterns/redundancy-detection.md +0 -210
- package/skills/adia-ui-ops/references/audit-patterns/spec-dating-sweep.md +0 -91
- package/skills/adia-ui-ops/references/audit-patterns/stale-content.md +0 -182
- package/skills/adia-ui-ops/references/audit-patterns/staleness-tooling.md +0 -156
- package/skills/adia-ui-ops/references/audit-patterns/token-waste-detection.md +0 -196
- package/skills/adia-ui-ops/references/doc-types/adr-pattern.md +0 -210
- package/skills/adia-ui-ops/references/doc-types/architecture-md.md +0 -190
- package/skills/adia-ui-ops/references/doc-types/changelog.md +0 -183
- package/skills/adia-ui-ops/references/doc-types/decisions-log.md +0 -146
- package/skills/adia-ui-ops/references/doc-types/plan-roadmap.md +0 -182
- package/skills/adia-ui-ops/references/doc-types/postmortem-pattern.md +0 -206
- package/skills/adia-ui-ops/references/genres/prose-and-writing.md +0 -149
- package/skills/adia-ui-ops/references/guidance/context-budget.md +0 -137
- package/skills/adia-ui-ops/references/guidance/llm-doc-writing.md +0 -116
- package/skills/adia-ui-ops/references/guidance/reliability-dial.md +0 -186
- package/skills/adia-ui-ops/references/recipes/adr-introduction.md +0 -211
- package/skills/adia-ui-ops/references/recipes/audit-existing-repo.md +0 -234
- package/skills/adia-ui-ops/references/recipes/cold-start-harvest.md +0 -263
- package/skills/adia-ui-ops/references/recipes/concurrent-learnings-merge.md +0 -158
- package/skills/adia-ui-ops/references/recipes/continuous-learning-loop.md +0 -169
- package/skills/adia-ui-ops/references/recipes/external-reference-verification.md +0 -158
- package/skills/adia-ui-ops/references/recipes/findings-index-readout.md +0 -126
- package/skills/adia-ui-ops/references/recipes/greenfield-setup.md +0 -252
- package/skills/adia-ui-ops/references/recipes/harvest-repo-brain.md +0 -169
- package/skills/adia-ui-ops/references/recipes/import-repo-brain-harvest.md +0 -153
- package/skills/adia-ui-ops/references/recipes/memory-organization.md +0 -182
- package/skills/adia-ui-ops/references/recipes/recommend-then-validate.md +0 -199
- package/skills/adia-ui-ops/references/recipes/self-healing-hooks.md +0 -366
- package/skills/adia-ui-ops/references/recipes/skill-stewardship-loop.md +0 -113
- package/skills/adia-ui-ops/references/standards/agents-md-spec.md +0 -138
- package/skills/adia-ui-ops/references/standards/claude-md-convention.md +0 -123
- package/skills/adia-ui-ops/references/standards/cross-tool-matrix.md +0 -85
- package/skills/adia-ui-ops/references/standards/readme-conventions.md +0 -232
- package/skills/adia-ui-ops/references/teach-protocol.md +0 -215
- package/skills/adia-ui-ops/scripts/audit-ops-roster.mjs +0 -104
- package/skills/adia-ui-ops/skill.json +0 -65
- package/skills/adia-ui-release/CHANGELOG.md +0 -66
- package/skills/adia-ui-release/SKILL.md +0 -323
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +0 -144
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +0 -155
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +0 -114
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +0 -139
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +0 -124
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +0 -125
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +0 -142
- package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +0 -97
- package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +0 -147
- package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +0 -22
- package/skills/adia-ui-release/evals/evals.json +0 -164
- package/skills/adia-ui-release/references/changelog-discipline.md +0 -250
- package/skills/adia-ui-release/references/cycle-happy-path.md +0 -520
- package/skills/adia-ui-release/references/exe-deploy.md +0 -149
- package/skills/adia-ui-release/references/gates-catalog.md +0 -778
- package/skills/adia-ui-release/references/independent-package-release.md +0 -129
- package/skills/adia-ui-release/references/ledger-discipline.md +0 -232
- package/skills/adia-ui-release/references/migration-guide-authoring.md +0 -174
- package/skills/adia-ui-release/references/multi-agent-baseline.md +0 -207
- package/skills/adia-ui-release/references/notes-authoring.md +0 -212
- package/skills/adia-ui-release/references/recovery-paths.md +0 -262
- package/skills/adia-ui-release/references/rollup-notes.md +0 -208
- package/skills/adia-ui-release/references/teach-protocol.md +0 -468
- package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +0 -196
- package/skills/adia-ui-release/scripts/make-ledger.mjs +0 -200
- package/skills/adia-ui-release/skill.json +0 -77
- package/skills/dogfood-sweep/CHANGELOG.md +0 -37
- package/skills/dogfood-sweep/README.md +0 -105
- package/skills/dogfood-sweep/SKILL.md +0 -1000
- package/skills/dogfood-sweep/analyze.mjs +0 -600
- package/skills/dogfood-sweep/skill.json +0 -31
- /package/skills/{adia-ui-authoring → adia-author}/references/api-contract.md +0 -0
- /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
|
+
```
|