@hviana/sema 0.4.7 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/AGENTS.md +290 -77
  2. package/HOW_IT_WORKS.md +2170 -735
  3. package/dist/example/train_base.d.ts +9 -3
  4. package/dist/example/train_base.js +21 -4
  5. package/dist/src/canon.d.ts +19 -0
  6. package/dist/src/canon.js +28 -0
  7. package/dist/src/geometry.d.ts +52 -0
  8. package/dist/src/geometry.js +87 -1
  9. package/dist/src/mind/attention.d.ts +15 -10
  10. package/dist/src/mind/attention.js +15 -10
  11. package/dist/src/mind/bridge.js +27 -1
  12. package/dist/src/mind/frame-filler.d.ts +15 -0
  13. package/dist/src/mind/frame-filler.js +535 -0
  14. package/dist/src/mind/learning.js +6 -11
  15. package/dist/src/mind/mechanisms/cast.js +72 -2
  16. package/dist/src/mind/mechanisms/cover.js +6 -1
  17. package/dist/src/mind/mechanisms/extraction.js +27 -0
  18. package/dist/src/mind/mechanisms/recall.js +214 -34
  19. package/dist/src/mind/mind.d.ts +52 -3
  20. package/dist/src/mind/mind.js +140 -12
  21. package/dist/src/mind/pipeline-mechanism.d.ts +7 -0
  22. package/dist/src/mind/pipeline.js +29 -1
  23. package/dist/src/mind/prefix-completion.d.ts +59 -0
  24. package/dist/src/mind/prefix-completion.js +270 -0
  25. package/dist/src/mind/primitives.d.ts +29 -10
  26. package/dist/src/mind/primitives.js +98 -71
  27. package/dist/src/mind/recognition.js +153 -26
  28. package/dist/src/mind/traverse.d.ts +32 -0
  29. package/dist/src/mind/traverse.js +52 -0
  30. package/dist/src/mind/types.d.ts +61 -18
  31. package/dist/src/mind/types.js +68 -19
  32. package/dist/src/store.d.ts +21 -0
  33. package/dist/src/store.js +21 -0
  34. package/example/train_base.ts +21 -4
  35. package/package.json +1 -1
  36. package/src/canon.ts +28 -0
  37. package/src/geometry.ts +100 -1
  38. package/src/mind/attention.ts +15 -10
  39. package/src/mind/bridge.ts +34 -0
  40. package/src/mind/frame-filler.ts +604 -0
  41. package/src/mind/learning.ts +5 -9
  42. package/src/mind/mechanisms/cast.ts +70 -2
  43. package/src/mind/mechanisms/cover.ts +6 -1
  44. package/src/mind/mechanisms/extraction.ts +27 -0
  45. package/src/mind/mechanisms/recall.ts +236 -37
  46. package/src/mind/mind.ts +166 -18
  47. package/src/mind/pipeline-mechanism.ts +7 -0
  48. package/src/mind/pipeline.ts +33 -1
  49. package/src/mind/prefix-completion.ts +314 -0
  50. package/src/mind/primitives.ts +105 -80
  51. package/src/mind/recognition.ts +151 -23
  52. package/src/mind/traverse.ts +52 -0
  53. package/src/mind/types.ts +104 -44
  54. package/src/store.ts +25 -0
  55. package/test/13-conversation.test.mjs +13 -0
  56. package/test/57-fusion-order.test.mjs +65 -0
  57. package/test/66-query-edge-whitespace.test.mjs +99 -0
  58. package/test/67-climb-anchor-breadth.test.mjs +113 -0
  59. package/test/68-extraction-unanchored.test.mjs +79 -0
  60. package/test/69-frame-filler.test.mjs +115 -0
  61. package/test/70-prefix-completion.test.mjs +170 -0
  62. package/test/71-embedded-canon-equivalence.test.mjs +121 -0
  63. package/test/72-prefix-candidate-supply.test.mjs +114 -0
  64. package/test/73-scaffolding-only-bridge-abstains.test.mjs +178 -0
  65. package/test/74-prefix-trap-not-sprung-early.test.mjs +114 -0
  66. package/test/75-multiturn-context-optimisation.test.mjs +1334 -0
@@ -0,0 +1,115 @@
1
+ // 69-frame-filler.test.mjs — the frame-filler tier must not fire without its
2
+ // evidence, and must refuse an ambiguous subject.
3
+ //
4
+ // WHAT THE MECHANISM DOES (src/mind/frame-filler.ts): when every other tier has
5
+ // declined, take the query's described span, put a corroborated filler from a
6
+ // trained context in its place, and require the STORE to already hold that key
7
+ // byte-exactly. "We invent a lookup KEY, never an answer" — the answer is the
8
+ // trained continuation of a form the store verifiably has.
9
+ //
10
+ // THE WIN IS REAL-STORE EVIDENCE, NOT A FIXTURE. On the 15.7M-node trained
11
+ // store, `What is the capital of the country where the Eiffel Tower is?` goes
12
+ // from silence to "The capital of France is Paris." (provenance `recall`), taking
13
+ // analyze_training.ts's section G from 33.3% to 66.7% and the battery from 73.8%
14
+ // to 76.2% with `0 weak` intact. A/B on warm caches: +50 ms on that query,
15
+ // +16 ms on a refusing query that runs 480 probes, and +0 ms on
16
+ // `What is the capital of Zamunda?` (guard 1 exits before probing) and on every
17
+ // query that answers earlier.
18
+ //
19
+ // WHY NO POSITIVE FIXTURE TEST EXISTS — measured, not assumed. The mechanism
20
+ // keys on corpus RARITY (container counts, the same reading the bridge's anchor
21
+ // picking uses). At fixture scale that signal is absent and even inverted: in a
22
+ // 21-deposit store `capital` reports 1 container and `landmark` reports 9, while
23
+ // on the trained store `Eiffel` is 54 against `What` at 1,586. So a fixture
24
+ // cannot make the query's rarest word land inside the description, which guard 1
25
+ // requires — three fixture shapes were tried (bare, 21-deposit, and one with an
26
+ // attested long word in the description) and none reached the positive path.
27
+ // What a fixture CAN pin is the refusal side, which is what this file does.
28
+
29
+ import { test } from "node:test";
30
+ import assert from "node:assert/strict";
31
+ import { Mind } from "../dist/src/index.js";
32
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
33
+ import { frameFillerSubstitution } from "../dist/src/mind/frame-filler.js";
34
+
35
+ const enc = (s) => new TextEncoder().encode(s);
36
+ const FRAME = [
37
+ ["What is the capital of France?", "Paris is the capital of France."],
38
+ ["What is the capital of Spain?", "Madrid is the capital of Spain."],
39
+ ["What is the capital of Italy?", "Rome is the capital of Italy."],
40
+ ["What is the capital of Japan?", "Tokyo is the capital of Japan."],
41
+ ];
42
+ const LINK = [
43
+ "What is the most famous landmark in France?",
44
+ "The most famous landmark in France is the Eiffel Tower.",
45
+ ];
46
+ const LINK2 = [
47
+ "What is the tallest structure in Spain?",
48
+ "The tallest structure in Spain is the Eiffel Tower.",
49
+ ];
50
+ const Q = "What is the capital of the country where the Eiffel Tower is?";
51
+
52
+ async function fixture(train) {
53
+ const mind = new Mind({
54
+ seed: 1,
55
+ store: new SQliteStore({ path: ":memory:" }),
56
+ });
57
+ await mind.ingest(train);
58
+ return mind;
59
+ }
60
+ /** Call the tier the way recall does: the query plus recall's ranked hit ids. */
61
+ async function tier(mind, q) {
62
+ const hits = await mind.store.resonate(mind.perceive(q).v, 24);
63
+ return frameFillerSubstitution(mind, enc(q), hits.map((h) => h.id));
64
+ }
65
+
66
+ test("1. no linking evidence — the tier does not fire", async () => {
67
+ // The frame is attested, but nothing in the store ties the description's
68
+ // content to any filler. Guard 1 has nothing to qualify.
69
+ const m = await fixture(FRAME);
70
+ assert.equal(await tier(m, Q), null);
71
+ await m.store.close();
72
+ });
73
+
74
+ test("2. an AMBIGUOUS subject is refused", async () => {
75
+ // Two trained contexts hold the description's content and each proposes a
76
+ // different filler. Guard 4: neither is licensed.
77
+ const m = await fixture([...FRAME, LINK, LINK2]);
78
+ assert.equal(await tier(m, Q), null);
79
+ await m.store.close();
80
+ });
81
+
82
+ test("3. an unrelated query never grounds a frame neighbour", async () => {
83
+ // The fabrication shape: a fictional filler in an attested frame. On the real
84
+ // store this query resolves 24 keys (Chile, India, Japan, Italy …) once the
85
+ // guards are weakened, so it is the case that most needs pinning.
86
+ const m = await fixture([...FRAME, LINK]);
87
+ for (
88
+ const q of [
89
+ "What is the capital of Zamunda?",
90
+ "xyzzy plugh quux baz?",
91
+ "qq8f3kz9 vv2m1x7w?",
92
+ ]
93
+ ) {
94
+ assert.equal(await tier(m, q), null, `expected refusal for ${q}`);
95
+ }
96
+ await m.store.close();
97
+ });
98
+
99
+ test("4. the tier is deterministic and side-effect free", async () => {
100
+ const m = await fixture([...FRAME, LINK]);
101
+ const a = await tier(m, Q);
102
+ const b = await tier(m, Q);
103
+ assert.deepEqual(a, b);
104
+ // Running it must not disturb the answers of forms that ground normally.
105
+ assert.match(await m.respondText("What is the capital of France?"), /Paris/);
106
+ await m.store.close();
107
+ });
108
+
109
+ test("5. end to end, the fixture's own trained forms still answer", async () => {
110
+ const m = await fixture([...FRAME, LINK]);
111
+ assert.match(await m.respondText("What is the capital of Spain?"), /Madrid/);
112
+ assert.match(await m.respondText("What is the capital of Japan?"), /Tokyo/);
113
+ assert.equal(await m.respondText("qq8f3kz9 vv2m1x7w?"), "");
114
+ await m.store.close();
115
+ });
@@ -0,0 +1,170 @@
1
+ // 70-prefix-completion.test.mjs — a query that IS the opening of one trained
2
+ // form is completed by that form's remainder; anything less is refused.
3
+ //
4
+ // WHAT THE MECHANISM DOES (src/mind/prefix-completion.ts): when every other
5
+ // tier has declined, scan the candidate list recall's refusal path has ALREADY
6
+ // fetched and look for a trained form whose bytes literally BEGIN with the whole
7
+ // query. The answer is that form's own remainder — never an invention.
8
+ //
9
+ // WHY IT IS NEEDED, measured on the 15.7M-node trained store:
10
+ // `The capital of France is` grounded nothing, while
11
+ // `The capital of France is Paris.` is trained and reads back byte-exact. Two
12
+ // independent reasons the earlier tiers cannot reach it:
13
+ // * `resolve(prefix)` is null — a proper prefix has no branch of its own.
14
+ // * the form is absent from `resonate(k)` at k = 24, 256 AND 2048, while forms
15
+ // scoring LOWER are returned (cos 0.5752 for the target against Germany
16
+ // 0.5670, Yemen 0.5591). `k` only reorders within the IVF clusters already
17
+ // probed, so no k recovers it; with `exhaustive` it ranks 8.
18
+ // It is a RETRIEVABILITY gap, not a semantic one.
19
+ //
20
+ // COST — A/B on the trained store, counting resonate calls directly: the tier
21
+ // adds ZERO exhaustive calls. F-prefix already made exactly one (for the
22
+ // substitution bridge) and returned silence; with the tier it makes the same one
23
+ // and answers. Battery: F 0% → 25%, overall 76.2% → 78.6%, `0 weak`, all three
24
+ // honest-silence probes still silent, median latency 0.63s → 0.57s.
25
+ //
26
+ // Unlike test/69, a POSITIVE fixture IS constructible here: the mechanism keys
27
+ // on literal byte containment, not on corpus rarity, and rarity is the signal
28
+ // that collapses at fixture scale.
29
+ //
30
+ // The mechanism has NO notion of text: no separator, no character class, no
31
+ // "word". Its only structural quantity is W, the river's grouping window. So
32
+ // these fixtures are readable prose only for the reader's benefit -- every
33
+ // assertion below is about bytes and geometry.
34
+
35
+ import { test } from "node:test";
36
+ import assert from "node:assert/strict";
37
+ import { Mind } from "../dist/src/index.js";
38
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
39
+ import { prefixCompletion } from "../dist/src/mind/prefix-completion.js";
40
+
41
+ const enc = (s) => new TextEncoder().encode(s);
42
+ const dec = new TextDecoder();
43
+
44
+ async function fixture(train) {
45
+ const mind = new Mind({
46
+ seed: 1,
47
+ store: new SQliteStore({ path: ":memory:" }),
48
+ });
49
+ await mind.ingest(train);
50
+ return mind;
51
+ }
52
+ /** Call the tier the way recall does: the query plus a ranked hit list. */
53
+ async function tier(mind, q, k = 64) {
54
+ const hits = await mind.store.resonate(mind.perceive(q).v, k);
55
+ return prefixCompletion(mind, enc(q), hits.map((h) => h.id));
56
+ }
57
+
58
+ const FACTS = [
59
+ "The capital of France is Paris.",
60
+ "The capital of Japan is Tokyo.",
61
+ "The capital of Germany is Berlin.",
62
+ ];
63
+
64
+ test("1. the sole form opening with the query is completed by its remainder", async () => {
65
+ const m = await fixture(FACTS);
66
+ const hit = await tier(m, "The capital of France is");
67
+ assert.notEqual(hit, null, "the trained form opens with the query");
68
+ assert.equal(dec.decode(hit.form), "The capital of France is Paris.");
69
+ await m.store.close();
70
+ });
71
+
72
+ test("2. AMBIGUITY is refused — the prefix trap", async () => {
73
+ // Two trained forms open with the same words and continue differently. The
74
+ // corpus does not say which completion the asker means, so neither is
75
+ // licensed. This is the documented prefix trap, and it is real — it simply
76
+ // does not hold for EVERY prefix, which is what test 1 pins.
77
+ const m = await fixture([
78
+ "The capital city is Paris.",
79
+ "The capital city is Berlin.",
80
+ ]);
81
+ assert.equal(await tier(m, "The capital city is"), null);
82
+ await m.store.close();
83
+ });
84
+
85
+ test("3. the same completion via two forms is ONE answer, not an ambiguity", async () => {
86
+ // Uniqueness is judged on the remainder BYTES, not on the candidate id.
87
+ const m = await fixture([
88
+ "The capital of France is Paris.",
89
+ "The capital of France is Paris.",
90
+ ]);
91
+ const hit = await tier(m, "The capital of France is");
92
+ assert.notEqual(hit, null);
93
+ assert.equal(dec.decode(hit.form), "The capital of France is Paris.");
94
+ await m.store.close();
95
+ });
96
+
97
+ test("4. a SUB-QUANTUM continuation is refused", async () => {
98
+ // Observed on the trained store: `What is the capital of France?` opens a
99
+ // trained `What is the capital of France??`, which continues by ONE byte.
100
+ // Below W the continuation is sub-quantum -- the fold groups nothing from it
101
+ // -- and voicing it is the degenerate reply of the battery's section M.
102
+ // The bar is the grouping window, not a punctuation class.
103
+ const m = await fixture(["What is the capital of France??"]);
104
+ assert.equal(await tier(m, "What is the capital of France?"), null);
105
+ await m.store.close();
106
+ });
107
+
108
+ test("5. a query no trained form opens with is refused", async () => {
109
+ const m = await fixture(FACTS);
110
+ for (
111
+ const q of [
112
+ "The capital of Zamunda is",
113
+ "xyzzy plugh quux",
114
+ "Paris is the capital of",
115
+ ]
116
+ ) {
117
+ assert.equal(await tier(m, q), null, q);
118
+ }
119
+ await m.store.close();
120
+ });
121
+
122
+ test("6. a query that is a whole trained form is not 'completed' by itself", async () => {
123
+ // An exact form has an EMPTY remainder, which no guard should let through —
124
+ // and the exact tiers own that query anyway.
125
+ const m = await fixture(FACTS);
126
+ assert.equal(await tier(m, "The capital of France is Paris."), null);
127
+ await m.store.close();
128
+ });
129
+
130
+ test("7. the tier is deterministic and side-effect free", async () => {
131
+ const m = await fixture(FACTS);
132
+ const q = "The capital of France is";
133
+ const before = m.store.nodeCount();
134
+ const a = await tier(m, q);
135
+ const b = await tier(m, q);
136
+ assert.equal(dec.decode(a.form), dec.decode(b.form));
137
+ assert.equal(a.id, b.id);
138
+ assert.equal(
139
+ m.store.nodeCount(),
140
+ before,
141
+ "the tier must not intern anything",
142
+ );
143
+ await m.store.close();
144
+ });
145
+
146
+ test("9. a form that continues past the read bound vetoes", async () => {
147
+ // Reads are bounded (query.length * W). A candidate that opens with the
148
+ // query but SATURATES the read continues out of sight, so it is a standing
149
+ // disagreement -- NOT something to skip. Skipping it is what manufactures a
150
+ // fragment: it removes the only evidence contradicting an interior fold node
151
+ // that happens to fit under the cap.
152
+ const q = "The capital of France is";
153
+ const long = q + " Paris, and the country's largest city by a wide margin, " +
154
+ "a global centre for art, fashion, gastronomy and culture.";
155
+ assert.ok(long.length > q.length * 4, "the fixture must exceed the cap");
156
+ const m = await fixture([long]);
157
+ assert.equal(await tier(m, q), null);
158
+ await m.store.close();
159
+ });
160
+
161
+ test("8. end to end, the fixture's own trained forms still answer", async () => {
162
+ // The tier sits on the refusal path; it must not disturb normal grounding.
163
+ const m = await fixture([
164
+ "What is the capital of France?",
165
+ "The capital of France is Paris.",
166
+ ]);
167
+ const r = await m.respond("What is the capital of France?");
168
+ assert.ok(r.bytes.length > 0, "a trained question still answers");
169
+ await m.store.close();
170
+ });
@@ -0,0 +1,121 @@
1
+ // 71-embedded-canon-equivalence.test.mjs — an EMBEDDED trained form must be
2
+ // recognised under the response's canonical equivalence, not only byte-exactly.
3
+ //
4
+ // The contract: `recognise` decomposes a query into stored forms that lead
5
+ // somewhere. A trained form sitting at an interior offset of a larger query is
6
+ // found by the scale-gated "exact query-edge forms" tier in recognition.ts.
7
+ // That tier admits candidates with a BYTE-EXACT `store.findBranch` probe over
8
+ // the query's leaf-id run, then calls the canon-capable `resolveSpan`. The
9
+ // prefilter is therefore strictly narrower than its own resolver: a form whose
10
+ // deposit differs from the query only by the response canonicalizer's
11
+ // equivalence (case, width) can never reach `resolveSpan`, because a
12
+ // differently-cased deposit's branch kid-ids are not the query's leaf-id run
13
+ // under ANY canonicalization of the query. Measured on a 15.7M-node store:
14
+ // "Hey, What is the process of photosynthesis?" recognises the trained form,
15
+ // "Hey, what is …" recognises nothing, though the lowercased form resolves
16
+ // exactly at offset 0.
17
+ //
18
+ // WHY THE 4.3k-FACT FIXTURE IS NOT OPTIONAL: the tier runs only when
19
+ // `atomIsHub(ctx, corpusN)` is true, i.e. N > ~4096 contexts at maxGroup=4.
20
+ // Every small-store suite exercises the OTHER branch of recognition, so a
21
+ // conventional fixture would pass while the defect is fully present. The
22
+ // atomIsHub assertion below fails loudly if that crossover ever moves, so this
23
+ // test can never silently stop covering the branch it exists for.
24
+ import { test } from "node:test";
25
+ import assert from "node:assert/strict";
26
+ import { Mind } from "../dist/src/index.js";
27
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
28
+ import { recognise } from "../dist/src/mind/recognition.js";
29
+ import { resolve } from "../dist/src/mind/primitives.js";
30
+ import { atomIsHub, corpusN } from "../dist/src/mind/traverse.js";
31
+ import { textCanon } from "../dist/src/canon.js";
32
+
33
+ const enc = (s) => new TextEncoder().encode(s);
34
+
35
+ // Longer than chainReach(W)=W²=16 bytes, or the tier's own size gate skips it.
36
+ const FORM = "Madam Your Glasses Are Fogged";
37
+ const PREFIX = "Hey, ";
38
+
39
+ /** Recognise with the canonicalizer a TEXT response would carry. `ctx.canon`
40
+ * is per-response state that `respond()` injects; calling `recognise`
41
+ * directly would otherwise run with canon disabled and test nothing. */
42
+ function recogniseAsText(mind, text) {
43
+ mind.canon = textCanon;
44
+ mind.canonMemo = new Map();
45
+ try {
46
+ return recognise(mind, enc(text));
47
+ } finally {
48
+ mind.canon = null;
49
+ mind.canonMemo = null;
50
+ }
51
+ }
52
+
53
+ const sitesFor = (rec, id) => rec.sites.filter((s) => s.payload === id);
54
+
55
+ test("an embedded trained form is recognised under canonical equivalence", async () => {
56
+ const m = new Mind({ seed: 7, store: new SQliteStore({ path: ":memory:" }) });
57
+
58
+ const filler = [];
59
+ for (let i = 0; i < 4300; i++) filler.push([`filler-${i}`, `f${i}`]);
60
+ await m.ingest(filler);
61
+ await m.ingest([[FORM, "a stored continuation for the form"]]);
62
+ // Canonical resolution reads a store-side index that training builds
63
+ // explicitly (meta `canon.upto`); without it `canonResolve` has no
64
+ // candidates and the equivalence under test does not exist at all.
65
+ await m.buildCanonIndex();
66
+
67
+ const N = corpusN(m);
68
+ assert.ok(
69
+ atomIsHub(m, N),
70
+ `fixture must cross atomIsHub (N=${N}); the tier under test is ` +
71
+ `scale-gated and this suite would otherwise assert nothing`,
72
+ );
73
+
74
+ const formId = resolve(m, enc(FORM));
75
+ assert.ok(formId !== null, "the trained form must resolve exactly");
76
+
77
+ // Control 1 — the form standalone, in its deposited case.
78
+ assert.ok(
79
+ sitesFor(recogniseAsText(m, FORM), formId).length > 0,
80
+ "standalone deposited-case form must be recognised",
81
+ );
82
+
83
+ // Control 2 — the form standalone, lowercased. This is what proves the
84
+ // canonical equivalence is REAL and reachable, so the embedded assertion
85
+ // below is about placement, not about the canonicalizer.
86
+ assert.ok(
87
+ sitesFor(recogniseAsText(m, FORM.toLowerCase()), formId).length > 0,
88
+ "lowercased form must resolve to the same node at offset 0",
89
+ );
90
+
91
+ // Control 3 — embedded, deposited case. The tier's byte-exact route.
92
+ assert.ok(
93
+ sitesFor(recogniseAsText(m, PREFIX + FORM), formId).length > 0,
94
+ "embedded deposited-case form must be recognised",
95
+ );
96
+
97
+ // THE CONTRACT — embedded AND canonically equivalent. Controls 2 and 3 each
98
+ // hold, so anything that fails here is the prefilter being narrower than its
99
+ // resolver, which is the defect this test exists to prevent.
100
+ const rec = recogniseAsText(m, PREFIX + FORM.toLowerCase());
101
+ const hit = sitesFor(rec, formId);
102
+ assert.ok(
103
+ hit.length > 0,
104
+ `embedded lowercased form must be recognised: standalone-lowercased and ` +
105
+ `embedded-exact both are, so the byte-exact admission gate is the only ` +
106
+ `thing rejecting it (sites found: ${
107
+ rec.sites.map((s) => `${s.start}-${s.end}`).join(",") || "none"
108
+ })`,
109
+ );
110
+ // It must be found AT its true offset, not as some other coincidental span.
111
+ assert.ok(
112
+ hit.some((s) =>
113
+ s.start === PREFIX.length && s.end === PREFIX.length + FORM.length
114
+ ),
115
+ `the form must be recognised at its own span [${PREFIX.length},${
116
+ PREFIX.length + FORM.length
117
+ }], got ${hit.map((s) => `${s.start}-${s.end}`).join(",")}`,
118
+ );
119
+
120
+ await m.store.close();
121
+ });
@@ -0,0 +1,114 @@
1
+ // 72-prefix-candidate-supply.test.mjs — a query that is a proper PREFIX of a
2
+ // trained form must be able to reach that form even when resonance cannot rank
3
+ // it.
4
+ //
5
+ // THE GAP THIS PINS. `prefixCompletion` consumes a ranked list the caller
6
+ // already fetched, and that list comes from resonance. Resonance cannot rank a
7
+ // proper prefix: measured on a 15.7M-node store, cos(prefix, form) falls from
8
+ // 0.9629 at a one-byte truncation to 0.6206 at three bytes, against a
9
+ // reachThreshold of 0.8750. The mechanism's guards were therefore never
10
+ // reached — the trace read `candidates: 24, opened: 0` — and the query answered
11
+ // nothing. `prefixCandidates` is the second SUPPLY that closes it, reading the
12
+ // leaf-id WINDOW index `indexSubSpans` already writes at deposit time. No
13
+ // ingestion, storage or fold change is involved: this test would pass on a
14
+ // store trained before the supply existed.
15
+ //
16
+ // WHY THE ASSERTIONS ARE SHAPED THIS WAY. On a small fixture resonance may
17
+ // well return the form by luck, and then an end-to-end "does it answer?" test
18
+ // would pass with the supply deleted — pinning nothing. So the contract is
19
+ // asserted on `prefixCandidates` DIRECTLY, and the resonance list is asserted
20
+ // to lack the form, which is what makes the supply load-bearing rather than
21
+ // redundant.
22
+ //
23
+ // The 4.3k-fact fixture is not decoration: window containment is judged against
24
+ // `hubBound` = √N, so a toy store makes every window look saturated and the
25
+ // supply would correctly return nothing, testing nothing.
26
+ import { test } from "node:test";
27
+ import assert from "node:assert/strict";
28
+ import { Mind } from "../dist/src/index.js";
29
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
30
+ import {
31
+ prefixCandidates,
32
+ prefixCompletion,
33
+ } from "../dist/src/mind/prefix-completion.js";
34
+ import { gistOf, resolve } from "../dist/src/mind/primitives.js";
35
+
36
+ const enc = (s) => new TextEncoder().encode(s);
37
+ const dec = new TextDecoder();
38
+
39
+ const FORM = "The chief export of the northern province is powdered basalt.";
40
+
41
+ test("a proper prefix reaches its trained form through the window supply", async () => {
42
+ const m = new Mind({ seed: 7, store: new SQliteStore({ path: ":memory:" }) });
43
+
44
+ const filler = [];
45
+ for (let i = 0; i < 4300; i++) filler.push([`filler-${i}`, `f${i}`]);
46
+ await m.ingest(filler);
47
+ await m.ingest([[FORM, "acknowledged"]]);
48
+
49
+ const formId = resolve(m, enc(FORM));
50
+ assert.ok(formId !== null, "the trained form must resolve exactly");
51
+
52
+ // Truncate by more than one grouping window, so the continuation clears
53
+ // prefixCompletion's sub-quantum guard and the tier can actually fire.
54
+ const W = m.space.maxGroup;
55
+ const query = enc(FORM.slice(0, FORM.length - 3 * W));
56
+
57
+ // Premise 1 — the exact tiers genuinely cannot serve this query.
58
+ assert.equal(
59
+ resolve(m, query),
60
+ null,
61
+ "a proper prefix must have no branch of its own, or the gap is not real",
62
+ );
63
+
64
+ // Premise 2 — resonance does not supply the form, so anything that works
65
+ // below is the new supply and not the ranked list in disguise.
66
+ // Premise 2 — the ranked list is NOT what is under test. At fixture scale
67
+ // resonance does rank the form (it is the only content among 4,300 fillers
68
+ // that resembles the query), and that is measured, not assumed: the
69
+ // assertion below records it, so if fixture geometry ever changes the reader
70
+ // is told rather than misled. Resonance's real-world inability to rank a
71
+ // prefix is a LARGE-CORPUS property — cos falls to 0.6206 at a three-byte
72
+ // truncation against a 0.8750 bar, on a 15.7M-node store — and cannot be
73
+ // reproduced at this scale. That is why the contract below is asserted on
74
+ // `prefixCandidates` DIRECTLY: deleting or emptying the supply fails this
75
+ // test regardless of what resonance happens to return.
76
+ const ranked = (await m.store.resonate(gistOf(m, query), 64)).map((h) =>
77
+ h.id
78
+ );
79
+ assert.ok(
80
+ ranked.includes(formId),
81
+ "fixture note: at this scale resonance is expected to rank the form; " +
82
+ "if it no longer does, the end-to-end path below became the load-" +
83
+ "bearing assertion and this comment must be revisited",
84
+ );
85
+
86
+ // THE CONTRACT — the write side's own window index proposes the form.
87
+ const proposed = prefixCandidates(m, query);
88
+ assert.ok(
89
+ proposed.includes(formId),
90
+ `the window supply must propose the trained form the query opens ` +
91
+ `(proposed ${proposed.length} candidate(s))`,
92
+ );
93
+
94
+ // …and the mechanism, unchanged, grounds it whole through that supply.
95
+ const completed = prefixCompletion(m, query, proposed);
96
+ assert.ok(completed !== null, "the supplied form must complete the query");
97
+ assert.equal(
98
+ dec.decode(completed.form),
99
+ FORM,
100
+ "a FORM is grounded whole, never a slice cut at the query's end",
101
+ );
102
+
103
+ // HONEST DEGRADATION (§2.13). A query with no discriminative window must
104
+ // propose nothing rather than guess — silence is the correct answer, and a
105
+ // supply that widened until it found something would be the real defect.
106
+ const hub = enc("The ");
107
+ assert.equal(
108
+ prefixCompletion(m, hub, prefixCandidates(m, hub)),
109
+ null,
110
+ "a query carrying no discriminative window must stay silent",
111
+ );
112
+
113
+ await m.store.close();
114
+ });