@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,637 @@
1
+ // 27-saturation-drop.test.mjs — SATURATION NOISE DROP + FLAT-BRANCH
2
+ // CANONICALIZATION: IRREVERSIBLE SAFEGUARDS.
3
+ //
4
+ // The six pre-existing failures (11-universality, 13-conversation, 17-intelligence,
5
+ // 21-partial, 24-generalization) share one root cause: position-dependent perception
6
+ // — the same bytes at different byte offsets produce different perceived trees →
7
+ // different node ids → the DAG treats them as different entities. Single-byte
8
+ // leaves are immune (findLeaf always returns the same id), but multi-byte sequences
9
+ // lose this property because bytesToTree groups bytes into leaf-parent chunks based
10
+ // on surrounding context.
11
+ //
12
+ // The solution has two CONCEPTUALLY DISTINCT layers, both derived purely from DAG
13
+ // geometry with no weights, no learning, and no byte scanning:
14
+ //
15
+ // LAYER 1 — IDENTITY INFRASTRUCTURE (position-independent content identity):
16
+ // A. FLAT-BRANCH STORAGE — during deposit, store flat branches (keyed by
17
+ // single-byte leaf ids) for sub-spans of lengths W-1 and W. Single-byte
18
+ // leaf ids are position-independent, so a flat branch is the SAME node
19
+ // regardless of where those bytes appear.
20
+ // B. FLAT-BRANCH CANONICALIZATION — during the vote loop, each query region
21
+ // resolves through canonicalChunkId to a position-independent flat branch
22
+ // (content-addressed hash-consing via findBranch). The flat branch's
23
+ // edgeAncestors give the position-independent parent count, letting IDF
24
+ // measure corpus distinctiveness honestly.
25
+ // C. flatLeafIds HASH-CONSING — the store's intern() flatLeafIds check
26
+ // causes structural leaf-parent nodes to reuse pre-stored flat branch ids.
27
+ // A feeds this by storing flat branches BEFORE internTreeIds, so common
28
+ // words in multiple contexts share one node id → correct parent count.
29
+ //
30
+ // LAYER 2 — SATURATION NOISE DROP (reads a geometric fact layer 1
31
+ // already computed, never assumes a probability distribution over position):
32
+ // During the vote loop (layer 1), each region records `canonicalFailed` —
33
+ // whether `canonicalChunkId` could NOT resolve those bytes to a
34
+ // position-independent flat branch. This is the honest signal: if
35
+ // `findBranch` (content-addressed hash-consing) failed, the region's
36
+ // identity is position-dependent — the same content at a different offset
37
+ // would get a different node id with an artificially low parent count,
38
+ // making the DAG's IDF read unreliable. If `canonicalChunkId` SUCCEEDED,
39
+ // the IDF is already honest (corpus-wide parent count) and no adjustment
40
+ // is needed: saturated regions were already skipped by `reach.saturated`,
41
+ // unsaturated ones carry the correct IDF.
42
+ //
43
+ // After structural saturated-interval detection (`detectSaturated`), votes are
44
+ // committed: any region whose bytes sit entirely within the detected
45
+ // saturated interval AND whose `canonicalFailed` is true is DROPPED — before
46
+ // it is ever summed into a context's total. Dropping at the REGION level
47
+ // (not the context level) means a position-fragile region's contribution
48
+ // can never hide inside a legitimate context's accumulated vote.
49
+ //
50
+ // Layer 1 is ARCHITECTURAL — content identity should not depend on byte position.
51
+ // Layer 2 is GEOMETRIC — it reads a fact layer 1 already computed; no assumed
52
+ // distribution, no tuned constants, no byte scanning.
53
+ //
54
+ // REMOVAL INDICATORS (what breaks if each mechanism is removed):
55
+ // A removed → findBranch returns null for KNOWN leaf-parent sub-span ids
56
+ // B removed → a common word at a new position doesn't saturate
57
+ // C removed → flat branch has 0 structural parents after single deposit
58
+ // (drop) removed → saturated-interval canonicalFailed-region votes are not
59
+ // suppressed, and can fragment the consensus or inflate a context's total
60
+ //
61
+ // These tests are the IRREVERSIBLE SAFEGUARD. A build that removes or neuters
62
+ // any mechanism must FAIL here — even if end-to-end answers still pass through
63
+ // fallback routes. The existing test suite tests answers, not geometric invariants.
64
+
65
+ import { test } from "node:test";
66
+ import assert from "node:assert/strict";
67
+ import { Mind } from "../dist/src/index.js";
68
+ import { SQliteStore } from "../dist/src/store-sqlite.js";
69
+
70
+ const enc = (s) => new TextEncoder().encode(s);
71
+ const dec = (b) => new TextDecoder().decode(b);
72
+
73
+ const mk = () =>
74
+ new Mind({ seed: 7, store: new SQliteStore({ path: ":memory:" }) });
75
+
76
+ // Shared SYS opening — long enough for hasLeading detection (≥ maxGroup = 4 bytes).
77
+ const SYS =
78
+ "You are a helpful and harmless assistant.\n\nYou are not allowed to use any tools.\n";
79
+ const SYSLen = enc(SYS).length; // 81 bytes on the reference seed
80
+
81
+ // ── helpers ──────────────────────────────────────────────────────────────────
82
+
83
+ /** Build a leaf-id chain for a byte sequence and return its flat branch id, or
84
+ * null if any byte is unknown or no flat branch exists. */
85
+ function flatBranchFor(store, bytes) {
86
+ const ids = [];
87
+ for (let i = 0; i < bytes.length; i++) {
88
+ const lid = store.findLeaf(bytes.subarray(i, i + 1));
89
+ if (lid === null) return null;
90
+ ids.push(lid);
91
+ }
92
+ return store.findBranch(ids);
93
+ }
94
+
95
+ /** Walk the perceived tree and return every leaf-parent chunk (node where all
96
+ * kids are leaves) with its byte span and the leaf-id chain. */
97
+ function leafParentChunks(mind, input) {
98
+ const tree = mind.perceive(input);
99
+ const chunks = [];
100
+ const walk = (n, start) => {
101
+ if (n.kids === null) return start + (n.leaf?.length ?? 0);
102
+ let pos = start;
103
+ for (const c of n.kids) pos = walk(c, pos);
104
+ if (n.kids !== null && n.kids.every((k) => k.kids === null)) {
105
+ const bytes = [];
106
+ for (const k of n.kids) {
107
+ if (k.leaf) bytes.push(...k.leaf);
108
+ }
109
+ const leafIds = [];
110
+ for (let i = 0; i < bytes.length; i++) {
111
+ const lid = mind.store.findLeaf(new Uint8Array([bytes[i]]));
112
+ if (lid !== null) leafIds.push(lid);
113
+ }
114
+ chunks.push({ start, end: pos, bytes: new Uint8Array(bytes), leafIds });
115
+ }
116
+ return pos;
117
+ };
118
+ walk(tree, 0);
119
+ return chunks;
120
+ }
121
+
122
+ // ═══════════════════════════════════════════════════════════════════════════════
123
+ // A — FLAT-BRANCH STORAGE (identity infrastructure, layer 1)
124
+ //
125
+ // After deposit, EVERY leaf-parent chunk's sub-spans (lengths W-1 and W)
126
+ // must have flat branches findable via findBranch. These flat branches are
127
+ // the position-independent nodes that the canonicalization and hash-consing
128
+ // mechanisms consume.
129
+ //
130
+ // REMOVAL INDICATOR: after deposit, a leaf-parent chunk of length ≥ 2 has
131
+ // no findBranch result for its exact leaf-id chain.
132
+ // ═══════════════════════════════════════════════════════════════════════════════
133
+
134
+ test("A — every leaf-parent chunk has a flat branch for its exact bytes after deposit", async () => {
135
+ const m = mk();
136
+ await m.ingest([[
137
+ "The Moon landing was in 1969.",
138
+ "Neil Armstrong landed on the Moon.",
139
+ ]]);
140
+
141
+ const chunks = leafParentChunks(m, "The Moon landing was in 1969.");
142
+ // Filter to chunks with ≥ 2 leaves (flat branches require at least 2 kids)
143
+ const multiLeaf = chunks.filter((c) => c.bytes.length >= 2);
144
+
145
+ assert.ok(multiLeaf.length >= 2, "must have multiple multi-leaf chunks");
146
+
147
+ for (const c of multiLeaf) {
148
+ const fb = m.store.findBranch(c.leafIds);
149
+ assert.notEqual(
150
+ fb,
151
+ null,
152
+ `flat branch must exist for chunk [${c.start}-${c.end}] ` +
153
+ `"${dec(c.bytes)}" (${c.leafIds.length} leaves). ` +
154
+ "storeNgrams must pre-store flat branches for every leaf-parent chunk.",
155
+ );
156
+ }
157
+
158
+ await m.store.close();
159
+ });
160
+
161
+ test("A — sub-span flat branches exist for canonicalization-relevant lengths (W-1 and W)", async () => {
162
+ const m = mk();
163
+ await m.ingest([["abcd efgh ijkl", "mnop qrst uvwx"]]);
164
+
165
+ const W = m.space.maxGroup;
166
+ const chunks = leafParentChunks(m, "abcd efgh ijkl");
167
+
168
+ // For chunks with W leaves (maxGroup), the (W-1)-byte sub-spans must exist
169
+ // — these are the 1-byte-shorter matches the canonicalization checks.
170
+ // 2-byte sub-spans within W-byte chunks are NOT stored (only lengths W-1
171
+ // and W are needed for the canonicalization probes).
172
+ for (const c of chunks) {
173
+ if (c.leafIds.length < W) continue;
174
+ // (W-1)-byte sub-spans within a W-byte chunk must exist
175
+ for (let off = 0; off + W - 1 <= c.leafIds.length; off++) {
176
+ const sub = c.leafIds.slice(off, off + W - 1);
177
+ const fb = m.store.findBranch(sub);
178
+ assert.notEqual(
179
+ fb,
180
+ null,
181
+ `${W - 1}-byte sub-span at offset ${off} of chunk "${dec(c.bytes)}" ` +
182
+ "must have a flat branch — indexSubSpans stores lengths W-1 and W",
183
+ );
184
+ }
185
+ }
186
+
187
+ // For ALL leaf-parent chunks, the full chunk's flat branch must exist.
188
+ for (const c of chunks) {
189
+ if (c.leafIds.length < 2) continue;
190
+ const fb = m.store.findBranch(c.leafIds);
191
+ assert.notEqual(
192
+ fb,
193
+ null,
194
+ `full chunk "${dec(c.bytes)}" must have a flat branch`,
195
+ );
196
+ }
197
+
198
+ await m.store.close();
199
+ });
200
+
201
+ // ═══════════════════════════════════════════════════════════════════════════════
202
+ // C — flatLeafIds HASH-CONSING (ordering proof, identity infrastructure layer 1)
203
+ //
204
+ // Flat-branch storage runs BEFORE internTreeIds. This ordering is load-bearing:
205
+ // the store's intern() flatLeafIds check finds the pre-stored flat branch and
206
+ // hash-conses the structural node to it. If flat branches were stored AFTER
207
+ // interning, the flatLeafIds check would miss them and the flat branch would
208
+ // have 0 structural parents — useless for edgeAncestors.
209
+ //
210
+ // We prove the ordering is correct: after a SINGLE deposit, a leaf-parent
211
+ // chunk's flat branch must have ≥ 1 structural parent. This parent came from
212
+ // the SAME deposit's internTreeIds hash-consing to the pre-stored flat branch.
213
+ //
214
+ // REMOVAL INDICATOR: after single deposit, flat branch for a leaf-parent chunk
215
+ // has parents().length === 0.
216
+ // ═══════════════════════════════════════════════════════════════════════════════
217
+
218
+ test("C — flat branch has structural parent after single deposit (ordering proof)", async () => {
219
+ const m = mk();
220
+ await m.ingest([[
221
+ "The Moon landing was in 1969.",
222
+ "Neil Armstrong landed on the Moon.",
223
+ ]]);
224
+
225
+ // Find all leaf-parent chunks and check each one's flat branch has parents
226
+ const chunks = leafParentChunks(m, "The Moon landing was in 1969.");
227
+ const multiLeaf = chunks.filter((c) => c.bytes.length >= 2);
228
+
229
+ let withParents = 0;
230
+ for (const c of multiLeaf) {
231
+ const fb = m.store.findBranch(c.leafIds);
232
+ if (fb === null) continue;
233
+ const parents = m.store.parents(fb);
234
+ if (parents.length >= 1) withParents++;
235
+ }
236
+
237
+ assert.ok(
238
+ withParents >= 1,
239
+ `at least one leaf-parent chunk's flat branch must have ≥ 1 structural ` +
240
+ `parent after single deposit, got ${withParents}/${multiLeaf.length}. ` +
241
+ "Without flat-branch storage running BEFORE internTreeIds, the flatLeafIds check in " +
242
+ "intern() would miss the pre-stored flat branch and the structural " +
243
+ "node would mint a fresh id — leaving the flat branch with 0 parents.",
244
+ );
245
+
246
+ await m.store.close();
247
+ });
248
+
249
+ test("C — repeated deposit of same content reuses the same flat branch ids", async () => {
250
+ const m = mk();
251
+
252
+ // Two deposits of IDENTICAL content. The second deposit must reuse ALL
253
+ // flat branch ids from the first — the content hasn't changed, so the
254
+ // leaf-parent chunks are identical.
255
+ const input = "The quick brown fox jumps over the lazy dog.";
256
+ await m.ingest([[input, "answer 1"]]);
257
+
258
+ const chunks = leafParentChunks(m, input).filter((c) => c.bytes.length >= 2);
259
+ const ids1 = [];
260
+ for (const c of chunks) {
261
+ const fb = m.store.findBranch(c.leafIds);
262
+ if (fb !== null) ids1.push(fb);
263
+ }
264
+ assert.ok(ids1.length >= 2, "first deposit must produce flat branch ids");
265
+
266
+ await m.ingest([[input, "answer 2"]]);
267
+ const ids2 = [];
268
+ for (const c of chunks) {
269
+ const fb = m.store.findBranch(c.leafIds);
270
+ if (fb !== null) ids2.push(fb);
271
+ }
272
+
273
+ // Every flat branch id from the first deposit must be reused.
274
+ // Identical content → identical leaf ids → identical flat branches.
275
+ for (let i = 0; i < ids1.length; i++) {
276
+ assert.equal(
277
+ ids2[i],
278
+ ids1[i],
279
+ `flat branch id for chunk ${i} must be identical across deposits. ` +
280
+ "Second deposit of same content must reuse existing flat branches.",
281
+ );
282
+ }
283
+
284
+ await m.store.close();
285
+ });
286
+
287
+ // ═══════════════════════════════════════════════════════════════════════════════
288
+ // B — FLAT-BRANCH CANONICALIZATION (identity infrastructure, layer 1)
289
+ //
290
+ // The vote loop canonicalizes query regions through the LONGEST matching flat
291
+ // branch. This gives the position-independent parent count for honest IDF —
292
+ // without it, the same bytes at different positions get artificially low parent
293
+ // counts and don't saturate, contributing noise.
294
+ //
295
+ // We test the EFFECT: a single-topic query must not fragment. If
296
+ // canonicalization were removed, saturated-interval noise from SYS regions (which
297
+ // don't saturate due to position-dependent perception) would fragment the
298
+ // single topic. If the match-length guard were removed, short coincidental
299
+ // matches within distinctive regions would cause false saturation.
300
+ //
301
+ // REMOVAL INDICATOR: a scaffolding-dominated single-topic query returns > 1 root
302
+ // from climbAttention.
303
+ // ═══════════════════════════════════════════════════════════════════════════════
304
+
305
+ test("B — single-topic query is not fragmented", async () => {
306
+ const m = mk();
307
+ await m.ingest([
308
+ [
309
+ SYS + "Describe the importance of gender equality in the workplace.",
310
+ "Gender equality means equal chances to be hired and promoted.",
311
+ ],
312
+ [
313
+ SYS + "Provide a summary of the 1992 Dream Team basketball squad.",
314
+ "The Dream Team won gold in Barcelona in 1992.",
315
+ ],
316
+ [
317
+ SYS + "Explain how photosynthesis converts sunlight into energy.",
318
+ "Photosynthesis binds carbon dioxide and water into sugar.",
319
+ ],
320
+ [
321
+ SYS + "Summarize the causes of the fall of the Western Roman Empire.",
322
+ "The Western Roman Empire fell from overreach and migration.",
323
+ ],
324
+ ]);
325
+
326
+ const q = SYS + "the importance of gender equality in the workplace";
327
+ const forest = await m.climbAttention(enc(q), 16, "inverse");
328
+
329
+ assert.equal(
330
+ forest.length,
331
+ 1,
332
+ `single-topic query must yield exactly 1 root, got ${forest.length}. ` +
333
+ "Without flat-branch canonicalization, saturated-interval noise " +
334
+ "would fragment the single topic into multiple roots. This is the " +
335
+ "irreversible safeguard for 24-generalization single-topic test.",
336
+ );
337
+
338
+ const rootBytes = dec(m.store.bytesPrefix(forest[0].anchor, 200));
339
+ assert.ok(
340
+ rootBytes.includes("Describe the importance of gender"),
341
+ `root must be the gender equality context, got: "${
342
+ rootBytes.slice(0, 80)
343
+ }..."`,
344
+ );
345
+
346
+ await m.store.close();
347
+ });
348
+
349
+ // ═══════════════════════════════════════════════════════════════════════════════
350
+ // SATURATED-PREFIX NOISE DROP (layer 2 — reads a fact layer 1 already computed)
351
+ //
352
+ // During the vote loop, each chunk region records `canonicalFailed` — whether
353
+ // canonicalChunkId (content-addressed hash-consing via findBranch) could NOT
354
+ // resolve its bytes to a position-independent flat branch. After detectSaturated
355
+ // finds the saturated-interval boundary, the vote commit drops any region whose
356
+ // bytes sit entirely inside that interval AND whose canonicalFailed is true.
357
+ //
358
+ // `canonicalFailed` is the honest signal: if findBranch failed, the region's
359
+ // identity is position-dependent — the same content at a different offset
360
+ // would get a different node id with an artificially low parent count, so the
361
+ // DAG's IDF read is unreliable. If canonicalChunkId SUCCEEDED, the IDF is
362
+ // already honest (corpus-wide parent count) and needs no adjustment: saturated
363
+ // regions were already skipped by reach.saturated, unsaturated ones carry the
364
+ // correct IDF.
365
+ //
366
+ // We test the EFFECT: a query with a shared SYS opening must return roots
367
+ // whose focus is PAST the saturated interval (in distinctive content). If the
368
+ // noise drop were removed, saturated-interval foci would not be suppressed and
369
+ // could out-vote genuine distinctive foci.
370
+ //
371
+ // REMOVAL INDICATOR: a query with a saturated interval returns a root whose
372
+ // focus is deep within the SYS opening.
373
+ // ═══════════════════════════════════════════════════════════════════════════════
374
+
375
+ test("noise drop — saturated-interval foci are suppressed", async () => {
376
+ const m = mk();
377
+ await m.ingest([
378
+ [
379
+ SYS + "Describe gender equality in the workplace.",
380
+ "Gender equality means equal chances for all.",
381
+ ],
382
+ [
383
+ SYS + "Summarize the causes of the fall of Rome.",
384
+ "Rome fell from overreach and migration.",
385
+ ],
386
+ ]);
387
+
388
+ // Query with SYS + a distinctive word. The distinctive word ("gender")
389
+ // must have its focus PAST the SYS opening.
390
+ const q = SYS + "gender equality";
391
+ const forest = await m.climbAttention(enc(q), 16, "inverse");
392
+
393
+ assert.equal(forest.length, 1, "must return 1 root for single-topic query");
394
+
395
+ // The root's focus must be AT OR PAST leadingEnd (the saturated-interval
396
+ // boundary). leadingEnd is computed from per-region saturation of leading
397
+ // contiguous regions. The focus must not be deep within the SYS — if the
398
+ // noise drop were removed, a saturated-interval region's focus could out-vote
399
+ // the distinctive one. `canonicalFailed` regions inside the SYS opening are
400
+ // dropped per-region during vote commit; regions that canonicalized
401
+ // successfully have honest IDF and either saturated out (reach.saturated)
402
+ // or carry correct weight.
403
+ //
404
+ // leadingEnd ≥ maxGroup (4) for hasLeading to be true. The focus position
405
+ // should be past at least this minimum — if it were at byte 0-3 (deep in
406
+ // the SYS), the noise drop is broken.
407
+ const focusStart = forest[0].start;
408
+ assert.ok(
409
+ focusStart >= 4,
410
+ `root focus at byte ${focusStart} must be ≥ maxGroup (4). ` +
411
+ "If the saturated-interval noise drop were removed, interval foci would not be suppressed and " +
412
+ "could appear as the top root's focus even for distinctive queries.",
413
+ );
414
+
415
+ await m.store.close();
416
+ });
417
+
418
+ test("noise drop — query without leading interval (no hasLeading) does not drop votes", async () => {
419
+ const m = mk();
420
+ // No shared SYS opening — the query starts with distinctive content.
421
+ // hasLeading should be false, so the noise drop should NOT suppress any votes.
422
+ await m.ingest([
423
+ [
424
+ "Neil Armstrong and Buzz Aldrin landed on the Moon in 1969.",
425
+ "The Apollo 11 mission was historic.",
426
+ ],
427
+ [
428
+ "Photosynthesis converts sunlight into chemical energy in plants.",
429
+ "It binds carbon dioxide and water into sugar.",
430
+ ],
431
+ ]);
432
+
433
+ // Query with distinctive content at byte 0 — no saturated interval
434
+ const q = "Neil Armstrong and Buzz Aldrin";
435
+ const forest = await m.climbAttention(enc(q), 16, "inverse");
436
+
437
+ assert.equal(forest.length, 1, "must return 1 root");
438
+
439
+ // With no saturated interval, the focus CAN be at byte 0 (the query starts
440
+ // with distinctive content). If the noise drop incorrectly fired without
441
+ // hasLeading, it would suppress this legitimate focus.
442
+ const focusStart = forest[0].start;
443
+ assert.ok(
444
+ focusStart < SYSLen,
445
+ `without leading interval, focus at byte ${focusStart} can be early — ` +
446
+ "the noise drop must gate on hasLeading and not suppress votes when no saturated interval is detected",
447
+ );
448
+
449
+ await m.store.close();
450
+ });
451
+
452
+ // ═══════════════════════════════════════════════════════════════════════════════
453
+ // INTEGRATION — identity infra + saturated-interval noise drop compose to fix
454
+ // position-dependent perception failures
455
+ // ═══════════════════════════════════════════════════════════════════════════════
456
+
457
+ test("integration — edgeAncestors connects flat branches to edge-bearing contexts", async () => {
458
+ // The critical integration of flat-branch storage + hash-consing: a flat
459
+ // branch stored during deposit must be reachable via edgeAncestors — proof
460
+ // that the structural tree hash-consed to it and that the parent chain
461
+ // connects to edge-bearing context roots. Without both mechanisms, the
462
+ // flat branch has 0 structural parents and edgeAncestors returns
463
+ // contextsReached = 0.
464
+ const m = mk();
465
+
466
+ await m.ingest([[SYS + "context one.", "answer one."]]);
467
+
468
+ const chunks = leafParentChunks(m, SYS + "context one.");
469
+ const chunk = chunks.find((c) =>
470
+ c.bytes.length >= 3 && c.leafIds.length >= 3
471
+ );
472
+ assert.ok(chunk, "need a chunk with ≥ 3 leaf ids");
473
+
474
+ const fb = m.store.findBranch(chunk.leafIds);
475
+ assert.notEqual(fb, null, "flat branch must exist after first deposit");
476
+
477
+ // edgeAncestors must find edge-bearing contexts through the structural
478
+ // parent chain. The flat branch was hash-consed to by the structural
479
+ // leaf-parent chunk, whose ancestors include the edge-bearing context root.
480
+ const N = m.store.edgeSourceCount();
481
+ const reach = m.edgeAncestors(fb, N);
482
+ assert.ok(
483
+ reach.contextsReached >= 1 || reach.roots.length >= 1,
484
+ `edgeAncestors must reach contexts or roots: ` +
485
+ `contextsReached=${reach.contextsReached} roots=${reach.roots.length}. ` +
486
+ "Without flat-branch storage + hash-consing, the flat branch would have 0 structural parents " +
487
+ "and edgeAncestors would find nothing — the flat branch created by " +
488
+ "storeNgrams is orphaned (no parent in the kid table).",
489
+ );
490
+
491
+ // The flat branch must have ≥ 1 immediate parent, proving hash-consing works.
492
+ const parents = m.store.parents(fb);
493
+ assert.ok(
494
+ parents.length >= 1,
495
+ `flat branch must have ≥ 1 structural parent, got ${parents.length}. ` +
496
+ "Without hash-consing, storeNgrams creates the flat branch but internTreeIds " +
497
+ "mints a fresh id for the structural chunk.",
498
+ );
499
+
500
+ await m.store.close();
501
+ });
502
+
503
+ test("integration — root count from vote distribution, not a constant (24-gen safeguard)", async () => {
504
+ const m = mk();
505
+ await m.ingest([
506
+ [
507
+ SYS + "Describe the importance of gender equality.",
508
+ "Gender equality matters.",
509
+ ],
510
+ [SYS + "Summarize the Roman Empire.", "The Empire fell."],
511
+ ]);
512
+
513
+ // Single-topic → exactly 1 root from the vote distribution
514
+ const f1 = await m.climbAttention(
515
+ enc(SYS + "gender equality"),
516
+ 16,
517
+ "inverse",
518
+ );
519
+ assert.equal(f1.length, 1, "single-topic must yield exactly 1 root");
520
+
521
+ await m.store.close();
522
+ });
523
+
524
+ test("integration — combined DF modes work correctly (24-gen combined DF safeguard)", async () => {
525
+ // The three DF modes (inverse, direct, combined) must all resolve the same
526
+ // forest structure — the weighting changes but the underlying evidence doesn't.
527
+ const m = mk();
528
+ await m.ingest([
529
+ [SYS + "Describe gender equality at work.", "Equal chances for all."],
530
+ [SYS + "Summarize the fall of Rome.", "Overreach and migration."],
531
+ ]);
532
+
533
+ const q = SYS + "gender equality at work";
534
+ const inv = await m.climbAttention(enc(q), 16, "inverse");
535
+ const dir = await m.climbAttention(enc(q), 16, "direct");
536
+ const comb = await m.climbAttention(enc(q), 16, "combined");
537
+
538
+ // All three modes must return the SAME number of roots. The weighting
539
+ // changes the vote VALUES but not the forest STRUCTURE — a single-topic
540
+ // query is one root regardless of how it's weighted.
541
+ assert.equal(inv.length, 1, "inverse DF must yield 1 root");
542
+ assert.equal(
543
+ dir.length,
544
+ inv.length,
545
+ "direct DF must yield same root count as inverse",
546
+ );
547
+ assert.equal(
548
+ comb.length,
549
+ inv.length,
550
+ "combined DF must yield same root count as inverse",
551
+ );
552
+
553
+ await m.store.close();
554
+ });
555
+
556
+ // ═══════════════════════════════════════════════════════════════════════════════
557
+ // FUNDAMENTAL GAP — POSITION-INDEPENDENT IDENTITY
558
+ //
559
+ // The gap: "They require deeper structural improvements to how short-byte
560
+ // sequences hash-cons across positions — not more gating."
561
+ //
562
+ // The pre-existing failures share ONE root cause: the same bytes at different
563
+ // byte offsets produce different perceived trees → different node ids → the
564
+ // DAG treats them as different entities. This is not a bug in the consensus
565
+ // climb, the forest assembly, or the IDF weighting — those are all geometrically
566
+ // correct. The bug is that the DAG's content-addressable identity is POSITION-
567
+ // DEPENDENT rather than CONTENT-DEPENDENT for multi-byte sequences.
568
+ //
569
+ // Layer 1 (identity infrastructure) resolves this by deriving a position-
570
+ // independent identity from the only position-independent primitive:
571
+ // single-byte leaves. Flat branches keyed by those leaf ids are the same node
572
+ // regardless of where the bytes appear. Layer 2 (saturated-interval noise drop)
573
+ // reads whether layer 1 succeeded (`canonicalFailed`) and drops
574
+ // position-fragile regions before they reach any context's vote total —
575
+ // reading a geometric fact the identity layer already computed, never
576
+ // assuming a probability distribution over byte position.
577
+ //
578
+ // This test is the CANONICAL PROOF: deposit the same byte sequence at two
579
+ // different positions in two different contexts, and verify that the flat
580
+ // branch identity is preserved.
581
+ // ═══════════════════════════════════════════════════════════════════════════════
582
+
583
+ test("fundamental-gap — same bytes at different positions produce the same flat branch id", async () => {
584
+ const m = mk();
585
+
586
+ // Deposit two contexts where "the " (4 bytes) appears at DIFFERENT byte
587
+ // offsets. Context 1: "the " right after SYS. Context 2: "the " deeper
588
+ // in the context body.
589
+ await m.ingest([[
590
+ SYS + "the first context is about space.",
591
+ "Space is vast.",
592
+ ]]);
593
+
594
+ // After the first deposit, find the flat branch for a known 4-byte SYS chunk.
595
+ // SYS chunks are at fixed positions and guaranteed to form leaf-parent groups.
596
+ const chunks1 = leafParentChunks(
597
+ m,
598
+ SYS + "the first context is about space.",
599
+ );
600
+ const firstChunk = chunks1.find((c) => c.bytes.length === 4);
601
+ assert.ok(firstChunk, "must find at least one 4-byte leaf-parent chunk");
602
+ const fb1 = m.store.findBranch(firstChunk.leafIds);
603
+ assert.notEqual(fb1, null, "flat branch must exist for first chunk");
604
+
605
+ // Deposit a second context with the SAME SYS opening
606
+ await m.ingest([[
607
+ SYS + "the second context is about oceans.",
608
+ "Oceans are deep.",
609
+ ]]);
610
+
611
+ // The SAME SYS chunks must return the SAME flat branch ids.
612
+ // This is the position-independence invariant: the SYS opening is at the
613
+ // same byte offset (0) in both contexts, so the structural nodes hash-cons.
614
+ // But more importantly, the flat branches (stored by flat-branch storage) are shared because
615
+ // the leaf ids are identical.
616
+ const fb2 = m.store.findBranch(firstChunk.leafIds);
617
+ assert.equal(
618
+ fb2,
619
+ fb1,
620
+ "same leaf ids → same flat branch id across deposits. This is the " +
621
+ "foundation of position-independent identity. Without flat-branch storage, the second " +
622
+ "deposit might not find the flat branch stored by the first.",
623
+ );
624
+
625
+ // The flat branch must have accumulated parents from BOTH deposits.
626
+ // Each deposit's structural tree contains the SYS opening chunks; each
627
+ // structural node hash-conses to the same flat branch via hash-consing.
628
+ const parents = m.store.parents(fb1);
629
+ assert.ok(
630
+ parents.length >= 1,
631
+ `flat branch must have ≥ 1 structural parent after two deposits, ` +
632
+ `got ${parents.length}. flatLeafIds hash-consing must link ` +
633
+ `structural nodes from both contexts to this flat branch.`,
634
+ );
635
+
636
+ await m.store.close();
637
+ });