@adia-ai/a2ui-compose 0.5.4 → 0.5.6
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/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,61 @@ transpiler, evals. Retrieval + validation now ship as sibling
|
|
|
7
7
|
packages (`@adia-ai/a2ui-retrieval`, `@adia-ai/a2ui-validator`) so
|
|
8
8
|
non-compose consumers can depend on them without pulling the
|
|
9
9
|
generator graph.
|
|
10
|
-
|
|
11
10
|
## [Unreleased]
|
|
12
11
|
|
|
13
12
|
_No pending changes._
|
|
13
|
+
## [0.5.6] - 2026-05-14
|
|
14
|
+
|
|
15
|
+
### Removed — §195 (v0.5.6) — retired fragment-graph iteration codepath
|
|
16
|
+
|
|
17
|
+
Deleted `packages/a2ui/compose/strategies/zettel/synthesizer.js`. The
|
|
18
|
+
file shipped the `synthesizeComposition` function as a throwing stub
|
|
19
|
+
since §37 (v0.4.7, 2026-05-12, fragment retirement). The dangling
|
|
20
|
+
caller in `generator-adapter.js` (iteration branch, turn ≥ 2 + LLM
|
|
21
|
+
present) caught the throw and auto-fired an `iteration-synthesis-failure`
|
|
22
|
+
issue ticket on every multi-turn refinement — surfaced as an auto-fired
|
|
23
|
+
bug at `.brain/audit-history/issues/2026-05-14-iteration-synthesis-failed-on-turn-3-for-4bfb.json`.
|
|
24
|
+
|
|
25
|
+
### Changed — §195 (v0.5.6) — weak-retrieval branch bridges to chunk-zettel
|
|
26
|
+
|
|
27
|
+
Replaced the `synthesizeComposition()` call in `generateZettel`'s
|
|
28
|
+
weak-retrieval-with-LLM branch with a bridge to
|
|
29
|
+
`chunk-synthesizer.js::composeFromIntent` (the §37 successor codepath).
|
|
30
|
+
Return shape is preserved (`messages`, `validation`, `strategy:
|
|
31
|
+
'composition-synthesized'`, `fragments_used: []`, `synthesized_template`,
|
|
32
|
+
`synthesis`). Fragment instances are no longer tracked on this path —
|
|
33
|
+
the chunk-bridge emits a single html-bearing component. Consumers that
|
|
34
|
+
need fragment-level resolution should wire via `engine: 'chunk-zettel'`
|
|
35
|
+
directly.
|
|
36
|
+
|
|
37
|
+
The `composition-iterated` strategy is retired — turn ≥ 2 on
|
|
38
|
+
`engine: 'zettel'` now takes the same path as turn 1. True
|
|
39
|
+
history-aware iteration lives in `chunk-refiner.js::refineFromIntent`
|
|
40
|
+
behind `engine: 'chunk-zettel'`.
|
|
41
|
+
|
|
42
|
+
### Added — §195 (v0.5.6) — smoke probe
|
|
43
|
+
|
|
44
|
+
NEW `scripts/smoke-iteration-synthesis.mjs` (npm run
|
|
45
|
+
`smoke:iteration-synthesis`) verifies the §195 invariants at three
|
|
46
|
+
layers: filesystem (`synthesizer.js` deleted), source
|
|
47
|
+
(`generator-adapter.js` has no surviving reference to the retired
|
|
48
|
+
identifiers), and runtime (4 sequential turns against the same
|
|
49
|
+
sessionId neither throw nor emit `composition-iterated`).
|
|
50
|
+
## [0.5.5] - 2026-05-14
|
|
51
|
+
|
|
52
|
+
### Changed — §179 (v0.5.5) — principled `deprecated:` yaml field
|
|
53
|
+
|
|
54
|
+
Three new yaml schema fields under each prop:
|
|
55
|
+
|
|
56
|
+
- **`deprecated`** (boolean, default `false`) — when `true`, the LLM prompt builder appends `(deprecated, do not use)` to the prop's line in CORPUS CONTEXT.
|
|
57
|
+
- **`deprecated_since`** (string) — version when deprecation was introduced.
|
|
58
|
+
- **`deprecated_reason`** (string) — human-readable migration guidance.
|
|
14
59
|
|
|
60
|
+
Build pipeline (`scripts/build/components.mjs::compileProp`) collects deprecation metadata and inlines onto the prop schema. Prompt builder (`packages/a2ui/compose/strategies/monolithic/_shared.js`) reads `v.deprecated === true` FIRST; falls back to `/deprecated/i.test(v.description)` (the v0.5.4 §167a substring detection) for back-compat. Existing §167a-tagged props continue to work without yaml changes.
|
|
61
|
+
|
|
62
|
+
Demonstrated on `Avatar.name`. Verified via `buildSystemPrompt`: `name:String[] (deprecated, do not use)` surfaces in CORPUS CONTEXT.
|
|
63
|
+
|
|
64
|
+
Commit `0379dd498`. See root CHANGELOG and journal §179 for full context.
|
|
15
65
|
## [0.5.4] - 2026-05-14
|
|
16
66
|
|
|
17
67
|
### Fixed — §163 transpiler prop-fidelity; catalog-driven extractor closes the harvester drop class (v0.5.4)
|
|
@@ -185,7 +235,6 @@ No compose source change in §173/§175 — both detect future drift in compose'
|
|
|
185
235
|
catalog-vs-prompt + registry-vs-catalog invariants.
|
|
186
236
|
|
|
187
237
|
### Changed — `version`: `0.5.3` → `0.5.4`.
|
|
188
|
-
|
|
189
238
|
## [0.5.3] - 2026-05-14
|
|
190
239
|
|
|
191
240
|
### Fixed — Deterministic chunk-loading order in zettel composition library (§160, v0.5.3)
|
|
@@ -208,7 +257,6 @@ Finalizes the v0.6.0 deprecation schedule for the last two `_debug.*` fields tha
|
|
|
208
257
|
**Scheduled removal**: v0.6.0 drops the `_debug` block entirely from the free-form-composed result shape. The dialog-recorder will read first-class fields directly. v0.5.3 is the **migration window** — any external consumers reading `_debug.attempts` / `_debug.warnings` should switch to the first-class fields before v0.6.0 ships.
|
|
209
258
|
|
|
210
259
|
**Internal verification**: zero live in-repo consumers (`grep -rn '_debug\?\.attempts\|_debug\.attempts\|_debug\?\.warnings\|_debug\.warnings' apps/ playgrounds/ catalog/ packages/` returns only the deprecation comment itself).
|
|
211
|
-
|
|
212
260
|
## [0.5.2] - 2026-05-13
|
|
213
261
|
|
|
214
262
|
### Changed — `plan` graduates from `_debug.*` to first-class on free-form-composed result (§107a infra, v0.5.2)
|
|
@@ -243,7 +291,6 @@ Expected impact: lifts substitution ratio 27.4% → ~35-40% (target ≥30%); F1
|
|
|
243
291
|
`strategies/registry.js` reads model priority chain at call-time (not module-load): `ctx.model` > `process.env.FREE_FORM_MODEL_OVERRIDE` > `FREE_FORM_MODEL_DEFAULT` (Haiku 4.5). Enables `eval-diff.mjs --model <id>` to run the Haiku-vs-Opus A/B for §127 without env-dance or static-import-ordering hazards. `FREE_FORM_MODEL` constant renamed to `FREE_FORM_MODEL_DEFAULT` to reflect the new priority chain.
|
|
244
292
|
|
|
245
293
|
Default behavior unchanged when no override set — the v0.5.1 §108 Haiku pin holds for every consumer that doesn't explicitly override.
|
|
246
|
-
|
|
247
294
|
## [0.5.1] - 2026-05-13
|
|
248
295
|
|
|
249
296
|
### Added — Free-form composer INTENT-PARAPHRASE block + paraphrase-retry (§106, v0.5.1)
|
|
@@ -265,7 +312,6 @@ Consumers passing `ctx.llmAdapter` keep getting their adapter via the mint-failu
|
|
|
265
312
|
### Coverage at v0.5.1 cut
|
|
266
313
|
|
|
267
314
|
Post-§106 prompt-tuning + §108 picker pin + §109 first-class graduation, free-form composer coverage measured at **~96-97%** on the 100-intent held-out set (up from §104's 92%). New AGENTS.md regression threshold floor: `cov≥96%, avg≥85, F1≥0.60` (§115 trip-wire baseline).
|
|
268
|
-
|
|
269
315
|
## [0.5.0] - 2026-05-13
|
|
270
316
|
|
|
271
317
|
### Added — Free-form composer auto-grouping (§103, v0.5.0)
|
|
@@ -283,17 +329,14 @@ Schema validation rejects unknown target keys; downgrade warnings fire when a ta
|
|
|
283
329
|
### Coverage at v0.5.0 cut
|
|
284
330
|
|
|
285
331
|
After §93 (layout regrowth) + §94 (forms regrowth) + §103 (auto-grouping) + §104 (structural substitutions + v0.5.1 deferred regrowth fold-in), free-form composer coverage measured at **92% on the 100-intent held-out set** (up from 21% at §92 baseline). New AGENTS.md regression threshold floor: `cov≥80%, avg≥85, F1≥0.45` (§97 rebaseline).
|
|
286
|
-
|
|
287
332
|
## [0.4.9] - 2026-05-13
|
|
288
333
|
|
|
289
334
|
_No pending changes._
|
|
290
|
-
|
|
291
335
|
## [0.4.8] - 2026-05-12
|
|
292
336
|
|
|
293
337
|
### Fixed — `strategies/zettel/generator-adapter.js` `ensureBooted()` race (§87a, v0.4.8)
|
|
294
338
|
|
|
295
339
|
The zettel composition library's lazy boot had a race condition where concurrent `ensureBooted()` calls could each kick off a separate boot promise. Under contention (multiple requests landing simultaneously at server cold-start), the composition map could be partially populated when consumers reached the synchronous getters. Fix: memoize the boot promise on first call so all subsequent callers await the same promise. Pairs with the v0.4.8 §87 honest-floor eval threshold rebaseline — without the boot race fix, the 1% rebaseline was actually undercounting due to occasional empty-map reads.
|
|
296
|
-
|
|
297
340
|
## [0.4.7] - 2026-05-12
|
|
298
341
|
|
|
299
342
|
### Changed — `strategies/monolithic/_shared.js` `getComponentCatalog()` reads canonical catalog (§72)
|
|
@@ -301,7 +344,6 @@ The zettel composition library's lazy boot had a race condition where concurrent
|
|
|
301
344
|
The legacy reader of `@adia-ai/a2ui-corpus/patterns/_components.json` has been migrated to read `@adia-ai/a2ui-corpus/catalog-a2ui_0_9.json` (the canonical v0.9 catalog, already the package root export). Per-component aliases are now lifted from `components[name].x-adiaui.synonyms.tags`. Same legacy output shape (`{ <Name>: { aliases: string[] } }`); zero behavior change for downstream callers.
|
|
302
345
|
|
|
303
346
|
Closes the §65 carry-over from v0.4.6 — `@adia-ai/a2ui-corpus` `patterns/` + `compositions/` are now deleted from disk + tarball.
|
|
304
|
-
|
|
305
347
|
## [0.4.6] - 2026-05-12
|
|
306
348
|
|
|
307
349
|
### Changed — `core/` retirement follow-through (§64, v0.4.6)
|
|
@@ -337,7 +379,6 @@ Closes the catalog-drift surface that §56 explicitly deferred ("different schem
|
|
|
337
379
|
5. `const` fields (e.g. `{const: 'Button'}`) are discriminator-only. Skip.
|
|
338
380
|
|
|
339
381
|
Source: `packages/a2ui/compose/strategies/monolithic/_shared.js` (+91, -2 lines, commit `afda98f5`).
|
|
340
|
-
|
|
341
382
|
## [0.4.5] - 2026-05-12
|
|
342
383
|
|
|
343
384
|
### Changed — GenUI overhaul prompt-engineering (§56, v0.4.5)
|
|
@@ -353,7 +394,6 @@ Source: `packages/a2ui/compose/strategies/monolithic/_shared.js` (+91, -2 lines,
|
|
|
353
394
|
- **`strategies/monolithic/generate-pro.js` — STRUCTURAL REFERENCE prose enriched.** Prior copy: "a real production block from the codebase matched this intent." New copy: "this chunk was retrieved from the AdiaUI training corpus (annotated production HTML, harvested from real app pages). It matched your intent on keyword/domain ranking." Threads chunk `metadata.domain`, `metadata.description`, `metadata.keywords` into the prompt when present. Reframes "do not copy the HTML" as "the chunk represents the SHAPE the user wants; instantiate it with their content" — more actionable framing.
|
|
354
395
|
|
|
355
396
|
See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the v0.4.5 overhaul arc + apps/genui/CHANGELOG.md `[Unreleased]` for the per-§ rollup.
|
|
356
|
-
|
|
357
397
|
## [0.4.4] - 2026-05-12
|
|
358
398
|
|
|
359
399
|
### Changed
|
|
@@ -370,7 +410,6 @@ See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the v0.4.5 ove
|
|
|
370
410
|
- **MCP server `mcp/server.js` (§37).** Removed `get_fragment` tool, simplified `zettel_stats`, updated imports + boot logs + engine description to reflect the post-fragment world.
|
|
371
411
|
|
|
372
412
|
See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the cross-cutting arc narrative + [docs/journal/2026/05/2026-05-12.md](../../../docs/journal/2026/05/2026-05-12.md) §§ 37 / 38 / 41 / 47 for per-§ details.
|
|
373
|
-
|
|
374
413
|
## [0.4.3] - 2026-05-11
|
|
375
414
|
|
|
376
415
|
### Fixed
|
|
@@ -380,7 +419,6 @@ See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the cross-cutt
|
|
|
380
419
|
### Lockstep
|
|
381
420
|
|
|
382
421
|
9-package coordinated PATCH cut to v0.4.3 (per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy)). Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). Source change scoped to `core/generator.js` + `strategies/zettel/state-cache.js`. Rides alongside `@adia-ai/web-components` v0.4.3 (input-ui locale + thousands grouping + hold-to-repeat). See root [CHANGELOG.md `## [0.4.3]`](../../../CHANGELOG.md) for the cut narrative.
|
|
383
|
-
|
|
384
422
|
## [0.4.2] - 2026-05-11
|
|
385
423
|
|
|
386
424
|
### Ride-along (no source changes)
|
|
@@ -388,7 +426,6 @@ See root [CHANGELOG.md `[Unreleased]`](../../../CHANGELOG.md) for the cross-cutt
|
|
|
388
426
|
Lockstep PATCH cut alongside `@adia-ai/web-components@0.4.2` (`<input-ui type="number">` rewrite drops native `<input type=number>` wrapping) + `@adia-ai/web-modules@0.4.2` (`<editor-sidebar>` grid-track width-mirror fix). Source byte-identical to v0.4.1.
|
|
389
427
|
|
|
390
428
|
Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4.0` covers `0.4.x` under semver). See root [CHANGELOG.md `## [0.4.2]`](../../../CHANGELOG.md) for the cut narrative.
|
|
391
|
-
|
|
392
429
|
## [0.4.1] - 2026-05-10
|
|
393
430
|
|
|
394
431
|
### Ride-along (no source changes)
|
|
@@ -396,7 +433,6 @@ Internal `@adia-ai/*` dep ranges stay at `^0.4.0` (patch-cut asymmetry — `^0.4
|
|
|
396
433
|
Lockstep PATCH cut alongside `@adia-ai/web-modules@0.4.1` (simple cluster) + `@adia-ai/a2ui-validator@0.4.1` (Phase 3 foundation) + `@adia-ai/a2ui-corpus@0.4.1` (fragment metrics reconciliation). Source byte-identical to v0.4.0.
|
|
397
434
|
|
|
398
435
|
Internal `@adia-ai/*` dep ranges bumped from `^0.4.0` to `^0.4.1`. See root [CHANGELOG.md `## [0.4.1]`](../../../CHANGELOG.md) for the cut narrative.
|
|
399
|
-
|
|
400
436
|
## [0.4.0] - 2026-05-10
|
|
401
437
|
|
|
402
438
|
### Ride-along (no source changes)
|
|
@@ -404,25 +440,21 @@ Internal `@adia-ai/*` dep ranges bumped from `^0.4.0` to `^0.4.1`. See root [CHA
|
|
|
404
440
|
Lockstep MINOR cut alongside `@adia-ai/web-modules@0.4.0` (ADR-0024 legacy shell shapes retired). Source byte-identical to v0.3.6.
|
|
405
441
|
|
|
406
442
|
Internal `@adia-ai/*` dep ranges bumped from `^0.3.0` to `^0.4.0`. See root [CHANGELOG.md `## [0.4.0]`](../../../CHANGELOG.md) for the cut narrative.
|
|
407
|
-
|
|
408
443
|
## [0.3.6] - 2026-05-10
|
|
409
444
|
|
|
410
445
|
### Ride-along (no source changes)
|
|
411
446
|
|
|
412
447
|
Lockstep version bump only — source byte-identical to v0.3.5. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.6]`](../../../CHANGELOG.md) for the cut narrative.
|
|
413
|
-
|
|
414
448
|
## [0.3.5] - 2026-05-07
|
|
415
449
|
|
|
416
450
|
### Ride-along (no source changes)
|
|
417
451
|
|
|
418
452
|
Lockstep version bump only — source byte-identical to v0.3.4. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.5]`](../../../CHANGELOG.md) for the cut narrative.
|
|
419
|
-
|
|
420
453
|
## [0.3.4] - 2026-05-07
|
|
421
454
|
|
|
422
455
|
### Ride-along (no source changes)
|
|
423
456
|
|
|
424
457
|
Lockstep version bump only — source byte-identical to v0.3.3. Internal `@adia-ai/*` dep ranges remain at `^0.3.0`. See root [CHANGELOG.md `## [0.3.4]`](../../../CHANGELOG.md) for the cut narrative.
|
|
425
|
-
|
|
426
458
|
## [0.3.3] - 2026-05-07
|
|
427
459
|
|
|
428
460
|
**Lockstep cut.** All 9 published `@adia-ai/*` packages now share version `0.3.3`, governed by [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` ranges stay at `^0.3.0` (patch-cut asymmetry — caret floats `0.3.x`).
|
|
@@ -467,7 +499,6 @@ Lockstep version bump only — source byte-identical to v0.3.3. Internal `@adia-
|
|
|
467
499
|
for the lifetime of the process. Trade-offs: good for long-running
|
|
468
500
|
MCP, bad for tests/hot-reload. To force a reload, call `loadAll()`
|
|
469
501
|
directly. (closes backlog #100)
|
|
470
|
-
|
|
471
502
|
## [0.3.2] - 2026-05-06
|
|
472
503
|
|
|
473
504
|
**9-package lockstep patch cut to v0.3.2.** All lockstep members share
|
|
@@ -494,7 +525,6 @@ Internal `@adia-ai/*` dep ranges unchanged at `^0.3.0`.
|
|
|
494
525
|
### Changed
|
|
495
526
|
|
|
496
527
|
- `version`: `0.3.1` → `0.3.2`.
|
|
497
|
-
|
|
498
528
|
## [0.3.1] - 2026-05-06
|
|
499
529
|
|
|
500
530
|
**9-package lockstep patch cut.** All 9 published `@adia-ai/*` packages bump 0.3.0 → 0.3.1 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges remain at `^0.3.0` (covers `0.3.1` under semver — patch-cut asymmetry).
|
|
@@ -505,7 +535,6 @@ This package itself ships **no source changes** in v0.3.1. The cut bumps version
|
|
|
505
535
|
|
|
506
536
|
- `version`: `0.3.0` → `0.3.1`.
|
|
507
537
|
- Internal `@adia-ai/*` dep ranges: unchanged at `^0.3.0` (covers `0.3.1` under semver — patch-cut asymmetry).
|
|
508
|
-
|
|
509
538
|
## [0.3.0] - 2026-05-05
|
|
510
539
|
|
|
511
540
|
**9-package lockstep cut + LLM subpath dropped.** All 9 published `@adia-ai/*` packages bump 0.2.5 → 0.3.0 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges bump `^0.2.0` → `^0.3.0`.
|
|
@@ -551,7 +580,6 @@ This is a **minor cut on top of v0.2.5 with one BREAKING change**: the `./llm` s
|
|
|
551
580
|
```
|
|
552
581
|
|
|
553
582
|
Plus rewrite imports as shown above. The change is mechanical.
|
|
554
|
-
|
|
555
583
|
## [0.2.5] - 2026-05-04
|
|
556
584
|
|
|
557
585
|
**8-package lockstep cut.** All 8 published `@adia-ai/*` packages bump 0.2.4 → 0.2.5 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges remain at `^0.2.0` (covers 0.2.5 under semver — patch-cut asymmetry).
|
|
@@ -562,7 +590,6 @@ This is a **patch cut on top of v0.2.4, no BREAKING changes.** Substantive conte
|
|
|
562
590
|
|
|
563
591
|
- `version`: `0.2.4` → `0.2.5`.
|
|
564
592
|
- Internal `@adia-ai/*` dep ranges: unchanged at `^0.2.0` (covers `0.2.5` under semver — patch-cut asymmetry).
|
|
565
|
-
|
|
566
593
|
## [0.2.4] - 2026-05-04
|
|
567
594
|
|
|
568
595
|
**8-package lockstep cut.** All 8 published `@adia-ai/*` packages bump 0.2.3 → 0.2.4 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Internal `@adia-ai/*` dep ranges remain at `^0.2.0` (covers 0.2.4 under semver — patch-cut asymmetry).
|
|
@@ -581,7 +608,6 @@ _Nothing yet._
|
|
|
581
608
|
---
|
|
582
609
|
|
|
583
610
|
---
|
|
584
|
-
|
|
585
611
|
## [0.2.3] - 2026-05-04
|
|
586
612
|
|
|
587
613
|
**Lockstep cut.** All 8 published `@adia-ai/*` packages bump
|
|
@@ -599,7 +625,6 @@ Patch cut — no breaking changes.
|
|
|
599
625
|
### No source changes
|
|
600
626
|
|
|
601
627
|
`@adia-ai/a2ui-compose` source is byte-identical to `0.2.2`. The cut bumps version + the internal dep range entries only.
|
|
602
|
-
|
|
603
628
|
## [0.2.2] - 2026-05-02
|
|
604
629
|
|
|
605
630
|
**Lockstep cut + reasoning-panel emission fixes.** All 8 published `@adia-ai/*` packages bump 0.2.1 → 0.2.2 per [`docs/specs/package-architecture.md` § 15](../../../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
@@ -623,7 +648,6 @@ Patch cut — no breaking changes.
|
|
|
623
648
|
Companion fix in `@adia-ai/a2ui-retrieval` Unreleased (web-research.js EXPLICIT/IMPLICIT pattern split). Both surfaces feed the same reasoning-panel deception class — five distinct bugs caught + fixed in commit `9986c71e`.
|
|
624
649
|
|
|
625
650
|
---
|
|
626
|
-
|
|
627
651
|
## [0.2.1] - 2026-05-02
|
|
628
652
|
|
|
629
653
|
**Lockstep cut + scope-drift gate at composer time + skeleton harvest + Tier-1 block filter + high-resolution session ticket trace.** All 8 published `@adia-ai/*` packages bump 0.2.0 → 0.2.1 per [`docs/specs/package-architecture.md` § 15](../../../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
|
|
@@ -662,7 +686,6 @@ The synthesizer now captures a `retrievalTrace` per attempt: Tier-1 hits with sc
|
|
|
662
686
|
`issue-reporter.js` renders this as a sibling Markdown ticket alongside the JSON; sections cover header, description, reproduction, component count, retrieval log table, LLM attempts (raw responses), user prompt, composer plan, generated HTML preview, warnings, ops history, environment. A maintainer can replay any flagged session from the ticket alone.
|
|
663
687
|
|
|
664
688
|
---
|
|
665
|
-
|
|
666
689
|
## [0.2.0] - 2026-05-02
|
|
667
690
|
|
|
668
691
|
**Lockstep cut + boundary cleanup.** All 8 published `@adia-ai/*`
|
|
@@ -717,7 +740,6 @@ cycle, but should update on next touch:
|
|
|
717
740
|
```
|
|
718
741
|
|
|
719
742
|
---
|
|
720
|
-
|
|
721
743
|
## [0.1.0] - 2026-04-28
|
|
722
744
|
|
|
723
745
|
**Multi-turn refinement engine (Phase A).** Adds three new modules to the
|
|
@@ -804,7 +826,6 @@ Additive surface; no breaking changes. Existing consumers calling
|
|
|
804
826
|
`composeFromIntent` continue to work unchanged.
|
|
805
827
|
|
|
806
828
|
---
|
|
807
|
-
|
|
808
829
|
## [0.0.1] - 2026-04-24
|
|
809
830
|
|
|
810
831
|
First public release. Framework-agnostic compose engine for the
|
|
@@ -863,7 +884,6 @@ behind a plug-in engine registry.
|
|
|
863
884
|
- Stale internal-identifier references in comments + doc strings swept to the current naming.
|
|
864
885
|
|
|
865
886
|
---
|
|
866
|
-
|
|
867
887
|
## [0.1.0] — internal baseline (unreleased)
|
|
868
888
|
|
|
869
889
|
Initial version at the time the monorepo was established. Contains:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/a2ui-compose",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "AdiaUI A2UI compose engine
|
|
3
|
+
"version": "0.5.6",
|
|
4
|
+
"description": "AdiaUI A2UI compose engine \u2014 framework-agnostic. Takes natural-language intents + a catalog and produces A2UI protocol messages. Pairs with `@adia-ai/a2ui-retrieval` (intent classification, catalog lookup) and `@adia-ai/a2ui-validator` (schema + semantic checks).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./index.js",
|
|
@@ -307,7 +307,8 @@ KEY RULES:
|
|
|
307
307
|
// but never read here, so deprecated props (Avatar.name, Field.persist
|
|
308
308
|
// alias, etc.) looked indistinguishable from canonical props. LLM
|
|
309
309
|
// would pick e.g. <avatar-ui name="..."> instead of text="...".
|
|
310
|
-
|
|
310
|
+
// §179 (v0.5.5): principled `deprecated:` field wins; falls back to §167a substring detection for back-compat.
|
|
311
|
+
if (v.deprecated === true || (v.description && /deprecated/i.test(v.description))) desc += ' (deprecated, do not use)';
|
|
311
312
|
return desc;
|
|
312
313
|
}).join(', ') : '';
|
|
313
314
|
const events = a2uiData.events?.length ? ` events: ${a2uiData.events.join(', ')}` : '';
|
|
@@ -350,7 +351,8 @@ KEY RULES:
|
|
|
350
351
|
// but never read here, so deprecated props (Avatar.name, Field.persist
|
|
351
352
|
// alias, etc.) looked indistinguishable from canonical props. LLM
|
|
352
353
|
// would pick e.g. <avatar-ui name="..."> instead of text="...".
|
|
353
|
-
|
|
354
|
+
// §179 (v0.5.5): principled `deprecated:` field wins; falls back to §167a substring detection for back-compat.
|
|
355
|
+
if (v.deprecated === true || (v.description && /deprecated/i.test(v.description))) desc += ' (deprecated, do not use)';
|
|
354
356
|
return desc;
|
|
355
357
|
}).join(', ') : '';
|
|
356
358
|
const events = comp.events?.length ? ` events: ${comp.events.join(', ')}` : '';
|
|
@@ -901,6 +903,15 @@ export function mergeCanvasDiff(priorComponents, diffComponents) {
|
|
|
901
903
|
const modifiedIds = new Set();
|
|
902
904
|
const newComponents = [];
|
|
903
905
|
|
|
906
|
+
// §190b (v0.5.6) — Aggregate blocked-layout-type-change warnings.
|
|
907
|
+
// The for-loop below can fire `console.warn` once per blocked component,
|
|
908
|
+
// producing 5-10 line bursts when the LLM tries to restructure a form's
|
|
909
|
+
// fields (typical case: 5 Field→Column blocks for a 5-field form).
|
|
910
|
+
// Collect blocks into an array; emit a single aggregated warning after
|
|
911
|
+
// the loop. Closes the 2026-05-14 user-reported "buglabels" intent
|
|
912
|
+
// emitting 6 consecutive blocks.
|
|
913
|
+
const blockedLayoutChanges = [];
|
|
914
|
+
|
|
904
915
|
for (const dc of diffComponents) {
|
|
905
916
|
if (!dc || !dc.id) continue;
|
|
906
917
|
|
|
@@ -918,7 +929,7 @@ export function mergeCanvasDiff(priorComponents, diffComponents) {
|
|
|
918
929
|
const LAYOUT_CONTAINERS = new Set(['Grid', 'Row', 'Column', 'Stack']);
|
|
919
930
|
if (dc.component && dc.component !== existing.component &&
|
|
920
931
|
(LAYOUT_CONTAINERS.has(existing.component) || LAYOUT_CONTAINERS.has(dc.component))) {
|
|
921
|
-
|
|
932
|
+
blockedLayoutChanges.push({ id: dc.id, from: existing.component, to: dc.component });
|
|
922
933
|
delete dc.component;
|
|
923
934
|
}
|
|
924
935
|
const merged = { ...existing, ...dc };
|
|
@@ -932,6 +943,14 @@ export function mergeCanvasDiff(priorComponents, diffComponents) {
|
|
|
932
943
|
}
|
|
933
944
|
}
|
|
934
945
|
|
|
946
|
+
// §190b — single aggregated warning for blocked layout changes.
|
|
947
|
+
if (blockedLayoutChanges.length > 0) {
|
|
948
|
+
const summary = blockedLayoutChanges
|
|
949
|
+
.map(b => `${b.from}→${b.to} on id="${b.id}"`)
|
|
950
|
+
.join(', ');
|
|
951
|
+
console.warn(`[mergeCanvasDiff] Blocked ${blockedLayoutChanges.length} layout type change${blockedLayoutChanges.length === 1 ? '' : 's'}: ${summary}. Preserving original types.`);
|
|
952
|
+
}
|
|
953
|
+
|
|
935
954
|
// Build result: prior components (minus deleted) + new components
|
|
936
955
|
const result = [];
|
|
937
956
|
for (const c of priorComponents) {
|
|
@@ -197,8 +197,12 @@ describe('§168 mergeCanvasDiff — iteration handoff invariants', () => {
|
|
|
197
197
|
const result = mergeCanvasDiff(prior, llmOutput);
|
|
198
198
|
// Grid type preserved despite LLM's attempted change
|
|
199
199
|
expect(result.find(c => c.id === 'root').component).toBe('Grid');
|
|
200
|
+
// §190b — warning is aggregated: "Blocked N layout type change(s): …"
|
|
200
201
|
expect(warn).toHaveBeenCalledWith(
|
|
201
|
-
expect.stringContaining('Blocked layout type change')
|
|
202
|
+
expect.stringContaining('Blocked 1 layout type change')
|
|
203
|
+
);
|
|
204
|
+
expect(warn).toHaveBeenCalledWith(
|
|
205
|
+
expect.stringContaining('Grid→Column on id="root"')
|
|
202
206
|
);
|
|
203
207
|
warn.mockRestore();
|
|
204
208
|
});
|
|
@@ -3,35 +3,66 @@
|
|
|
3
3
|
*
|
|
4
4
|
* generate({ intent, mode, llmAdapter, sessionId }) -> { messages, validation, strategy, ...extra }
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Two reasoning layers (post-§195, v0.5.6):
|
|
7
7
|
* 1. Retrieval (always available) — keyword-rank the corpus, resolve top composition.
|
|
8
|
-
* 2. LLM synthesis (when llmAdapter provided AND retrieval weak) —
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* 2. LLM synthesis (when llmAdapter provided AND retrieval weak) — bridge to
|
|
9
|
+
* chunk-zettel's `composeFromIntent` (the §37 successor codepath) which
|
|
10
|
+
* produces a single-shot html composition from the chunk corpus.
|
|
11
|
+
*
|
|
12
|
+
* Session iteration is currently NOT history-aware in this engine. Prior turns
|
|
13
|
+
* are recorded for analytics + drift tracking, but turn≥2 takes the same code
|
|
14
|
+
* path as turn 1 (fresh retrieval → fresh synthesis). Full history-aware
|
|
15
|
+
* iteration (multi-turn refinement modifying an existing canvas) lives in the
|
|
16
|
+
* `chunk-zettel` engine via `chunk-refiner.js::refineFromIntent` — wire it via
|
|
17
|
+
* `engine: 'chunk-zettel'` rather than `engine: 'zettel'`.
|
|
18
|
+
*
|
|
19
|
+
* The prior fragment-graph iteration codepath (`synthesizeComposition` with
|
|
20
|
+
* `historySummary`) was retired in §37 (2026-05-12) when fragments retired.
|
|
21
|
+
* §195 (v0.5.6) cleaned up the dangling caller — turn≥2 no longer throws +
|
|
22
|
+
* auto-fires a `iteration-synthesis-failure` issue on every multi-turn turn.
|
|
13
23
|
*
|
|
14
24
|
* Strategy labels in the return:
|
|
15
25
|
* - composition-match — fresh retrieval, strong match, emitted verbatim
|
|
16
|
-
* - composition-synthesized —
|
|
17
|
-
* - composition-iterated — LLM modified prior turn's template
|
|
26
|
+
* - composition-synthesized — chunk-zettel single-shot synthesis
|
|
18
27
|
* - fragment-candidates — retrieval weak + no LLM, returning atoms only
|
|
19
|
-
* - synthesis-failed —
|
|
28
|
+
* - synthesis-failed — chunk-zettel tried and failed validation
|
|
20
29
|
*/
|
|
21
30
|
import {
|
|
22
31
|
getComposition,
|
|
23
32
|
searchAll,
|
|
24
33
|
} from './composition-library.js';
|
|
25
34
|
import { resolveComposition, templateToMessages } from './composer.js';
|
|
26
|
-
import { synthesizeComposition } from './synthesizer.js';
|
|
27
35
|
import {
|
|
28
36
|
recordTurn,
|
|
29
37
|
getTurns,
|
|
30
|
-
buildHistorySummary,
|
|
31
38
|
} from './session-store.js';
|
|
32
|
-
import { autoReport } from './issue-reporter.js';
|
|
33
39
|
import { validateSchema } from '../../../validator/validator.js';
|
|
34
40
|
|
|
41
|
+
// Lazy-load the chunk-synthesizer bridge. It imports chunk-corpus data
|
|
42
|
+
// via composition-library's dual-mode loader, which is already top-level
|
|
43
|
+
// awaited; importing it here statically would not break anything but the
|
|
44
|
+
// async-import keeps the cold-start surface tight for the strong-match
|
|
45
|
+
// (no-LLM) path that doesn't need synthesis at all.
|
|
46
|
+
async function bridgeToChunkSynthesis({ intent, llmAdapter }) {
|
|
47
|
+
const { composeFromIntent } = await import('./chunk-synthesizer.js');
|
|
48
|
+
const result = await composeFromIntent({ intent, llmAdapter, maxAttempts: 2 });
|
|
49
|
+
// Shape-adapt chunk-synthesizer's `{ html, plan, source, ... }` to the
|
|
50
|
+
// synthesis-branch's prior `{ messages, template, synthesis }` contract.
|
|
51
|
+
const messages = result.html
|
|
52
|
+
? [{ type: 'updateComponents', components: [{ id: 'chunk-root', component: 'article', html: result.html }] }]
|
|
53
|
+
: [];
|
|
54
|
+
return {
|
|
55
|
+
messages,
|
|
56
|
+
template: result.plan ? [{ $chunk: 'composeFromIntent', plan: result.plan }] : [],
|
|
57
|
+
synthesis: {
|
|
58
|
+
source: result.source,
|
|
59
|
+
score: result.score,
|
|
60
|
+
warnings: result.warnings || [],
|
|
61
|
+
scopeDrift: result.scopeDrift || null,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
35
66
|
// Composition library auto-loads at module import time via top-level `await
|
|
36
67
|
// loadAll()` in composition-library.js (§72 dual-mode loader, commit
|
|
37
68
|
// `76dbcff2`). The previous `ensureBooted()` here called `loadAll()` WITHOUT
|
|
@@ -72,62 +103,17 @@ function toUpdateComponentsMessages(template) {
|
|
|
72
103
|
}
|
|
73
104
|
|
|
74
105
|
export async function generateZettel({ intent, mode = 'instant', llmAdapter = null, sessionId = null } = {}) {
|
|
75
|
-
// ── Session
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
106
|
+
// ── Session iteration note (post-§195, v0.5.6) ──
|
|
107
|
+
// Fragment-graph history-aware iteration (`synthesizeComposition` with
|
|
108
|
+
// `historySummary`) was retired in §37 when fragments retired. Turn≥2 now
|
|
109
|
+
// takes the same path as turn 1 — fresh retrieval → fresh chunk-synthesis.
|
|
110
|
+
// For true history-aware iteration (modify-an-existing-canvas), wire the
|
|
111
|
+
// request via `engine: 'chunk-zettel'` which uses `chunk-refiner.js`.
|
|
112
|
+
//
|
|
113
|
+
// Prior turns are still recorded (analytics + drift tracking via `getDrift`)
|
|
114
|
+
// but the iteration BRANCH is gone — no more spurious
|
|
115
|
+
// `iteration-synthesis-failure` auto-fires on every multi-turn request.
|
|
79
116
|
const priorTurns = sessionId ? getTurns(sessionId) : [];
|
|
80
|
-
const hasHistory = priorTurns.length > 0;
|
|
81
|
-
|
|
82
|
-
if (hasHistory && llmAdapter) {
|
|
83
|
-
try {
|
|
84
|
-
const historySummary = buildHistorySummary(sessionId, 3);
|
|
85
|
-
const synth = await synthesizeComposition({ intent, llmAdapter, historySummary });
|
|
86
|
-
const validation = validateSchema(synth.messages, { intent });
|
|
87
|
-
const fragments = (synth.template || []).filter((n) => n.$fragment).map((n) => n.$fragment);
|
|
88
|
-
recordTurn(sessionId, {
|
|
89
|
-
intent,
|
|
90
|
-
messages: synth.messages,
|
|
91
|
-
template: synth.template,
|
|
92
|
-
composition: null,
|
|
93
|
-
strategy: 'composition-iterated',
|
|
94
|
-
fragments,
|
|
95
|
-
validation,
|
|
96
|
-
});
|
|
97
|
-
return {
|
|
98
|
-
messages: synth.messages,
|
|
99
|
-
validation,
|
|
100
|
-
strategy: 'composition-iterated',
|
|
101
|
-
retrieval: { hit: false, rank: null, candidate: null, reason: `iteration on turn ${priorTurns.length + 1}` },
|
|
102
|
-
composition: null,
|
|
103
|
-
fragments_used: fragments,
|
|
104
|
-
synthesized_template: synth.template,
|
|
105
|
-
synthesis: synth.synthesis,
|
|
106
|
-
sessionTurns: priorTurns.length + 1,
|
|
107
|
-
};
|
|
108
|
-
} catch (err) {
|
|
109
|
-
// If iteration synthesis fails, fall through to the normal path. Record
|
|
110
|
-
// the failure so the next turn can see we tried, and auto-fire an issue
|
|
111
|
-
// ticket so synthesis-owners can investigate the failure post-hoc.
|
|
112
|
-
console.error('[zettel] iteration synthesis failed:', err.message);
|
|
113
|
-
try {
|
|
114
|
-
await autoReport(
|
|
115
|
-
'iteration-synthesis-failure',
|
|
116
|
-
{
|
|
117
|
-
intent,
|
|
118
|
-
turn: priorTurns.length + 1,
|
|
119
|
-
state_id: sessionId,
|
|
120
|
-
body: `Auto-fired by generator-adapter. Iteration synthesis threw on turn ${priorTurns.length + 1}.\n\nError: \`${err.message}\``,
|
|
121
|
-
tags: ['generator-adapter', `turn-${priorTurns.length + 1}`],
|
|
122
|
-
},
|
|
123
|
-
{ evalMode: mode === 'eval' }
|
|
124
|
-
);
|
|
125
|
-
} catch (reportErr) {
|
|
126
|
-
// Never let issue-reporting crash the request path.
|
|
127
|
-
console.error('[zettel] autoReport failed:', reportErr.message);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
117
|
|
|
132
118
|
const hits = searchAll(intent, { limit: 5 });
|
|
133
119
|
const composition = hits.find((h) => h.type === 'composition');
|
|
@@ -163,19 +149,22 @@ export async function generateZettel({ intent, mode = 'instant', llmAdapter = nu
|
|
|
163
149
|
};
|
|
164
150
|
}
|
|
165
151
|
|
|
166
|
-
// ── Weak/no retrieval:
|
|
152
|
+
// ── Weak/no retrieval: bridge to chunk-zettel synthesis (the §37 successor) ──
|
|
167
153
|
if (llmAdapter && mode !== 'instant-only') {
|
|
168
154
|
try {
|
|
169
|
-
const synth = await
|
|
155
|
+
const synth = await bridgeToChunkSynthesis({ intent, llmAdapter });
|
|
170
156
|
const validation = validateSchema(synth.messages, { intent });
|
|
171
|
-
|
|
157
|
+
// Chunk-bridge produces an html-bearing single component, not
|
|
158
|
+
// resolved fragment instances. `fragments_used` is empty by design;
|
|
159
|
+
// consumers tracking fragment usage should switch to the
|
|
160
|
+
// chunk-zettel engine which surfaces `_debug.plan` directly.
|
|
172
161
|
recordTurn(sessionId, {
|
|
173
162
|
intent,
|
|
174
163
|
messages: synth.messages,
|
|
175
164
|
template: synth.template,
|
|
176
165
|
composition: null,
|
|
177
166
|
strategy: 'composition-synthesized',
|
|
178
|
-
fragments,
|
|
167
|
+
fragments: [],
|
|
179
168
|
validation,
|
|
180
169
|
});
|
|
181
170
|
return {
|
|
@@ -189,7 +178,7 @@ export async function generateZettel({ intent, mode = 'instant', llmAdapter = nu
|
|
|
189
178
|
reason: composition ? `top score ${composition.score} below threshold ${STRONG_MATCH_THRESHOLD}` : 'no composition retrieved',
|
|
190
179
|
},
|
|
191
180
|
composition: null,
|
|
192
|
-
fragments_used:
|
|
181
|
+
fragments_used: [],
|
|
193
182
|
synthesized_template: synth.template,
|
|
194
183
|
synthesis: synth.synthesis,
|
|
195
184
|
candidates: hits,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composition synthesizer — RETIRED (§37, 2026-05-12).
|
|
3
|
-
*
|
|
4
|
-
* Previously: when zettel retrieval was weak, this called the LLM to
|
|
5
|
-
* assemble a NEW composition from the fragment catalog (technique B/C
|
|
6
|
-
* fragment-graph synthesis). Fragments are retired and there's no
|
|
7
|
-
* fragment catalog to draw from anymore. The deterministic path
|
|
8
|
-
* (`resolveComposition` on a retrieved composition) still works.
|
|
9
|
-
*
|
|
10
|
-
* Until a chunk-based synthesis fallback lands, this export throws on
|
|
11
|
-
* call. Callers should catch and fall through to monolithic-pro's
|
|
12
|
-
* generation path. generator-adapter.js handles this gracefully.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
export async function synthesizeComposition() {
|
|
16
|
-
const err = new Error(
|
|
17
|
-
'synthesizeComposition is retired (§37 fragment retirement). ' +
|
|
18
|
-
'Use chunk-zettel or monolithic-pro for LLM-driven composition.'
|
|
19
|
-
);
|
|
20
|
-
err.code = 'SYNTHESIZER_RETIRED';
|
|
21
|
-
throw err;
|
|
22
|
-
}
|