@adia-ai/a2ui-compose 0.5.2 → 0.5.3

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
@@ -12,6 +12,29 @@ generator graph.
12
12
 
13
13
  _No pending changes._
14
14
 
15
+ ## [0.5.3] - 2026-05-14
16
+
17
+ ### Fixed — Deterministic chunk-loading order in zettel composition library (§160, v0.5.3)
18
+
19
+ `strategies/zettel/composition-library.js`: `walk()` now sorts `fs.readdirSync` output via `localeCompare` before recursing. Pre-§160 the directory walker relied on filesystem-defined entry order, which varies across processes on APFS/ext4. When two chunks tied on retrieval score for a given intent, the first-loaded won the tie-break — so the same intent could match chunk A in one process and chunk B in the next.
20
+
21
+ Surfaced as ~40% flake rate on the `admin dashboard with kpi cards` retrieval probe post-§143 (the 8 new UI-primitive chunks compete with the original `dashboard-kpi-grid` template). Sorted walk pins load order; remaining flakiness is now constrained to a corpus-quality bug (Stat chunks strip `label`/`value`/`change` attrs in the `template` field) tracked as v0.5.4 F-S1a.
22
+
23
+ No behavior change for callers that don't hit a tie-break — most intents have a clear retrieval winner.
24
+
25
+ ### Deprecated — `_debug.attempts` and `_debug.warnings` on free-form-composed results (§146, v0.5.3)
26
+
27
+ Finalizes the v0.6.0 deprecation schedule for the last two `_debug.*` fields that consumers might still read on `generateFreeFormAdapter`'s result. Both fields are dialog-recorder-gated (silently `undefined` when not recording) — the same access pattern §109 (v0.5.1) + §107a (v0.5.2) removed for `usedIngredients` / `rationale` / `plan`.
28
+
29
+ **v0.6.0 migration path** (folded into the inline `@deprecated` JSDoc on `strategies/registry.js`):
30
+
31
+ - `result._debug?.attempts` → `result.attempts: number` (LLM round-trips: 1 normally; 2-3 with hallucination retry or paraphrase-retry)
32
+ - `result._debug?.warnings` → `result.warnings: string[]` (non-fatal transpile findings: unknown substitution keys, layout-value fall-throughs, chunk-resolution warns)
33
+
34
+ **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.
35
+
36
+ **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).
37
+
15
38
  ## [0.5.2] - 2026-05-13
16
39
 
17
40
  ### Changed — `plan` graduates from `_debug.*` to first-class on free-form-composed result (§107a infra, v0.5.2)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/a2ui-compose",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "AdiaUI A2UI compose engine — 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": {
@@ -191,6 +191,33 @@ async function generateFreeFormAdapter(ctx) {
191
191
  // were removed by §109 / §107a; this block is now strictly debug-
192
192
  // recorder fodder. Scheduled removal: v0.6.0 will fold `attempts` +
193
193
  // `warnings` into first-class result fields and drop `_debug` here.
194
+ //
195
+ // §146 (v0.5.3): finalize the v0.6.0 deprecation schedule for the
196
+ // last two `_debug.*` fields that any consumer might still read.
197
+ //
198
+ // @deprecated `_debug.attempts` and `_debug.warnings` — both fields
199
+ // are dialog-recorder-gated (silently `undefined` when not
200
+ // recording), which is exactly the access pattern §109+§107a
201
+ // removed for `usedIngredients`/`rationale`/`plan`. v0.6.0 folds
202
+ // both into first-class result fields:
203
+ //
204
+ // - `result.attempts: number` — number of LLM round-trips taken
205
+ // to produce the final plan (1 normally; 2-3 with hallucination
206
+ // retry or paraphrase-retry; same value as §106's loop counter)
207
+ // - `result.warnings: string[]` — non-fatal transpile findings
208
+ // (unknown substitution keys, layout-value fall-throughs,
209
+ // chunk-resolution warns); same value as transpilePlan output
210
+ //
211
+ // Consumers should switch reads from `result._debug?.attempts` →
212
+ // `result.attempts` and `result._debug?.warnings` → `result.warnings`
213
+ // before v0.6.0 ships. The `_debug` block itself disappears from
214
+ // the free-form-composed result shape entirely in v0.6.0; the
215
+ // dialog-recorder will read first-class fields directly.
216
+ //
217
+ // No in-repo consumers currently read these fields (verified
218
+ // `grep -rn '_debug\?.attempts\|_debug.attempts\|_debug\?.warnings\|_debug.warnings'
219
+ // apps/ playgrounds/ catalog/ packages/` → 0 hits at v0.5.3 cut).
220
+ // External consumers should treat v0.6.0 as the migration window.
194
221
  _debug: isRecording() ? {
195
222
  systemPrompt: null,
196
223
  rawLLMResponse: null,
@@ -101,7 +101,17 @@ async function _loadAllNode() {
101
101
 
102
102
  function walk(dir, cb) {
103
103
  if (!fs.existsSync(dir)) return;
104
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
104
+ // §160 (v0.5.3, F-S1 root cause): sort readdir output. fs.readdirSync
105
+ // returns entries in filesystem-defined order (variable across
106
+ // processes on APFS/ext4), which means chunk-loading order varied
107
+ // run-to-run. When two chunks tied on score for a given intent, the
108
+ // first-loaded won the tie-break — so the same intent could match
109
+ // chunk A in one process and chunk B in the next. Surfaced as
110
+ // ~40% probe-failure rate on admin-dashboard post-§143 (the new
111
+ // chunks compete with the original 4-row KPI composition).
112
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
113
+ .sort((a, b) => a.name.localeCompare(b.name));
114
+ for (const entry of entries) {
105
115
  const p = path.join(dir, entry.name);
106
116
  if (entry.isDirectory()) walk(p, cb);
107
117
  else if (entry.name.endsWith('.json') && !entry.name.startsWith('_')) cb(p);