@hviana/sema 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.
Files changed (41) hide show
  1. package/AGENTS.md +114 -52
  2. package/HOW_IT_WORKS.md +275 -184
  3. package/dist/src/mind/bridge.d.ts +5 -7
  4. package/dist/src/mind/bridge.js +6 -97
  5. package/dist/src/mind/match.d.ts +159 -0
  6. package/dist/src/mind/match.js +300 -7
  7. package/dist/src/mind/mechanisms/prefix-completion.d.ts +22 -0
  8. package/dist/src/mind/{prefix-completion.js → mechanisms/prefix-completion.js} +64 -91
  9. package/dist/src/mind/mechanisms/recall.js +10 -108
  10. package/dist/src/mind/mechanisms/reference.d.ts +6 -0
  11. package/dist/src/mind/mechanisms/reference.js +296 -0
  12. package/dist/src/mind/mind.d.ts +1 -1
  13. package/dist/src/mind/pipeline-mechanism.d.ts +56 -1
  14. package/dist/src/mind/pipeline-mechanism.js +104 -3
  15. package/dist/src/mind/pipeline.d.ts +1 -1
  16. package/dist/src/mind/pipeline.js +13 -1
  17. package/dist/src/mind/traverse.d.ts +38 -0
  18. package/dist/src/mind/traverse.js +91 -1
  19. package/dist/src/store.d.ts +4 -4
  20. package/jsr.json +6 -0
  21. package/package.json +1 -1
  22. package/src/mind/bridge.ts +10 -104
  23. package/src/mind/match.ts +416 -7
  24. package/src/mind/{prefix-completion.ts → mechanisms/prefix-completion.ts} +66 -92
  25. package/src/mind/mechanisms/recall.ts +9 -126
  26. package/src/mind/mechanisms/reference.ts +343 -0
  27. package/src/mind/mind.ts +12 -8
  28. package/src/mind/pipeline-mechanism.ts +120 -3
  29. package/src/mind/pipeline.ts +16 -2
  30. package/src/mind/traverse.ts +92 -1
  31. package/src/store.ts +13 -4
  32. package/test/33-multi-candidate.test.mjs +21 -11
  33. package/test/70-prefix-completion.test.mjs +1 -1
  34. package/test/72-prefix-candidate-supply.test.mjs +7 -9
  35. package/test/74-prefix-trap-not-sprung-early.test.mjs +1 -1
  36. package/test/76-reference-binding.test.mjs +471 -0
  37. package/dist/src/mind/frame-filler.d.ts +0 -15
  38. package/dist/src/mind/frame-filler.js +0 -535
  39. package/dist/src/mind/prefix-completion.d.ts +0 -59
  40. package/src/mind/frame-filler.ts +0 -604
  41. package/test/69-frame-filler.test.mjs +0 -115
@@ -0,0 +1,471 @@
1
+ // 76-reference-binding.test.mjs — REFERENCE: voicing a slot with the
2
+ // context's own bytes.
3
+ //
4
+ // THE GAP THIS CLOSES. Sema is otherwise a fully GROUND system: every item of
5
+ // the deduction system, every matcher and every gate compares ground bytes.
6
+ // Nothing represents a POSITION whose occupant comes from the context rather
7
+ // than the corpus, so no mechanism can tell
8
+ //
9
+ // "the corpus does not explain these bytes" (PASS — refuse)
10
+ //
11
+ // apart from
12
+ //
13
+ // "these bytes occupy a place the corpus keeps open" (bind).
14
+ //
15
+ // Both arrive as unaligned residue. Asked `How do I compile main.c?` against a
16
+ // corpus that knows hello.c / server.c / parser.c, the engine returned SILENCE
17
+ // — while the corpus attests, three times over, exactly what to do with a name
18
+ // in that slot.
19
+ //
20
+ // WHY IT IS NOT A SUBSTITUTION. bridge.ts refuses this shape and is right to:
21
+ // `attestedQ` demands the query-side span be corpus-attested, because a
22
+ // substitution asserts EQUIVALENCE, and nothing can corroborate an equivalence
23
+ // claim about bytes the corpus has never seen. A reference asserts no
24
+ // equivalence. It asserts POSITION, and the bytes come from the asker, so
25
+ // voicing them cannot fabricate corpus knowledge. The only thing that can be
26
+ // fabricated is the RELATION claimed about them — the licence's whole subject.
27
+ //
28
+ // THE LICENCE, IN ONE BYTE PREDICATE (match.ts carriesFillers). For two
29
+ // instances i, j of one frame:
30
+ //
31
+ // substituteAll(cont_i, fillers_i -> fillers_j) == cont_j
32
+ //
33
+ // If it holds, the corpus attests byte-exactly that the continuation is a
34
+ // function of the fillers and nothing else. No threshold, no similarity, no
35
+ // new constant. Three readings, all pinned below:
36
+ //
37
+ // CARRIED the continuation quotes the fillers -> splice the referents
38
+ // ABSORBED the continuation is constant -> the same test, vacuously
39
+ // REFUSED the continuation carries filler-DEPENDENT content
40
+ //
41
+ // THE MEASURED FABRICATION THIS FORBIDS. On the trained 15.7M-node store,
42
+ // `What is the capital of Zamunda?` resonates to a PURE cohort — every one of
43
+ // the top 14 hits an instance of `What is the capital of X?` — with an
44
+ // unambiguous slot. Every structural gate passes; only the licence refuses,
45
+ // on `replace("Tokyo", "Japan" -> "France") != "Paris"`. That refusal is the
46
+ // only thing between this mechanism and invented capitals, so the FABRICATION
47
+ // tests here are not decoration.
48
+ //
49
+ // THE SLOT IS AN ALIGNMENT GAP, NOT "THE NOVEL PART". Two readings of novelty
50
+ // were measured and both fail as a delimiter:
51
+ // * "positions covered by no stored W-window" only BRACKETS the slot — it is
52
+ // dilated by up to W-1 at each edge (measured: `main.c?` for `main.c`), so
53
+ // splicing it carries the query's punctuation into the answer;
54
+ // * at corpus scale it does not fire at all — at 325,615 contexts every
55
+ // window of `Zamunda` and `flurbish` is already attested somewhere.
56
+ // The gap between the query and an instance of its frame IS the varying slot,
57
+ // contracted to its core: the mirror of the bridge, which EXPANDS a gap until
58
+ // the query side attests.
59
+ import { test } from "node:test";
60
+ import assert from "node:assert/strict";
61
+ import { Mind } from "../dist/src/index.js";
62
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
63
+ import { Precomputed } from "../dist/src/mind/pipeline-mechanism.js";
64
+ import { recognise } from "../dist/src/mind/recognition.js";
65
+ import { gistOf } from "../dist/src/mind/primitives.js";
66
+ import { bindReference } from "../dist/src/mind/mechanisms/reference.js";
67
+ import { frameSlots } from "../dist/src/mind/match.js";
68
+
69
+ const dec = new TextDecoder();
70
+ const clean = (b) => dec.decode((b ?? new Uint8Array()).filter((x) => x !== 0));
71
+
72
+ const mindWith = async (pairs) => {
73
+ const m = new Mind({ seed: 7, store: new SQliteStore({ path: ":memory:" }) });
74
+ await m.ingest(pairs);
75
+ return m;
76
+ };
77
+
78
+ /** The frame whose continuation QUOTES its filler. */
79
+ const CARRIED = [
80
+ ["How do I compile hello.c?", "Run gcc hello.c"],
81
+ ["How do I compile server.c?", "Run gcc server.c"],
82
+ ["How do I compile parser.c?", "Run gcc parser.c"],
83
+ ];
84
+
85
+ /** The frame whose continuation is CONSTANT across distinct fillers. */
86
+ const ABSORBED = [
87
+ ["What is the type of alpha?", "It is a variable."],
88
+ ["What is the type of beta?", "It is a variable."],
89
+ ["What is the type of delta?", "It is a variable."],
90
+ ];
91
+
92
+ /** The frame whose continuation depends on WHICH filler — no licence. */
93
+ const FABRICATION = [
94
+ ["What is the capital of France?", "Paris"],
95
+ ["What is the capital of Japan?", "Tokyo"],
96
+ ["What is the capital of Peru?", "Lima"],
97
+ ];
98
+
99
+ /** Two slots, both carried. */
100
+ const TWO_SLOT = [
101
+ ["Copy alpha.txt to beta.txt please", "cp alpha.txt beta.txt"],
102
+ ["Copy gamma.txt to delta.txt please", "cp gamma.txt delta.txt"],
103
+ ["Copy sigma.txt to omega.txt please", "cp sigma.txt omega.txt"],
104
+ ];
105
+
106
+ // ── THE SHARED REPRESENTATION ──────────────────────────────────────────────
107
+ //
108
+ // The slot notion is machinery, not one mechanism's private reading. It lives
109
+ // on Precomputed, reachable by ANY mechanism, and it reports an INVENTORY
110
+ // rather than electing a frame — a slot is a property of a PAIRING, not of the
111
+ // query, and committing to one reading in the shared container would push
112
+ // whichever consumer asked first onto every other.
113
+
114
+ test("the frame inventory REPORTS without judging", async () => {
115
+ // The shared reading must be usable by consumers other than this one, and
116
+ // that is not a matter of where the code sits — it is a matter of what the
117
+ // code hides. Four real pairings, only ONE of which reference can voice:
118
+ // every one must come back, correctly typed, so another consumer can apply
119
+ // its own reading.
120
+ //
121
+ // Measured before the gates were moved out of frameSlots: three of these
122
+ // four were reported as NOTHING, including a definite description standing
123
+ // where a proper noun stands — the shape the frame filler exists for. A
124
+ // shared layer with one usable consumer is private code at a public address.
125
+ const m = await mindWith([
126
+ ["What is the capital of France?", "Paris is the capital of France."],
127
+ ]);
128
+ const enc = (t) => new TextEncoder().encode(t);
129
+ const q = enc(
130
+ "What is the capital of the country where the " +
131
+ "Eiffel Tower is?",
132
+ );
133
+ const cand = enc("What is the capital of France?");
134
+
135
+ // 1. A SUBSTITUTION reference cannot voice: the varying part dwarfs the
136
+ // frame (covered 23 of 61), so `voiceable` refuses it — but the matcher
137
+ // must still report it.
138
+ const inst = frameSlots(m, q, cand, 1);
139
+ assert.ok(inst !== null, "the pairing was hidden");
140
+ assert.equal(inst.slots.length, 1);
141
+ assert.equal(inst.slots[0].kind, "substitution");
142
+ assert.equal(
143
+ clean(q.subarray(inst.slots[0].qs, inst.slots[0].qe)),
144
+ "the country where the Eiffel Tower is",
145
+ );
146
+ assert.equal(clean(inst.slots[0].filler), "France");
147
+ assert.equal(inst.covered, 23, "coverage must be reported, not judged");
148
+
149
+ // 2. An INSERTION — a real variation, and not a slot anything can carry.
150
+ const ins = frameSlots(
151
+ m,
152
+ enc("What is the capital of France, really?"),
153
+ cand,
154
+ 1,
155
+ );
156
+ assert.equal(ins.slots[0].kind, "insertion");
157
+ assert.equal(clean(new Uint8Array(ins.slots[0].filler)), "");
158
+
159
+ // 3. A DELETION, likewise.
160
+ const del = frameSlots(m, enc("What is the capital of Fran?"), cand, 1);
161
+ assert.equal(del.slots[0].kind, "deletion");
162
+ assert.equal(clean(del.slots[0].filler), "ce");
163
+
164
+ await m.store.close();
165
+ });
166
+
167
+ test("the inventory is shared, lazy, and elects no frame", async () => {
168
+ const m = await mindWith(CARRIED);
169
+ const q = new TextEncoder().encode("How do I compile main.c?");
170
+ m.beginResponse(undefined, null);
171
+ try {
172
+ m._edgeGuide = gistOf(m, q);
173
+ const pre = new Precomputed(m, q, recognise(m, q), [], m._edgeGuide);
174
+ const inventory = await pre.frames();
175
+ assert.ok(inventory.length >= 2, "no instances reported");
176
+ for (const inst of inventory) {
177
+ assert.ok(!("chosen" in inst), "the inventory must not elect");
178
+ assert.equal(typeof inst.covered, "number");
179
+ }
180
+ assert.equal(
181
+ new Set(inventory.map((i) => i.id)).size,
182
+ inventory.length,
183
+ "instances must stay distinct so a consumer can group them",
184
+ );
185
+ // Computed once and shared, not per-consumer.
186
+ assert.equal(await pre.frames(), inventory);
187
+ } finally {
188
+ m.endResponse(q.length);
189
+ }
190
+ await m.store.close();
191
+ });
192
+
193
+ // ── THE NEED ───────────────────────────────────────────────────────────────
194
+
195
+ test("CARRIED: the asker's name is voiced through the frame's own answer", async () => {
196
+ const m = await mindWith(CARRIED);
197
+ const r = await m.respond("How do I compile main.c?");
198
+ assert.equal(clean(r.bytes).trim(), "Run gcc main.c");
199
+ assert.equal(r.provenance, "reference");
200
+ await m.store.close();
201
+ });
202
+
203
+ test("CARRIED: the answer voices the ASKER's bytes, never the corpus's", async () => {
204
+ // The regression that matters most. The engine's nearest behaviour on this
205
+ // shape is to voice the CORPUS's filler — a confident misreference, worse
206
+ // than silence. Measured live on the trained store: `How do you say
207
+ // 'flurbish' in French?` answers "the way to say hello is \"Bonjour\"".
208
+ const m = await mindWith(CARRIED);
209
+ const out = clean((await m.respond("How do I compile main.c?")).bytes);
210
+ assert.match(out, /main\.c/);
211
+ for (const foreign of ["hello", "server", "parser"]) {
212
+ assert.ok(
213
+ !out.includes(foreign),
214
+ `answer named the corpus's filler ${foreign}: ${JSON.stringify(out)}`,
215
+ );
216
+ }
217
+ await m.store.close();
218
+ });
219
+
220
+ test("ABSORBED: a filler-independent answer is licensed by the same test", async () => {
221
+ const m = await mindWith(ABSORBED);
222
+ const r = await m.respond("What is the type of gamma?");
223
+ assert.equal(clean(r.bytes).trim(), "It is a variable.");
224
+ assert.equal(r.provenance, "reference");
225
+ await m.store.close();
226
+ });
227
+
228
+ test("the carriage may be structural, not just a copy", async () => {
229
+ // With the slot contracted to its varying core the filler is the BASENAME,
230
+ // carried to two places in the answer. Refusing this would refuse evidence
231
+ // the corpus actually holds.
232
+ const m = await mindWith([
233
+ ["How do I compile hello.c?", "Run gcc hello.c -o hello"],
234
+ ["How do I compile server.c?", "Run gcc server.c -o server"],
235
+ ["How do I compile parser.c?", "Run gcc parser.c -o parser"],
236
+ ]);
237
+ const r = await m.respond("How do I compile main.c?");
238
+ assert.equal(clean(r.bytes).trim(), "Run gcc main.c -o main");
239
+ await m.store.close();
240
+ });
241
+
242
+ // ── SEVERAL REFERENTS AT ONCE ──────────────────────────────────────────────
243
+ //
244
+ // A query may name more than one new thing, and a frame with two slots is not
245
+ // two frames. The licence generalises without weakening because it tests the
246
+ // WHOLE substitution at once.
247
+
248
+ test("TWO referents are bound together", async () => {
249
+ const m = await mindWith(TWO_SLOT);
250
+ const r = await m.respond("Copy input.txt to output.txt please");
251
+ assert.equal(clean(r.bytes).trim(), "cp input.txt output.txt");
252
+ assert.equal(r.provenance, "reference");
253
+ await m.store.close();
254
+ });
255
+
256
+ test("THREE referents, one of them carried to two places", async () => {
257
+ const m = await mindWith([
258
+ [
259
+ "Move alpha.txt from aaaa to bbbb now",
260
+ "mv aaaa/alpha.txt bbbb/alpha.txt",
261
+ ],
262
+ [
263
+ "Move gamma.txt from cccc to dddd now",
264
+ "mv cccc/gamma.txt dddd/gamma.txt",
265
+ ],
266
+ [
267
+ "Move sigma.txt from eeee to ffff now",
268
+ "mv eeee/sigma.txt ffff/sigma.txt",
269
+ ],
270
+ ]);
271
+ const r = await m.respond("Move input.txt from gggg to hhhh now");
272
+ assert.equal(clean(r.bytes).trim(), "mv gggg/input.txt hhhh/input.txt");
273
+ await m.store.close();
274
+ });
275
+
276
+ test("MULTI-SLOT licence: inventing around one slot refuses the whole binding", async () => {
277
+ // The command tracks both fillers, but the warning COUNT tracks neither — it
278
+ // is knowledge about the specific pair, which the store cannot have for a new
279
+ // one. One slot behaving is not a licence.
280
+ const m = await mindWith([
281
+ ["Compile hello.c with clang please", "clang hello.c gives 3 warnings"],
282
+ ["Compile server.c with rustc please", "rustc server.c gives 7 warnings"],
283
+ ["Compile parser.c with swiftc please", "swiftc parser.c gives 1 warnings"],
284
+ ]);
285
+ const r = await m.respond("Compile main.c with zigcc please");
286
+ assert.notEqual(r.provenance, "reference");
287
+ assert.ok(
288
+ !/\d+ warnings/.test(clean(r.bytes)),
289
+ `invented a warning count: ${JSON.stringify(clean(r.bytes))}`,
290
+ );
291
+ await m.store.close();
292
+ });
293
+
294
+ // ── THE LICENCE: what must NEVER be voiced ─────────────────────────────────
295
+
296
+ test("FABRICATION: a filler-DEPENDENT answer is refused", async () => {
297
+ const m = await mindWith(FABRICATION);
298
+ const r = await m.respond("What is the capital of Zamunda?");
299
+ const out = clean(r.bytes).trim();
300
+ assert.notEqual(r.provenance, "reference");
301
+ for (const city of ["Paris", "Tokyo", "Lima"]) {
302
+ assert.ok(
303
+ !out.includes(city),
304
+ `invented a capital for a place the corpus never saw: ${
305
+ JSON.stringify(out)
306
+ }`,
307
+ );
308
+ }
309
+ await m.store.close();
310
+ });
311
+
312
+ test("INCONSISTENT CARRIAGE: one instance breaking the pattern refuses all", async () => {
313
+ const m = await mindWith([
314
+ ["How do I compile hello.c?", "Run gcc hello.c -o out"],
315
+ ["How do I compile server.c?", "Run gcc server.c -o server"],
316
+ ["How do I compile parser.c?", "Run gcc parser.c -o parser"],
317
+ ]);
318
+ const r = await m.respond("How do I compile main.c?");
319
+ assert.notEqual(r.provenance, "reference");
320
+ assert.ok(
321
+ !/main\.c -o (main|out|server|parser)/.test(clean(r.bytes)),
322
+ `voiced an unattested carriage: ${JSON.stringify(clean(r.bytes))}`,
323
+ );
324
+ await m.store.close();
325
+ });
326
+
327
+ test("ONE INSTANCE: agreement needs two — a lone exemplar licenses nothing", async () => {
328
+ const m = await mindWith([
329
+ ["How do I compile hello.c?", "Run gcc hello.c"],
330
+ ["What is the capital of France?", "Paris"],
331
+ ]);
332
+ const r = await m.respond("How do I compile main.c?");
333
+ assert.notEqual(r.provenance, "reference");
334
+ await m.store.close();
335
+ });
336
+
337
+ test("the window floor applies PER SLOT, not to the query", async () => {
338
+ // `gcc` / `zig` are three bytes — under one river window, where byte overlap
339
+ // is chance. The first slot is a good referent; the second is not, and one
340
+ // bad slot refuses the binding rather than being dropped.
341
+ const m = await mindWith([
342
+ ["How do I compile hello.c with gcc?", "Run gcc hello.c"],
343
+ ["How do I compile server.c with tcc?", "Run tcc server.c"],
344
+ ["How do I compile parser.c with zcc?", "Run zcc parser.c"],
345
+ ]);
346
+ const r = await m.respond("How do I compile main.c with zig?");
347
+ assert.notEqual(r.provenance, "reference");
348
+ await m.store.close();
349
+ });
350
+
351
+ test("two slots naming the SAME bytes are ambiguous, not a binding", async () => {
352
+ // Which occurrence in the answer stands for which slot? Nothing says.
353
+ const m = await mindWith(TWO_SLOT);
354
+ const r = await m.respond("Copy input.txt to input.txt please");
355
+ assert.notEqual(r.provenance, "reference");
356
+ await m.store.close();
357
+ });
358
+
359
+ // ── THE FLOW ───────────────────────────────────────────────────────────────
360
+
361
+ test("post-grounding does not pivot PAST a binding", async () => {
362
+ // A bound answer is a byte string this mechanism CONSTRUCTED; the corpus
363
+ // never said it, so pivoting through it treats the engine's own construction
364
+ // as a trained fact — and here it also throws the answer away.
365
+ //
366
+ // Measured before `complete`: this answered "then execute ./a.out" — the
367
+ // referent gone AND the question unanswered.
368
+ const m = await mindWith([
369
+ ...CARRIED,
370
+ ["Run gcc main.c", "then execute ./a.out"],
371
+ ]);
372
+ const r = await m.respond("How do I compile main.c?");
373
+ assert.equal(clean(r.bytes).trim(), "Run gcc main.c");
374
+ assert.equal(r.provenance, "reference");
375
+ await m.store.close();
376
+ });
377
+
378
+ test("a referent may not be lifted out of the engine's OWN reply", async () => {
379
+ // Quoting a completed answer back as a referent launders the engine's output
380
+ // into evidence — the same rule the weave applies when it aligns only the
381
+ // asker's stream. Driven at the guard itself: the same query binds or
382
+ // refuses purely on whether the SLOT falls inside an answered span, so the
383
+ // control proves the refusal is the guard's doing and not an accident.
384
+ const m = await mindWith(CARRIED);
385
+ const q = new TextEncoder().encode("How do I compile main.c?");
386
+ const bind = async (answeredSpans) => {
387
+ m.beginResponse(undefined, null);
388
+ try {
389
+ m._edgeGuide = gistOf(m, q);
390
+ m.answeredSpans = answeredSpans;
391
+ const pre = new Precomputed(m, q, recognise(m, q), [], m._edgeGuide);
392
+ return await bindReference(m, q, pre);
393
+ } finally {
394
+ m.answeredSpans = [];
395
+ m.endResponse(q.length);
396
+ }
397
+ };
398
+ // The slot is "main" at 17-21 (see the inventory test above).
399
+ assert.equal(await bind([[16, 24]]), null, "bound out of its own reply");
400
+ const control = await bind([[0, 4]]);
401
+ assert.ok(control !== null, "the control did not bind");
402
+ assert.equal(clean(control.bytes).trim(), "Run gcc main.c");
403
+ await m.store.close();
404
+ });
405
+
406
+ // ── NO HIJACK ──────────────────────────────────────────────────────────────
407
+
408
+ test("a trained query is answered by its own edge, not by reference", async () => {
409
+ const m = await mindWith(CARRIED);
410
+ const r = await m.respond("How do I compile server.c?");
411
+ assert.equal(clean(r.bytes).trim(), "Run gcc server.c");
412
+ assert.notEqual(r.provenance, "reference");
413
+ await m.store.close();
414
+ });
415
+
416
+ test("honest silence survives: nothing relates, nothing is bound", async () => {
417
+ const m = await mindWith(CARRIED);
418
+ for (const q of ["xyzzy plugh quux baz?", "qq8f3kz9 vv2m1x7w?"]) {
419
+ const r = await m.respond(q);
420
+ assert.equal(clean(r.bytes).trim(), "", `expected silence for ${q}`);
421
+ }
422
+ await m.store.close();
423
+ });
424
+
425
+ test("the binding is deterministic", async () => {
426
+ const m = await mindWith(CARRIED);
427
+ const a = (await m.respond("How do I compile main.c?")).bytes;
428
+ const b = (await m.respond("How do I compile main.c?")).bytes;
429
+ assert.deepEqual([...a], [...b]);
430
+ await m.store.close();
431
+ });
432
+
433
+ // ── GENERIC: bytes, not text ───────────────────────────────────────────────
434
+
435
+ test("reference is a BYTE mechanism — no text, no canon, no character class", async () => {
436
+ // The same shape in a modality with no words, no case and no punctuation: a
437
+ // fixed byte frame with a varying region, carried into the reply. Nothing in
438
+ // the mechanism may consult what a byte MEANS.
439
+ const F = (region) =>
440
+ Uint8Array.from([0x01, 0x02, 0x03, 0x04, ...region, 0xfe, 0xff]);
441
+ const A = (region) => Uint8Array.from([0x10, 0x11, 0x12, 0x13, ...region]);
442
+ const m = new Mind({ seed: 7, store: new SQliteStore({ path: ":memory:" }) });
443
+ await m.ingest([
444
+ [F([0x41, 0x42, 0x43, 0x44, 0x45]), A([0x41, 0x42, 0x43, 0x44, 0x45])],
445
+ [F([0x51, 0x52, 0x53, 0x54, 0x55]), A([0x51, 0x52, 0x53, 0x54, 0x55])],
446
+ [F([0x61, 0x62, 0x63, 0x64, 0x65]), A([0x61, 0x62, 0x63, 0x64, 0x65])],
447
+ ]);
448
+ const novel = [0x71, 0x72, 0x73, 0x74, 0x75];
449
+ const r = await m.respond(F(novel));
450
+ assert.deepEqual([...r.bytes], [...A(novel)]);
451
+ assert.equal(r.provenance, "reference");
452
+ await m.store.close();
453
+ });
454
+
455
+ // ── OPTIMIZED ──────────────────────────────────────────────────────────────
456
+
457
+ test("the frame inventory and recall share ONE resonance call", async () => {
458
+ // Precomputed.resonance() is the response's one top-k read. Before it
459
+ // existed, a query reaching both paid two identical ANN queries.
460
+ const m = new Mind({
461
+ seed: 7,
462
+ store: new SQliteStore({ path: ":memory:" }),
463
+ profile: true,
464
+ });
465
+ await m.ingest(FABRICATION); // refuses, so BOTH mechanisms run to the end
466
+ await m.respond("What is the capital of Zamunda?");
467
+ const phase = m.lastCost.phases["resonance"];
468
+ assert.ok(phase, "the shared resonance phase never ran");
469
+ assert.equal(phase.calls, 1, "the shared resonance ran more than once");
470
+ await m.store.close();
471
+ });
@@ -1,15 +0,0 @@
1
- import type { MindContext } from "./types.js";
2
- /** A grounded frame-filler substitution: the stored form the constructed key
3
- * resolved to, and the spans that explain how it was reached. */
4
- export interface FrameFillerHit {
5
- /** The trained form the key resolved to — grounded through its own edge. */
6
- id: number;
7
- /** `[start, end)` of the query span the filler stood in for. */
8
- described: [number, number];
9
- /** The filler's bytes, for the rationale trace. */
10
- filler: Uint8Array;
11
- }
12
- /** Find the query's own most discriminative unit and the trained contexts that
13
- * hold it, then try the store for the query with a candidate filler in the
14
- * described span's place. Returns the sole surviving stored form, or null. */
15
- export declare function frameFillerSubstitution(ctx: MindContext, query: Uint8Array, ranked: ReadonlyArray<number>): FrameFillerHit | null;