@hviana/sema 0.1.0

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 (110) hide show
  1. package/AGENTS.md +470 -0
  2. package/AUTHORS.md +12 -0
  3. package/COMMERCIAL-LICENSE.md +19 -0
  4. package/CONTRIBUTING.md +15 -0
  5. package/HOW_IT_WORKS.md +4210 -0
  6. package/LICENSE.md +117 -0
  7. package/README.md +290 -0
  8. package/TRADEMARKS.md +19 -0
  9. package/example/demo.ts +46 -0
  10. package/example/train_base.ts +2675 -0
  11. package/index.html +893 -0
  12. package/package.json +25 -0
  13. package/src/alphabet.ts +34 -0
  14. package/src/alu/README.md +332 -0
  15. package/src/alu/src/alu.ts +541 -0
  16. package/src/alu/src/expr.ts +339 -0
  17. package/src/alu/src/index.ts +115 -0
  18. package/src/alu/src/kernel-arith.ts +377 -0
  19. package/src/alu/src/kernel-bits.ts +199 -0
  20. package/src/alu/src/kernel-logic.ts +102 -0
  21. package/src/alu/src/kernel-nd.ts +235 -0
  22. package/src/alu/src/kernel-numeric.ts +466 -0
  23. package/src/alu/src/operation.ts +344 -0
  24. package/src/alu/src/parser.ts +574 -0
  25. package/src/alu/src/resonance.ts +161 -0
  26. package/src/alu/src/text.ts +83 -0
  27. package/src/alu/src/value.ts +327 -0
  28. package/src/alu/test/alu.test.ts +1004 -0
  29. package/src/bytes.ts +62 -0
  30. package/src/config.ts +227 -0
  31. package/src/derive/README.md +295 -0
  32. package/src/derive/src/deduction.ts +263 -0
  33. package/src/derive/src/index.ts +24 -0
  34. package/src/derive/src/priority-queue.ts +70 -0
  35. package/src/derive/src/rewrite.ts +127 -0
  36. package/src/derive/src/trie.ts +242 -0
  37. package/src/derive/test/derive.test.ts +137 -0
  38. package/src/extension.ts +42 -0
  39. package/src/geometry.ts +511 -0
  40. package/src/index.ts +38 -0
  41. package/src/ingest-cache.ts +224 -0
  42. package/src/mind/articulation.ts +137 -0
  43. package/src/mind/attention.ts +1061 -0
  44. package/src/mind/canonical.ts +107 -0
  45. package/src/mind/graph-search.ts +1100 -0
  46. package/src/mind/index.ts +18 -0
  47. package/src/mind/junction.ts +347 -0
  48. package/src/mind/learning.ts +246 -0
  49. package/src/mind/match.ts +507 -0
  50. package/src/mind/mechanisms/alu.ts +33 -0
  51. package/src/mind/mechanisms/cast.ts +568 -0
  52. package/src/mind/mechanisms/confluence.ts +268 -0
  53. package/src/mind/mechanisms/cover.ts +248 -0
  54. package/src/mind/mechanisms/extraction.ts +422 -0
  55. package/src/mind/mechanisms/recall.ts +241 -0
  56. package/src/mind/mind.ts +483 -0
  57. package/src/mind/pipeline-mechanism.ts +326 -0
  58. package/src/mind/pipeline.ts +300 -0
  59. package/src/mind/primitives.ts +201 -0
  60. package/src/mind/rationale.ts +275 -0
  61. package/src/mind/reasoning.ts +198 -0
  62. package/src/mind/recognition.ts +234 -0
  63. package/src/mind/resonance.ts +0 -0
  64. package/src/mind/trace.ts +108 -0
  65. package/src/mind/traverse.ts +556 -0
  66. package/src/mind/types.ts +281 -0
  67. package/src/rabitq-hnsw/README.md +303 -0
  68. package/src/rabitq-hnsw/src/database.ts +492 -0
  69. package/src/rabitq-hnsw/src/heap.ts +90 -0
  70. package/src/rabitq-hnsw/src/hnsw.ts +514 -0
  71. package/src/rabitq-hnsw/src/index.ts +15 -0
  72. package/src/rabitq-hnsw/src/prng.ts +39 -0
  73. package/src/rabitq-hnsw/src/rabitq.ts +308 -0
  74. package/src/rabitq-hnsw/src/store.ts +994 -0
  75. package/src/rabitq-hnsw/test/hnsw.test.ts +1213 -0
  76. package/src/store-sqlite.ts +928 -0
  77. package/src/store.ts +2148 -0
  78. package/src/vec.ts +124 -0
  79. package/test/00-extract.test.mjs +151 -0
  80. package/test/01-floor.test.mjs +20 -0
  81. package/test/02-roundtrip.test.mjs +83 -0
  82. package/test/03-recall.test.mjs +98 -0
  83. package/test/04-think.test.mjs +627 -0
  84. package/test/05-concepts.test.mjs +84 -0
  85. package/test/08-storage.test.mjs +948 -0
  86. package/test/09-edges.test.mjs +65 -0
  87. package/test/11-universality.test.mjs +180 -0
  88. package/test/13-conversation.test.mjs +228 -0
  89. package/test/14-scaling.test.mjs +503 -0
  90. package/test/15-decomposition-gap.test.mjs +0 -0
  91. package/test/16-bridge.test.mjs +250 -0
  92. package/test/17-intelligence.test.mjs +240 -0
  93. package/test/18-alu.test.mjs +209 -0
  94. package/test/19-nd.test.mjs +254 -0
  95. package/test/20-stability.test.mjs +489 -0
  96. package/test/21-partial.test.mjs +158 -0
  97. package/test/22-multihop.test.mjs +130 -0
  98. package/test/23-rationale.test.mjs +316 -0
  99. package/test/24-generalization.test.mjs +416 -0
  100. package/test/25-embedding.test.mjs +75 -0
  101. package/test/26-cooperative.test.mjs +89 -0
  102. package/test/27-saturation-drop.test.mjs +637 -0
  103. package/test/28-unknowable.test.mjs +88 -0
  104. package/test/29-counterfactual.test.mjs +476 -0
  105. package/test/30-conflict-resolution.test.mjs +166 -0
  106. package/test/31-audit.test.mjs +288 -0
  107. package/test/32-confluence.test.mjs +173 -0
  108. package/test/33-multi-candidate.test.mjs +222 -0
  109. package/test/34-cross-region.test.mjs +252 -0
  110. package/tsconfig.json +16 -0
@@ -0,0 +1,250 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { Mind } from "../dist/src/index.js";
4
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
5
+
6
+ // =========================================================================
7
+ // THE BRIDGE — synthesising the connector between rewritten parts
8
+ // =========================================================================
9
+ //
10
+ // When `think` rewrites several parts of a query at once, it must decide how to
11
+ // JOIN the results. The connector between two rewrites is NOT simply the bytes
12
+ // the query had between the originals: after a rewrite, the asker's connector
13
+ // may no longer make sense, may be missing entirely, or may need to become
14
+ // something the asker never wrote.
15
+ //
16
+ // The bridge is the heart of the algorithm, not a special case. Whenever parts
17
+ // are rewritten, the graph is consulted for how the RESULTS cohere. Three
18
+ // outcomes, all decided by the graph, never assumed:
19
+ //
20
+ // • nothing — the results stand adjacent with no connector;
21
+ // • the input's — the query's own connector still coheres, so it is kept;
22
+ // • a synthesised one — the graph learned a connector between the results
23
+ // (a space, a ".", or a whole phrase), so it is inserted
24
+ // even though the asker never wrote it.
25
+ //
26
+ // The synthesised case is what these tests pin down. A previous refactor, with
27
+ // no test guarding it, silently dropped synthesis — "icefire" answered
28
+ // "coldhot" with the two rewrites run together, even when the store had learned
29
+ // how "cold" and "hot" connect. That is the regression these tests forbid.
30
+ //
31
+ // The graph signal: resonate the bare concatenation of the two result spans;
32
+ // if a learned form both BEGINS WITH the left result and ENDS WITH the right,
33
+ // the bytes in between are the learned connector. No learned form ⇒ no
34
+ // connector invented (strangers do not get a spurious phrase).
35
+
36
+ const mk = () => new Mind({ seed: 7 });
37
+
38
+ // ── 1. Synthesise a word connector the asker never wrote ─────────────────
39
+ // "ice"→"cold", "fire"→"hot" are independent facts; the store SEPARATELY
40
+ // learned the experience "cold or hot". Asking the two together — with no
41
+ // usable connector between them ("icefire") — must reconstruct the learned
42
+ // join, answering "cold or hot", not "coldhot".
43
+ test("bridge synthesises a learned word connector between rewrites", async () => {
44
+ const m = mk();
45
+ await m.ingest([["ice", "cold"], ["fire", "hot"]]);
46
+ await m.ingest("cold or hot"); // the graph learns how the answers connect
47
+ const r = await m.respondText("icefire");
48
+ assert.equal(r, "cold or hot");
49
+ await m.store.close();
50
+ });
51
+
52
+ // ── 2. Synthesise a whole-phrase connector ───────────────────────────────
53
+ // The connector can be anything the graph learned, not just punctuation.
54
+ test("bridge synthesises a learned phrase connector", async () => {
55
+ const m = mk();
56
+ await m.ingest([["sky", "blue"], ["grass", "green"]]);
57
+ await m.ingest("blue is the opposite of green");
58
+ const r = await m.respondText("skygrass");
59
+ assert.equal(r, "blue is the opposite of green");
60
+ await m.store.close();
61
+ });
62
+
63
+ // ── 3. No learned connection ⇒ no connector invented ─────────────────────
64
+ // Synthesis is graph-evidenced, never guessed. Without a learned join the two
65
+ // rewrites simply abut — the bridge must not hallucinate a phrase.
66
+ test("bridge invents nothing when the graph learned no connection", async () => {
67
+ const m = mk();
68
+ await m.ingest([["ice", "cold"], ["fire", "hot"]]);
69
+ const r = await m.respondText("icefire");
70
+ // Both answers present, adjacent, with no fabricated linking text.
71
+ assert.ok(r.includes("cold") && r.includes("hot"));
72
+ assert.ok(
73
+ !r.includes(" or ") && !r.includes(" is "),
74
+ `no connector should be invented, got ${JSON.stringify(r)}`,
75
+ );
76
+ await m.store.close();
77
+ });
78
+
79
+ // ── 4. The asker's own connector is kept when it still coheres ───────────
80
+ // Synthesis must not override a perfectly good input connector. "ice, fire"
81
+ // with the comma intact stays "cold, hot".
82
+ test("bridge keeps the asker's connector when it coheres", async () => {
83
+ const m = mk();
84
+ await m.ingest([["ice", "cold"], ["fire", "hot"]]);
85
+ const r = await m.respondText("ice, fire");
86
+ assert.ok(
87
+ r.includes("cold") && r.includes("hot") && r.includes(","),
88
+ `the asker's comma should survive, got ${JSON.stringify(r)}`,
89
+ );
90
+ await m.store.close();
91
+ });
92
+
93
+ // ── 4b. Learning a connector phrase must NOT corrupt the parts ───────────
94
+ // THE PREREQUISITE THE BRIDGE STANDS ON. Multi-part rewriting works on its own
95
+ // ("ice fire" → "cold hot"). The moment the store ALSO learns a phrase that
96
+ // happens to contain those answers ("cold or hot"), the cover search must still
97
+ // rewrite each part cleanly — it must not let the phrase's chunks bleed into a
98
+ // part and turn "cold" into "or hot". (Before the fix, this regressed "ice fire"
99
+ // from "cold hot" to "or hothot": the fuse/resolve rules absorbed a completed
100
+ // rewrite into an unrelated learned phrase chunk.)
101
+ test("learning a connector phrase does not corrupt the rewrites", async () => {
102
+ const base = mk();
103
+ await base.ingest([["ice", "cold"], ["fire", "hot"]]);
104
+ const before = await base.respondText("ice fire");
105
+ await base.store.close();
106
+ assert.equal(before, "cold hot");
107
+
108
+ const m = mk();
109
+ await m.ingest([["ice", "cold"], ["fire", "hot"]]);
110
+ await m.ingest("cold or hot"); // a phrase containing both answers
111
+ const after = await m.respondText("ice fire");
112
+ // The two parts still rewrite cleanly; no chunk of the phrase bleeds in.
113
+ assert.equal(
114
+ after.replace(/[^a-z ]/g, "").replace(/ +/g, " ").trim(),
115
+ "cold hot",
116
+ `parts must stay clean, got ${JSON.stringify(after)}`,
117
+ );
118
+ await m.store.close();
119
+ });
120
+
121
+ // =========================================================================
122
+ // THE BRIDGE IS IN THE SEARCH, NOT A POST-PASS
123
+ // =========================================================================
124
+ //
125
+ // The connector must be chosen DURING the cover search — a weighted rule in the
126
+ // same deduction system as the rewrites — not stitched on afterwards. A post-hoc
127
+ // pass that joins finished parts pairwise, left to right, has two fatal faults
128
+ // these tests forbid:
129
+ //
130
+ // • it cannot see a connector that spans MORE THAN TWO parts (a learned
131
+ // "X then Y then Z" is invisible to pairwise bridge(X,Y), bridge(Y,Z));
132
+ // • joining already-rewritten parts one pair at a time lets small mismatches
133
+ // ACCUMULATE into near-dedup gaps (a dropped or doubled fragment), because no
134
+ // single decision ever sees the whole join.
135
+ //
136
+ // Pricing the connector inside the search makes the cover globally optimal: the
137
+ // derivation that yields the most coherent whole wins, connectors included.
138
+
139
+ // ── 5. A connector spanning three parts is found as one whole ────────────
140
+ // The graph learned "X then Y then Z" linking three answers. Asking a, b, c
141
+ // together must reconstruct that whole linked form — a pairwise post-pass,
142
+ // knowing only two-part forms, would miss it and emit a bare "XYZ".
143
+ test("bridge spans three rewritten parts at once", async () => {
144
+ const m = mk();
145
+ await m.ingest([["a", "X"], ["b", "Y"], ["c", "Z"]]);
146
+ await m.ingest("X then Y then Z"); // the three answers cohere as one phrase
147
+ const r = await m.respondText("abc");
148
+ assert.equal(r, "X then Y then Z");
149
+ await m.store.close();
150
+ });
151
+
152
+ // ── 6. No accumulated gaps across several junctions ──────────────────────
153
+ // Joining many rewrites must never drop or double a fragment. Every recognised
154
+ // answer appears exactly once, in order, with no garbage between.
155
+ test("bridge accumulates no gaps across many parts", async () => {
156
+ const m = mk();
157
+ await m.ingest([["a", "X"], ["b", "Y"], ["c", "Z"]]);
158
+ await m.ingest("X then Y then Z");
159
+ const r = await m.respondText("a b c");
160
+ // Each answer once, in order; no doubled or dropped letter.
161
+ assert.equal(r.replace(/[^XYZ]/g, ""), "XYZ");
162
+ await m.store.close();
163
+ });
164
+
165
+ // =========================================================================
166
+ // N-ARY CONNECTORS — the whole interior, not pairwise scraps
167
+ // =========================================================================
168
+ //
169
+ // A learned whole that runs three or more answers together (e.g.
170
+ // "cold, hot, and windy") carries DIFFERENT material between different pairs:
171
+ // between the first two it is ", ", but between the first and the LAST it is
172
+ // ", hot, and " — the interior answer plus both separators. Pairwise bridging,
173
+ // stitched greedily left-to-right, takes the first pairwise connector (", ") and
174
+ // then cannot place the rest, emitting "cold, hot" + "windy" → "cold, hotwindy".
175
+ //
176
+ // The N-ary connector resolves the single learned whole that runs ALL the
177
+ // recognised answers in order and records, for the first answer paired with each
178
+ // later one, the EXACT interior between them. The cover then jumps from the first
179
+ // answer straight to the last across the (recognised) interior, voicing the whole
180
+ // coherent phrase. These tests pass only with that mechanism.
181
+
182
+ // ── 7. Three answers cohere with the full interior between them ──────────
183
+ test("n-ary connector voices a three-answer whole", async () => {
184
+ const m = mk();
185
+ await m.ingest([["ice", "cold"], ["fire", "hot"], ["wind", "windy"]]);
186
+ await m.ingest("cold, hot, and windy"); // the three cohere as one phrase
187
+ const r = await m.respondText("icefirewind");
188
+ assert.equal(r, "cold, hot, and windy");
189
+ await m.store.close();
190
+ });
191
+
192
+ // ── 8. Four answers — the interior grows, still found as one whole ───────
193
+ test("n-ary connector voices a four-answer whole", async () => {
194
+ const m = mk();
195
+ await m.ingest([["a", "W"], ["b", "X"], ["c", "Y"], ["d", "Z"]]);
196
+ await m.ingest("W, X, Y, and Z");
197
+ const r = await m.respondText("abcd");
198
+ assert.equal(r, "W, X, Y, and Z");
199
+ await m.store.close();
200
+ });
201
+
202
+ // ── 9. The asker's own separator is never crossed by an N-ary jump ───────
203
+ // The N-ary jump fires only across a span that is ITSELF wholly recognised
204
+ // (interior answers). When the asker wrote their own separator between parts,
205
+ // that gap is unrecognised, so the jump must NOT fire and the separator must
206
+ // survive — "ice fire" stays "cold hot", never the learned "cold, hot, and …".
207
+ test("n-ary jump does not swallow the asker's separator", async () => {
208
+ const m = mk();
209
+ await m.ingest([["ice", "cold"], ["fire", "hot"], ["wind", "windy"]]);
210
+ await m.ingest("cold, hot, and windy");
211
+ const r = await m.respondText("ice fire wind");
212
+ // The asker ran them apart; their own spacing is kept, parts cleanly rewritten.
213
+ assert.equal(
214
+ r.replace(/[^a-z ]/g, "").replace(/ +/g, " ").trim(),
215
+ "cold hot windy",
216
+ );
217
+ await m.store.close();
218
+ });
219
+
220
+ // =========================================================================
221
+ // SYNONYM JUNCTIONS — bridging through a halo sibling
222
+ // =========================================================================
223
+ //
224
+ // When two answers lack a direct learnt container linking them, but a HALO
225
+ // SIBLING of one answer participates in a learnt whole with the other (e.g.
226
+ // "chilly or hot" where "chilly" is a distributional synonym of "cold"), the
227
+ // bridge must find that junction through the sibling and extract the connector.
228
+ // This is the halo-sibling tier between the exact edge junctions (tier 2)
229
+ // and the approximate resonance fallback (tier 3): the container evidence is
230
+ // exact (content-addressed DAG ascent, same as tier 1), but one side is
231
+ // relaxed from the exact answer to a distributional sibling.
232
+
233
+ // ── 10. Connector found through a halo sibling of the left answer ──────────
234
+ // "ice"→"cold", "fire"→"hot" are the base facts. "chilly" shares
235
+ // distributional company with "cold" (both follow "freeze"), so they are halo
236
+ // siblings. The store separately learned "chilly or hot". The bridge must
237
+ // find "chilly or hot" through the halo-sibling relationship and extract
238
+ // " or " as the connector between "cold" and "hot".
239
+ test("bridge finds a connector via a halo-sibling synonym", async () => {
240
+ const m = mk();
241
+ await m.ingest([["ice", "cold"], ["fire", "hot"]]);
242
+ // Make "chilly" a halo sibling of "cold" — both appear after "freeze".
243
+ await m.ingest([["freeze", "cold"], ["freeze", "chilly"]]);
244
+ // Learn the junction phrase — the connector " or " lives between
245
+ // "chilly" and "hot", but NOT between "cold" and "hot" directly.
246
+ await m.ingest("chilly or hot");
247
+ const r = await m.respondText("icefire");
248
+ assert.equal(r, "cold or hot");
249
+ await m.store.close();
250
+ });
@@ -0,0 +1,240 @@
1
+ // 17-intelligence.test.mjs — the intelligence regression bed.
2
+ //
3
+ // A corpus that mirrors the trained model's hardest pathology: every record is a
4
+ // shared instruction FRAME ("You are a helpful and harmless assistant…") plus a
5
+ // distinctive instruction → an answer. The shared scaffolding is the overwhelming majority of
6
+ // every context's bytes, so whole-query gist resonance is pulled toward the
7
+ // shared preamble and cannot, by itself, tell the records apart. Answering a
8
+ // reworded or partial query therefore demands the graph's CONNECTIVITY —
9
+ // consensus-climbing the structural parents-DAG to the context the query's
10
+ // distinctive sub-regions agree on — not mere whole-query similarity.
11
+ //
12
+ // These assertions pin down that capability so it cannot silently regress:
13
+ // • exact and distractor-framed queries must always resolve (the floor);
14
+ // • the aggregate score across query STYLES (exact, partial, paraphrase,
15
+ // reorder, distractor) must stay at or above a bar that only the
16
+ // connectivity-driven search clears — pure whole-query resonance scores far
17
+ // below it (it answers only near-verbatim queries);
18
+ // • a hard paraphrase that shares distinctive content resolves to its own
19
+ // answer, not a scaffolding-neighbour's.
20
+ //
21
+ // The bar is deliberately below the current pass count so ordinary codec/ANN
22
+ // jitter never flakes it, while a real loss of the climb (e.g. reverting to
23
+ // whole-query resonance) drops well beneath it and fails.
24
+
25
+ import { test } from "node:test";
26
+ import assert from "node:assert/strict";
27
+ import { Mind } from "../dist/src/index.js";
28
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
29
+
30
+ const SYS =
31
+ "You are a helpful and harmless assistant.\n\nYou are not allowed to use any tools.\n";
32
+
33
+ const FACTS = [
34
+ [
35
+ "Describe the importance of gender equality in the workplace to a high school student in exactly 4 sentences.",
36
+ "Gender equality in the workplace means everyone has the same chance to be hired, paid, and promoted fairly.",
37
+ ],
38
+ [
39
+ "Provide a summary of the 1992 Men's Olympic Basketball Team, the Dream Team, in 8 sentences.",
40
+ "The 1992 Dream Team was the greatest basketball roster ever assembled, winning gold in Barcelona.",
41
+ ],
42
+ [
43
+ "Write a short story in JSON format about a street-art vendor who helps a young artist.",
44
+ '{"title":"First Mural","vendor":"Slick","artist":"Maya","scene":"a dawn alley of spray cans"}',
45
+ ],
46
+ [
47
+ "Explain the importance of age discrimination laws to a high school student in 4 sentences.",
48
+ "Age discrimination laws stop employers from treating people unfairly because of how old they are.",
49
+ ],
50
+ [
51
+ "Write an essay analyzing the cinematography of a classic film with the title in double brackets.",
52
+ "<<Light and Shadow>> Citizen Kane uses deep focus to layer meaning in every single frame.",
53
+ ],
54
+ [
55
+ "Create a weekly basketball practice plan with drills for a high school team.",
56
+ "Monday is dribbling and layup drills; Wednesday defense; Friday scrimmage and free throws.",
57
+ ],
58
+ [
59
+ "Summarize the plot of a science fiction novel about time travel in three sentences.",
60
+ "A physicist builds a machine that loops her through one fatal afternoon until she rewrites it.",
61
+ ],
62
+ [
63
+ "Give tips for managing time as a returning college student with a family.",
64
+ "Block your study hours like appointments, batch errands, and protect one evening a week to rest.",
65
+ ],
66
+ [
67
+ "Explain how neighborhood watch programs improve community safety.",
68
+ "Neighborhood watch programs deter crime by organizing residents to notice and report what is unusual.",
69
+ ],
70
+ [
71
+ "Write a guided meditation script for managing anxiety before an exam.",
72
+ "Breathe in for four counts, hold, release slowly, and let the worry drain from your shoulders.",
73
+ ],
74
+ [
75
+ "Describe how social media platforms change interpersonal communication.",
76
+ "Social media speeds contact but flattens nuance, so tone is read from emoji more than from words.",
77
+ ],
78
+ [
79
+ "Summarize the rules of beach volleyball for a first-time spectator.",
80
+ "Beach volleyball pairs two players a side who rally a ball over a net on sand, best of three sets.",
81
+ ],
82
+ [
83
+ "Explain the water cycle to a curious eight-year-old in simple terms.",
84
+ "The sun warms water into vapor, clouds gather it, and rain returns it to rivers and the sea again.",
85
+ ],
86
+ [
87
+ "Write a cover letter for a junior data analyst position at a fintech startup.",
88
+ "Dear Hiring Team, I turn messy financial data into clear decisions, and your startup excites me.",
89
+ ],
90
+ [
91
+ "Describe the health benefits of a Mediterranean diet for older adults.",
92
+ "A Mediterranean diet of olive oil, fish, and vegetables protects the heart and steadies the mind.",
93
+ ],
94
+ [
95
+ "Explain how photosynthesis converts sunlight into chemical energy.",
96
+ "Photosynthesis captures sunlight in chlorophyll to bind carbon dioxide and water into sugar.",
97
+ ],
98
+ [
99
+ "Give advice for a beginner learning to play acoustic guitar.",
100
+ "Start with clean open chords, keep your wrist loose, and practice short daily rather than long rarely.",
101
+ ],
102
+ [
103
+ "Summarize the causes of the fall of the Western Roman Empire.",
104
+ "The Western Roman Empire fell from overreach, currency decay, and waves of migrating peoples.",
105
+ ],
106
+ [
107
+ "Describe best practices for securing a home wireless network.",
108
+ "Secure a home network with WPA3, a long unique passphrase, and firmware kept promptly updated.",
109
+ ],
110
+ [
111
+ "Write a haiku about the first snowfall in a quiet city.",
112
+ "First snow on lamplight / the city holds its breath once / footprints fill with white.",
113
+ ],
114
+ ];
115
+
116
+ // [style, query (shared opening prepended at ask time), index of the expected FACT]
117
+ const PROBES = [
118
+ ["exact", FACTS[0][0], 0],
119
+ ["exact", FACTS[17][0], 17],
120
+ [
121
+ "partial",
122
+ "Describe the importance of gender equality in the workplace.",
123
+ 0,
124
+ ],
125
+ ["partial", "Write a short story in JSON about a street-art vendor.", 2],
126
+ [
127
+ "partial",
128
+ "Provide a summary of the 1992 Men's Olympic Basketball Team.",
129
+ 1,
130
+ ],
131
+ ["partial", "Create a weekly basketball practice plan with drills.", 5],
132
+ ["partial", "Explain how photosynthesis works.", 15],
133
+ [
134
+ "paraphrase",
135
+ "Tell a high schooler why gender equality at work matters.",
136
+ 0,
137
+ ],
138
+ [
139
+ "paraphrase",
140
+ "Give me an overview of the 1992 Dream Team basketball squad.",
141
+ 1,
142
+ ],
143
+ ["paraphrase", "Why do age discrimination laws matter, explained simply?", 3],
144
+ ["paraphrase", "What does the Mediterranean diet do for the elderly?", 14],
145
+ ["paraphrase", "What happened to the Western Roman Empire and why?", 17],
146
+ [
147
+ "reorder",
148
+ "In the workplace, the importance of gender equality, describe it.",
149
+ 0,
150
+ ],
151
+ [
152
+ "distractor",
153
+ "I was chatting with a friend and wondered, how does photosynthesis convert sunlight into energy?",
154
+ 15,
155
+ ],
156
+ [
157
+ "distractor",
158
+ "Quick question before lunch — the health benefits of a Mediterranean diet for older adults?",
159
+ 14,
160
+ ],
161
+ ];
162
+
163
+ // A distinctive interior slice of the expected answer (lossy-first-byte tolerant).
164
+ const marker = (a) => a.replace(/\s+/g, " ").slice(1, 16);
165
+ const hits = (got, want) => got.replace(/\s+/g, " ").includes(marker(want));
166
+
167
+ async function build() {
168
+ const store = new SQliteStore({ path: ":memory:" });
169
+ const mind = new Mind({ seed: 7, store });
170
+ await mind.ingest(FACTS.map(([q, a]) => [SYS + q, a]));
171
+ return { store, mind };
172
+ }
173
+
174
+ test("scaffolding-dominated corpus: connectivity answers across query styles", async () => {
175
+ const { store, mind } = await build();
176
+ const got = [];
177
+ for (const [style, q, idx] of PROBES) {
178
+ const ans = (await mind.respondText(SYS + q)).replace(/\s+/g, " ").trim();
179
+ got.push({ style, ok: hits(ans, FACTS[idx][1]), ans });
180
+ }
181
+ await store.close();
182
+
183
+ const by = (s) => got.filter((g) => g.style === s);
184
+ const rate = (s) => by(s).filter((g) => g.ok).length;
185
+
186
+ // Floor: exact reproduction and distractor-framed (distinctive content intact)
187
+ // must ALWAYS resolve — these need no rewording intelligence, only that the
188
+ // search finds present content.
189
+ assert.equal(
190
+ rate("exact"),
191
+ by("exact").length,
192
+ "every exact query must resolve",
193
+ );
194
+ assert.equal(
195
+ rate("distractor"),
196
+ by("distractor").length,
197
+ "distinctive content buried in framing must still resolve",
198
+ );
199
+
200
+ // Aggregate: the climb must clear a bar that whole-query resonance cannot.
201
+ // The bar of 15 absorbs codec/ANN jitter while a reversion to plain whole-
202
+ // query resonance (which answers only near-verbatim queries) scores far
203
+ // lower and fails.
204
+ const total = got.filter((g) => g.ok).length;
205
+ assert.ok(
206
+ total >= 15,
207
+ `intelligence score ${total}/${PROBES.length} — expected ≥ 15 ` +
208
+ `(connectivity-driven climb; pure whole-query resonance scores far less)\n` +
209
+ got.filter((g) => !g.ok).map((g) =>
210
+ ` ✗ [${g.style}] ${g.ans.slice(0, 40)}`
211
+ ).join("\n"),
212
+ );
213
+
214
+ // At least one genuine paraphrase must resolve to its OWN answer — the
215
+ // signature of the consensus climb, impossible for scaffolding-pulled whole-query
216
+ // resonance.
217
+ assert.ok(
218
+ rate("paraphrase") >= 2,
219
+ `only ${rate("paraphrase")}/${
220
+ by("paraphrase").length
221
+ } paraphrases resolved — ` +
222
+ `expected ≥ 2 (the climb's distinctive-region consensus)`,
223
+ );
224
+ });
225
+
226
+ // A reworded query whose distinctive content clearly names one record must not
227
+ // be captured by a scaffolding-sharing neighbour — the precise win consensus-climbing
228
+ // delivers over whole-query gist.
229
+ test("a distinctive paraphrase resolves to its own record, not a frame neighbour", async () => {
230
+ const { store, mind } = await build();
231
+ const ans = (await mind.respondText(
232
+ SYS + "Tell a high schooler why gender equality at work matters.",
233
+ )).replace(/\s+/g, " ").trim();
234
+ await store.close();
235
+ assert.ok(
236
+ hits(ans, FACTS[0][1]),
237
+ `gender-equality paraphrase resolved to "${ans.slice(0, 48)}" — ` +
238
+ `expected the gender-equality record`,
239
+ );
240
+ });