@hviana/sema 0.5.3 → 0.5.4

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 (143) hide show
  1. package/AGENTS.md +6 -6
  2. package/HOW_IT_WORKS.md +16 -0
  3. package/jsr.json +1 -1
  4. package/package.json +1 -1
  5. package/src/mind/match.ts +81 -0
  6. package/src/mind/mechanisms/recall.ts +29 -3
  7. package/test/76-reference-binding.test.mjs +72 -0
  8. package/dist/example/demo.d.ts +0 -1
  9. package/dist/example/demo.js +0 -39
  10. package/dist/example/train_base.d.ts +0 -93
  11. package/dist/example/train_base.js +0 -2269
  12. package/dist/src/alphabet.d.ts +0 -7
  13. package/dist/src/alphabet.js +0 -33
  14. package/dist/src/alu/src/alu.d.ts +0 -185
  15. package/dist/src/alu/src/alu.js +0 -440
  16. package/dist/src/alu/src/expr.d.ts +0 -61
  17. package/dist/src/alu/src/expr.js +0 -318
  18. package/dist/src/alu/src/index.d.ts +0 -11
  19. package/dist/src/alu/src/index.js +0 -19
  20. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  21. package/dist/src/alu/src/kernel-arith.js +0 -264
  22. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  23. package/dist/src/alu/src/kernel-bits.js +0 -152
  24. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  25. package/dist/src/alu/src/kernel-logic.js +0 -60
  26. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  27. package/dist/src/alu/src/kernel-nd.js +0 -208
  28. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  29. package/dist/src/alu/src/kernel-numeric.js +0 -366
  30. package/dist/src/alu/src/operation.d.ts +0 -168
  31. package/dist/src/alu/src/operation.js +0 -189
  32. package/dist/src/alu/src/parser.d.ts +0 -221
  33. package/dist/src/alu/src/parser.js +0 -577
  34. package/dist/src/alu/src/resonance.d.ts +0 -55
  35. package/dist/src/alu/src/resonance.js +0 -126
  36. package/dist/src/alu/src/text.d.ts +0 -31
  37. package/dist/src/alu/src/text.js +0 -73
  38. package/dist/src/alu/src/value.d.ts +0 -109
  39. package/dist/src/alu/src/value.js +0 -300
  40. package/dist/src/alu/test/alu.test.d.ts +0 -1
  41. package/dist/src/alu/test/alu.test.js +0 -764
  42. package/dist/src/bytes.d.ts +0 -14
  43. package/dist/src/bytes.js +0 -59
  44. package/dist/src/canon.d.ts +0 -45
  45. package/dist/src/canon.js +0 -85
  46. package/dist/src/config.d.ts +0 -111
  47. package/dist/src/config.js +0 -91
  48. package/dist/src/derive/src/deduction.d.ts +0 -136
  49. package/dist/src/derive/src/deduction.js +0 -159
  50. package/dist/src/derive/src/index.d.ts +0 -8
  51. package/dist/src/derive/src/index.js +0 -11
  52. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  53. package/dist/src/derive/src/priority-queue.js +0 -73
  54. package/dist/src/derive/src/rewrite.d.ts +0 -56
  55. package/dist/src/derive/src/rewrite.js +0 -100
  56. package/dist/src/derive/src/trie.d.ts +0 -90
  57. package/dist/src/derive/src/trie.js +0 -217
  58. package/dist/src/derive/test/derive.test.d.ts +0 -1
  59. package/dist/src/derive/test/derive.test.js +0 -122
  60. package/dist/src/extension.d.ts +0 -37
  61. package/dist/src/extension.js +0 -7
  62. package/dist/src/geometry.d.ts +0 -233
  63. package/dist/src/geometry.js +0 -1089
  64. package/dist/src/index.d.ts +0 -17
  65. package/dist/src/index.js +0 -19
  66. package/dist/src/ingest-cache.d.ts +0 -41
  67. package/dist/src/ingest-cache.js +0 -165
  68. package/dist/src/meter.d.ts +0 -176
  69. package/dist/src/meter.js +0 -274
  70. package/dist/src/mind/articulation.d.ts +0 -6
  71. package/dist/src/mind/articulation.js +0 -99
  72. package/dist/src/mind/attention.d.ts +0 -430
  73. package/dist/src/mind/attention.js +0 -2418
  74. package/dist/src/mind/bridge.d.ts +0 -37
  75. package/dist/src/mind/bridge.js +0 -907
  76. package/dist/src/mind/canonical.d.ts +0 -34
  77. package/dist/src/mind/canonical.js +0 -93
  78. package/dist/src/mind/graph-search.d.ts +0 -294
  79. package/dist/src/mind/graph-search.js +0 -996
  80. package/dist/src/mind/index.d.ts +0 -9
  81. package/dist/src/mind/index.js +0 -5
  82. package/dist/src/mind/junction.d.ts +0 -137
  83. package/dist/src/mind/junction.js +0 -358
  84. package/dist/src/mind/learning.d.ts +0 -75
  85. package/dist/src/mind/learning.js +0 -265
  86. package/dist/src/mind/match.d.ts +0 -351
  87. package/dist/src/mind/match.js +0 -959
  88. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  89. package/dist/src/mind/mechanisms/alu.js +0 -36
  90. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  91. package/dist/src/mind/mechanisms/cast.js +0 -1186
  92. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  93. package/dist/src/mind/mechanisms/confluence.js +0 -271
  94. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  95. package/dist/src/mind/mechanisms/cover.js +0 -232
  96. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  97. package/dist/src/mind/mechanisms/extraction.js +0 -327
  98. package/dist/src/mind/mechanisms/prefix-completion.d.ts +0 -22
  99. package/dist/src/mind/mechanisms/prefix-completion.js +0 -243
  100. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  101. package/dist/src/mind/mechanisms/recall.js +0 -460
  102. package/dist/src/mind/mechanisms/reference.d.ts +0 -6
  103. package/dist/src/mind/mechanisms/reference.js +0 -296
  104. package/dist/src/mind/mind.d.ts +0 -386
  105. package/dist/src/mind/mind.js +0 -754
  106. package/dist/src/mind/pipeline-mechanism.d.ts +0 -238
  107. package/dist/src/mind/pipeline-mechanism.js +0 -622
  108. package/dist/src/mind/pipeline.d.ts +0 -49
  109. package/dist/src/mind/pipeline.js +0 -343
  110. package/dist/src/mind/primitives.d.ts +0 -85
  111. package/dist/src/mind/primitives.js +0 -333
  112. package/dist/src/mind/rationale.d.ts +0 -139
  113. package/dist/src/mind/rationale.js +0 -163
  114. package/dist/src/mind/reasoning.d.ts +0 -42
  115. package/dist/src/mind/reasoning.js +0 -305
  116. package/dist/src/mind/recognition.d.ts +0 -20
  117. package/dist/src/mind/recognition.js +0 -696
  118. package/dist/src/mind/resonance.d.ts +0 -35
  119. package/dist/src/mind/resonance.js +0 -365
  120. package/dist/src/mind/trace.d.ts +0 -15
  121. package/dist/src/mind/trace.js +0 -73
  122. package/dist/src/mind/traverse.d.ts +0 -196
  123. package/dist/src/mind/traverse.js +0 -806
  124. package/dist/src/mind/types.d.ts +0 -418
  125. package/dist/src/mind/types.js +0 -179
  126. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  127. package/dist/src/rabitq-ivf/src/database.js +0 -201
  128. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  129. package/dist/src/rabitq-ivf/src/index.js +0 -4
  130. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  131. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  132. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  133. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  134. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  135. package/dist/src/rabitq-ivf/src/rabitq.js +0 -313
  136. package/dist/src/sema.d.ts +0 -41
  137. package/dist/src/sema.js +0 -77
  138. package/dist/src/store-sqlite.d.ts +0 -184
  139. package/dist/src/store-sqlite.js +0 -942
  140. package/dist/src/store.d.ts +0 -762
  141. package/dist/src/store.js +0 -1823
  142. package/dist/src/vec.d.ts +0 -31
  143. package/dist/src/vec.js +0 -109
@@ -1,907 +0,0 @@
1
- // bridge.ts — corroborated-substitution grounding (recall's last tier before
2
- // refusal).
3
- //
4
- // THE GAP (test/49): a query phrased through a near-synonym of a trained
5
- // word ("Name the biggest planet." against a corpus that only ever says
6
- // "largest planet") reaches nothing — recognition finds no form, whole-query
7
- // resonance stays below the reach bar — even though the fact is trained and
8
- // the synonym pairing is corroborated across the corpus. Words are never
9
- // independently addressable nodes (deposit interns whole streams plus W-1/W
10
- // leaf windows; a word mid-sentence falls between those scales), so no halo
11
- // ever links "biggest" to "largest" — and the write side cannot cheaply
12
- // mint such nodes without polluting the shared indexes (measured: an
13
- // earlier write-side attempt regressed 24 unrelated tests).
14
- //
15
- // THE MECHANISM — read-only, refusal-path-only. When recall is about to
16
- // refuse, the query's own content-addressed windows (the W-byte leaf-id
17
- // flat branches indexSubSpans already interns at every byte offset) are
18
- // probed against the store; the rarest ones anchor a climb (edgeAncestors —
19
- // the same climb consensus voting uses) to the trained contexts that
20
- // contain them. Each candidate context is ALIGNED to the query byte-for-
21
- // byte around the anchor, leaving mismatched spans; a mismatch grounds as a
22
- // SUBSTITUTION only under two derived gates:
23
- //
24
- // • CORROBORATION — the query-side span is itself corpus-attested: every
25
- // W-window inside it resolves as a stored flat form, at least one of
26
- // them reused across ≥ 2 containers (the same "≥ 2 structural parents"
27
- // bar propagateSuffixes gates suffix inheritance with). An untrained
28
- // word ("deadliest") has no stored windows and can never substitute.
29
- // • GRADED IDENTITY — lexical geometry is tried first at
30
- // conceptThreshold(D). Differently-spelled forms fall through to VSA
31
- // company: their stored W-window occurrences ascend to learned episodes,
32
- // whose bundled halos must clear significanceBar(D), the same
33
- // distributional-evidence bar used by analogyStrength.
34
- //
35
- // A candidate context is accepted when its aligned-plus-substituted spans
36
- // DOMINATE the query (the same half-dominance predicate used throughout)
37
- // and every unexplained gap stays within one perception window W (the same
38
- // single-window tolerance identityBar prices). The accepted context is
39
- // then grounded exactly like any recall hit — project() through its learnt
40
- // edges — so the answer is a trained continuation, never synthesized bytes.
41
- //
42
- // COST: nothing on any answering path — the bridge runs only where the
43
- // alternative was silence. There it pays O(|query|) content-hash probes
44
- // (the propagateSuffixes trick), at most W anchor climbs and
45
- // 2·recallQueryK candidate reads, and one
46
- // O(|query|·|candidate|)-bounded alignment each.
47
- //
48
- // FIXED WRONG-ANSWER GAP (found and closed 2026-07-20): a proper-noun swap
49
- // could pass both derived gates above and voice a WRONG fact. Live case:
50
- // "The capital of France is" (a prefix-completion probe) bridged through a
51
- // substitution reading "of Fra[nce]" as "of Spain si[nce]" into "Madrid has
52
- // been the capital of Spain since 1561...", because the TRUE France fact
53
- // ("The capital of France is Paris.") is a terminal statement with no
54
- // outgoing edge and is therefore never admitted as a bridge candidate (§
55
- // candidate admission above) — so no competing evidence for "France" was
56
- // ever collected, and the Spain candidate's own text satisfied frame
57
- // unanimity vacuously (nothing to disagree with).
58
- // REFUTED FIX 1 — require unanimous()'s frame-consensus scan to find a
59
- // genuine corroborating occurrence (not vacuous-true on zero evidence):
60
- // breaks test/49 — "biggest"~"largest" is corroborated ONLY by the very
61
- // candidate proposing the substitution in that miniature corpus (no
62
- // OTHER trained pair pairs either word with "planet"); requiring
63
- // external evidence makes that legitimate case fail too.
64
- // REFUTED FIX 2 — exclude the candidate's own bytes from being its own
65
- // corroborating witness (same idea, scoped to self-reference): same
66
- // failure, same reason — self-witness is ALL the evidence test/49 has.
67
- // REFUTED FIX 3 — require the CANDIDATE-side substituted span to also
68
- // clear the ≥2-container reuse bar (attestedSpan, symmetric with the
69
- // query-side attestedQ): does not discriminate — "Spain" is reused
70
- // across at least as many trained contexts as "France" is, so it
71
- // passes trivially.
72
- // THE ACTUAL FIX — RAW BALANCE (see the substitution loop below): the raw
73
- // mismatch (BEFORE expansion absorbs any matched flanking bytes) must
74
- // be roughly length-balanced on both sides — dominates(min(uLen,cLen),
75
- // max(uLen,cLen)), the SAME "part*2 > whole" bar used throughout the
76
- // codebase, no new constant. Measured on both cases: the legitimate
77
- // "biggest"~"largest" substitution's raw diff is "big"/"lar" (3/3
78
- // bytes, perfectly balanced — expansion then absorbs the shared "gest"
79
- // suffix, identical on both sides, to reach an attestable span). The
80
- // wrong "France"~"Spain" substitution's raw diff was "Fra"/"Spai" (3/8
81
- // bytes) — the align sweep's greedy search had found a coincidental
82
- // "nce " match years later inside "since", so 3 bytes of query content
83
- // were standing in for 8 bytes of candidate content. That asymmetry is
84
- // exactly what a real lexical/morphological synonym never has and an
85
- // arbitrary sentence divergence always does; expansion (which only
86
- // grows both sides by IDENTICAL absorbed bytes) can never repair a raw
87
- // imbalance, so gating on the RAW gap is the correct point of attack.
88
- // Verified: real-store repro now falls through to an honest echo of
89
- // the true trained fact instead of the wrong Spain continuation; the
90
- // boiling-point and lowercase-France bridge wins are unaffected; full
91
- // suite green (358/358).
92
- import { cosine } from "../vec.js";
93
- import { conceptThreshold, dominates, significanceBar } from "../geometry.js";
94
- import { bytesEqual, indexOf } from "../bytes.js";
95
- import { foldTree, perceive, read } from "./primitives.js";
96
- import { chainReach, leafIdRun } from "./canonical.js";
97
- import { allWindowsAreScaffolding, corpusN, edgeAncestors, hubBound, sharedReachMemo, } from "./traverse.js";
98
- import { rItem, rNode } from "./trace.js";
99
- import { junctionContainersFrom } from "./junction.js";
100
- import { alignAround, spanHalo } from "./match.js";
101
- /** True when some query byte-range left UNACCOUNTED by `spans` contains a
102
- * STORED window — content the store has seen that the proposed reading
103
- * simply ignores. The IGNORED-KNOWN principle: a span may be dismissed
104
- * only when the store itself has never seen it; known content the
105
- * alignment failed to account for is grounds for refusal, while genuinely
106
- * novel spans (an untrained word, stray punctuation) remain tolerable.
107
- * Shared by the substitution bridge's own acceptance and CAST's
108
- * frame-tier comparison gate (cast.ts). Pure attestation — no
109
- * similarity, no constants. */
110
- export function dismissedKnownContent(ctx, query, spans) {
111
- const W = ctx.space.maxGroup;
112
- const sorted = [...spans].sort((a, b) => a[0] - b[0]);
113
- let cursor = 0;
114
- for (const [s, e] of [...sorted, [query.length, query.length]]) {
115
- for (let o = cursor; o + W <= s; o++) {
116
- const ids = leafIdRun(ctx, query, o, o + W);
117
- if (ids !== null && ctx.store.findBranch(ids) !== null)
118
- return true;
119
- }
120
- cursor = Math.max(cursor, e);
121
- }
122
- return false;
123
- }
124
- // The seeded aligner this file used to own now lives in the shared match
125
- // family as {@link alignAround} — the frame reading (match.ts) reads the same
126
- // gaps and asks the OPPOSITE question of them (see AlignGap's own doc). Two
127
- // consumers, one definition (AGENTS §2.5); the bridge's reading is unchanged.
128
- const align = alignAround;
129
- /** Recall's corroborated-substitution bridge — see the module comment.
130
- * Returns the best bridged grounding proposal, or null. */
131
- /** `proposed` is a THUNK, not a list: the bridge's own cheap gates (the
132
- * two-quantum query floor and the O(|query|) stored-window anchor scan)
133
- * decide whether ANY candidate can be aligned, and they need no proposals
134
- * to do it. Resolving the caller's proposals eagerly meant recall paid its
135
- * exhaustive whole-index resonance — the most expensive single act on the
136
- * refusal path — for every query, including the ones whose windows the
137
- * store has never seen and which the anchor scan rejects outright. Same
138
- * investment discipline the mechanism floors follow (AGENTS §2.6): never
139
- * compute a shared analysis just to discard it. */
140
- export async function substitutionBridge(ctx, query, proposed = async () => []) {
141
- const meter = ctx.meter;
142
- return meter
143
- ? meter.time("substitutionBridge", () => bridgeImpl(ctx, query, proposed))
144
- : bridgeImpl(ctx, query, proposed);
145
- }
146
- async function bridgeImpl(ctx, query, proposed) {
147
- const W = ctx.space.maxGroup;
148
- if (query.length < 2 * W)
149
- return null;
150
- const bound = hubBound(ctx);
151
- const N = corpusN(ctx);
152
- const marketScale = ctx.cfg.recallQueryK * W;
153
- const candidateCap = N <= marketScale ** 3 ? bound : 2 * ctx.cfg.recallQueryK;
154
- const bar = conceptThreshold(ctx.store.D);
155
- const synonymBar = significanceBar(ctx.store.D);
156
- const reachCap = chainReach(W);
157
- const diagnostics = ctx.trace
158
- ? {
159
- anchors: 0,
160
- picked: 0,
161
- proposed: 0,
162
- structuralProposed: 0,
163
- proposedGrounded: 0,
164
- synonymChecks: 0,
165
- bestSynonym: 0,
166
- climbed: 0,
167
- phraseScale: 0,
168
- seeded: 0,
169
- aligned: 0,
170
- structurallyValid: 0,
171
- coverageValid: 0,
172
- identityValid: 0,
173
- knownContentValid: 0,
174
- bestCovered: 0,
175
- bestRank: -1,
176
- closest: [],
177
- }
178
- : null;
179
- // PHRASE-SCALE CANDIDATE CAP — the same |content|·W bound the weave
180
- // (pipeline-mechanism.ts), the cross-region junction ladder's
181
- // `maxInterior`, and structural resonance's `maxSiblingBytes` all apply,
182
- // for the same reason and now at the one remaining place that read
183
- // candidate contexts WHOLE.
184
- //
185
- // The bridge accepts a candidate only when the query is DOMINATED by its
186
- // matched runs plus substitutions, with at most one window W of slack at
187
- // each edge and at most one chain reach (W²) per interior gap — so the
188
- // candidate region an accepted alignment can ever consume is bounded by
189
- // |query|·W. Content beyond that cannot participate in any alignment
190
- // this function would accept; reading it is pure cost. And a candidate
191
- // an order of magnitude past the query is not a paraphrase of it: it is a
192
- // document or a whole conversation that merely quotes a phrase, and
193
- // grounding through ITS learnt edge voices that document's continuation,
194
- // not a phrase answer.
195
- //
196
- // Measured on the 17.7M-node / 325K-context store: uncapped, the refusal
197
- // path materialised up to ~1 MB of candidate bytes per query (up to √N
198
- // proposals plus √N climbed contexts, each read in full), and the frame-
199
- // unanimity scan — which walks EVERY collected candidate's bytes, inside
200
- // the per-gap expansion loop — paid that volume back tens of times per
201
- // substitution. Recall's run() was 0.7–2.6 s per refusing query.
202
- const capBytes = query.length * W;
203
- /** A candidate's bytes, phrase-scale capped: null when it exceeds the cap
204
- * (read one byte past it, so "too long" is decided without materialising
205
- * the rest) or has no content. */
206
- const candidateBytes = (sid) => {
207
- const b = read(ctx, sid, capBytes + 1);
208
- return b.length === 0 || b.length > capBytes ? null : b;
209
- };
210
- // 1. The query's stored windows, rarest first (fewest containers — the
211
- // most discriminative anchors; hub-clamped like every fan-out read).
212
- // The scan doubles as the ONE store probe of every query window: the
213
- // per-offset stored/reused facts it establishes serve every later
214
- // attestation and ignored-known check as plain array reads (the same
215
- // probes repeated per candidate dominated the refusal-path cost).
216
- const nWin = Math.max(0, query.length - W + 1);
217
- const winStored = new Uint8Array(nWin);
218
- const winReused = new Uint8Array(nWin);
219
- const anchors = [];
220
- for (let o = 0; o + W <= query.length; o++) {
221
- const ids = leafIdRun(ctx, query, o, o + W);
222
- if (ids === null)
223
- continue;
224
- const id = ctx.store.findBranch(ids);
225
- if (id === null)
226
- continue;
227
- winStored[o] = 1;
228
- const rarity = ctx.store.containersSlice(id, 0, bound + 1).length;
229
- if (rarity >= 2)
230
- winReused[o] = 1;
231
- if (rarity === 0)
232
- continue;
233
- anchors.push({ off: o, id, rarity });
234
- }
235
- if (diagnostics)
236
- diagnostics.anchors = anchors.length;
237
- if (anchors.length === 0) {
238
- ctx.trace?.step("substitutionBridge", [rItem(query, "query")], [], "no stored query window can anchor a corroborated substitution", undefined, diagnostics);
239
- return null;
240
- }
241
- // NO DISCRIMINATING LITERAL EVIDENCE — abstain (§2.13). A bridge grounds
242
- // through the literal spans it did NOT substitute; those anchors are the
243
- // whole of its evidence. When every one of them is SATURATED — containment
244
- // clamped at the √N hub bound, i.e. the window is corpus-global scaffolding
245
- // — the query's unsubstituted part discriminates nothing, and the single
246
- // substituted span is carrying the entire semantic load. That is not a
247
- // corroborated bridge; it is a template match, and it FABRICATES.
248
- //
249
- // Measured on the trained store (hubBound 571). "What is the capital of"
250
- // has 19 anchors, ALL saturated ("What":572, "hat ":572, "at i":572 …), and
251
- // bridged to an unrelated trained context about an integral, voiced
252
- // confidently. Every query the bridge answers CORRECTLY has at least one
253
- // unsaturated anchor, by a wide margin and with no near miss:
254
- // "Who is the author of Hamlet?" → "let?":12, "How do you say 'thank you'
255
- // in French?" → "y 't":3, "…largest planet…" → "tem?":31, "What is the
256
- // capital of France?" → "f Fr":114. The honest-silence probes sit on the
257
- // same side as the correct ones ("Zamu":3), so this gate is not what makes
258
- // them silent and cannot be credited for them.
259
- //
260
- // This introduces NO new threshold: `bound` is the same √N reading of "hub"
261
- // the anchor scan already clamps its own containment read to (§2.2, §2.7).
262
- if (allWindowsAreScaffolding(ctx, query)) {
263
- ctx.trace?.step("substitutionBridge", [rItem(query, "query")], [], "every query window that could anchor is corpus-global scaffolding — " +
264
- "no literal evidence to corroborate a substitution", undefined, diagnostics);
265
- return null;
266
- }
267
- // CORROBORATION (see the module-level doc) over the precomputed window
268
- // facts: the query span [qs,qe) attests when every full W-window inside
269
- // it is a stored flat form and at least one is reused across ≥ 2
270
- // containers. Spans shorter than W carry no window of their own and can
271
- // never substitute.
272
- const attestedQ = (qs, qe) => {
273
- if (qe - qs < W)
274
- return false;
275
- let reused = false;
276
- for (let o = qs; o + W <= qe; o++) {
277
- if (!winStored[o])
278
- return false;
279
- if (winReused[o])
280
- reused = true;
281
- }
282
- return reused;
283
- };
284
- // dismissedKnownContent (see above) over the same precomputed facts.
285
- const dismissedKnownQ = (spans) => {
286
- const sorted = [...spans].sort((a, b) => a[0] - b[0]);
287
- let cursor = 0;
288
- for (const [s, e] of [...sorted, [query.length, query.length]]) {
289
- for (let o = cursor; o + W <= s; o++)
290
- if (winStored[o])
291
- return true;
292
- cursor = Math.max(cursor, e);
293
- }
294
- return false;
295
- };
296
- // ── EXPLAINED SPANS — the scaffolding judgement, corpus-global ──────────
297
- //
298
- // The question every gap poses is "may the two forms differ HERE without
299
- // differing in what they SAY?", and that is the discriminative-vs-
300
- // scaffolding question AGENTS §2.7 names, over the CORPUS-GLOBAL
301
- // population. It already has one definition — `dominates(reachOf(...), N)`,
302
- // the same gate confluence's filler test uses ("scaffolding never binds").
303
- // Nothing new is derived here; the bar is read, not invented.
304
- //
305
- // A span is explained when EITHER
306
- // • it is sub-quantum (< W) — typographic glue, the tolerance identityBar
307
- // already prices ("below one river window, byte overlap is chance"); or
308
- // • every full W-window inside it is COMMON by the store's own climb:
309
- // the ascent SATURATES (the window sits in more places than √N — the
310
- // climb's own definition of non-discriminative), or it resolves to a
311
- // majority of the corpus's contexts. "the process of ", " is the ".
312
- //
313
- // THE READING MATTERS, not just the population (AGENTS §2.7). This
314
- // deliberately does NOT go through `reachOf`, which maps BOTH "saturated"
315
- // and "reaches nothing" to Infinity. For IDF weighting those are the same
316
- // thing (no usable identity evidence); for THIS question they are
317
- // opposites — a window reaching nothing is novel content, the most
318
- // discriminative material there is, and reading it as Infinity would call
319
- // it scaffolding. Measured: with `reachOf`, "Is water wet?" was answered
320
- // with "No, heavy water is not wet." — "heav"/"eavy" occur once, reach no
321
- // edge-bearing ancestor, and were written off as filler. So an
322
- // empty-rooted window is NEVER explained, and neither is an untrained one
323
- // (the same principle attestedQ applies to the query side).
324
- const reachMemo = sharedReachMemo(ctx);
325
- const explainedSpan = (bytes, from, to) => {
326
- if (to - from < W)
327
- return true;
328
- const common = (start, end) => {
329
- if (end - start < W)
330
- return false;
331
- for (let o = start; o + W <= end; o++) {
332
- const ids = leafIdRun(ctx, bytes, o, o + W);
333
- if (ids === null)
334
- return false;
335
- const wid = ctx.store.findBranch(ids);
336
- if (wid === null)
337
- return false;
338
- const r = edgeAncestors(ctx, wid, N, reachMemo);
339
- if (r.saturated)
340
- continue; // in too many places to discriminate
341
- if (r.roots.length === 0)
342
- return false; // reaches nothing: novel content
343
- if (!dominates(r.contextsReached, N))
344
- return false;
345
- }
346
- return true;
347
- };
348
- if (common(from, to))
349
- return true;
350
- // Alignment may attach the shared delimiter to either side of an inserted
351
- // phrase. Up to W-1 boundary bytes are below the fold's identity scale;
352
- // classify the phrase by a full-window interior core when one exists.
353
- // This does not erase a short discriminative insertion: "heavy" still
354
- // leaves the full `heav`/`eavy` windows for the corpus-global test.
355
- for (let left = 0; left < W; left++) {
356
- for (let right = 0; right < W; right++) {
357
- if (left + right === 0 || left + right >= W)
358
- continue;
359
- if (common(from + left, to - right))
360
- return true;
361
- }
362
- }
363
- return false;
364
- };
365
- anchors.sort((a, b) => a.rarity - b.rarity);
366
- // Up to W anchors, at least one window apart — the quantum's own count.
367
- const picked = [];
368
- for (const a of anchors) {
369
- if (picked.length >= W)
370
- break;
371
- if (picked.some((p) => Math.abs(p.off - a.off) < W))
372
- continue;
373
- picked.push(a);
374
- }
375
- if (diagnostics)
376
- diagnostics.picked = picked.length;
377
- // 2. Candidate trained contexts. Two proposal channels, one verifier:
378
- // (a) the caller's PROPOSED hits — recall's whole-query resonance
379
- // ranking, the retrieval structure built to surface near-paraphrase
380
- // forms the window climb cannot single out at corpus scale; (b) each
381
- // picked anchor climbed to its edge-bearing ancestors (the same climb
382
- // consensus voting uses). Both are only ever PROPOSALS — every
383
- // candidate passes the same byte-exact alignment and gates below.
384
- const seen = new Set();
385
- const candidates = [];
386
- // Exact co-occurrence proposes contexts the whole-form ANN can miss when a
387
- // short insertion shifts every later fold boundary. The byte alignment below
388
- // remains the decider. All pairs share one candidateCap·W junction
389
- // allowance, ordered
390
- // by their rarest side and then span: a rare content window joined to a
391
- // distant frame boundary discriminates a whole question better than two
392
- // neighbouring rare windows inside the same word.
393
- if (query.length <= 2 * reachCap) {
394
- const pairs = [];
395
- for (let i = 0; i < picked.length; i++) {
396
- for (let j = i + 1; j < picked.length; j++) {
397
- pairs.push([picked[i], picked[j]]);
398
- }
399
- }
400
- pairs.sort((a, b) => Math.min(a[0].rarity, a[1].rarity) -
401
- Math.min(b[0].rarity, b[1].rarity) ||
402
- Math.abs(b[0].off - b[1].off) - Math.abs(a[0].off - a[1].off) ||
403
- a[0].rarity + a[1].rarity - b[0].rarity - b[1].rarity);
404
- const structuralBudget = {
405
- n: chainReach(W) * W * ctx.cfg.recallQueryK,
406
- };
407
- for (const [left, right] of pairs.slice(0, W)) {
408
- const found = junctionContainersFrom(ctx, query.subarray(left.off, left.off + W), query.subarray(right.off, right.off + W), capBytes, [left.id], [right.id], structuralBudget, true);
409
- for (const hit of found) {
410
- if (candidates.length >= candidateCap)
411
- break;
412
- if (seen.has(hit.id) || !ctx.store.hasNext(hit.id))
413
- continue;
414
- seen.add(hit.id);
415
- candidates.push(hit.id);
416
- if (diagnostics)
417
- diagnostics.structuralProposed++;
418
- }
419
- }
420
- }
421
- // Once exact structural proposals fill the shared cap, no caller proposal
422
- // can enter the verifier. Do not evaluate the lazy ANN thunk merely to
423
- // discard every result at the loop's first guard.
424
- const proposedIds = candidates.length < candidateCap ? await proposed() : [];
425
- if (diagnostics)
426
- diagnostics.proposed = proposedIds.length;
427
- for (const sid of proposedIds) {
428
- if (candidates.length >= candidateCap)
429
- break;
430
- if (seen.has(sid))
431
- continue;
432
- seen.add(sid);
433
- const tb = candidateBytes(sid);
434
- if (tb === null)
435
- continue;
436
- if (!picked.some((a) => indexOf(tb, query.subarray(a.off, a.off + W), 0) >= 0))
437
- continue;
438
- let use = sid;
439
- if (!ctx.store.hasNext(use)) {
440
- const folded = foldTree(ctx, perceive(ctx, tb), 0).node;
441
- if (folded === null || folded === sid || !ctx.store.hasNext(folded)) {
442
- continue;
443
- }
444
- use = folded;
445
- if (seen.has(use))
446
- continue;
447
- seen.add(use);
448
- }
449
- candidates.push(use);
450
- if (diagnostics)
451
- diagnostics.proposedGrounded++;
452
- }
453
- // Proposal channel — carries its caller's own bound (recall's resonance
454
- // k), sharing the 2·recallQueryK candidate allowance
455
- // with the structural and climb channels. A proposal may
456
- // be a FLAT content twin whose continuation edge lives on the
457
- // fold-shaped deposit node with the same bytes — the same twin split
458
- // canonResolve bridges by re-folding (primitives.ts) — but the re-fold
459
- // (a full perceive of the candidate's bytes) is paid only for proposals
460
- // that could align at all: alignment can only seed at a picked anchor
461
- // window occurring literally in the candidate (measured: unconditional
462
- // re-folds multiplied the refusal-path latency several-fold).
463
- // FIRST TOUCH of the caller's proposals — past every gate that could have
464
- // refused without them (see substitutionBridge's doc).
465
- // Climb channel — edge-bearing ancestors only, decided by the indexed
466
- // O(1) hasNext; no byte is read here (the climb visits hundreds of
467
- // roots, and reading each was measured to dominate the refusal path).
468
- for (const a of picked) {
469
- const reach = edgeAncestors(ctx, a.id, N, reachMemo);
470
- for (const sid of reach.roots) {
471
- if (candidates.length >= candidateCap)
472
- break;
473
- if (seen.has(sid))
474
- continue;
475
- seen.add(sid);
476
- if (!ctx.store.hasNext(sid))
477
- continue;
478
- candidates.push(sid);
479
- if (diagnostics)
480
- diagnostics.climbed++;
481
- }
482
- if (candidates.length >= candidateCap)
483
- break;
484
- }
485
- // 3. Align each candidate; gate its mismatches; keep the best.
486
- // Over-cap candidates are dropped here rather than earlier: the climb
487
- // channel deliberately reads no bytes while collecting (the climb visits
488
- // hundreds of roots), so this is where its proposals are first sized.
489
- //
490
- // Candidate bytes are read LAZILY — on first access during the seed
491
- // check — not eagerly for every collected id. Most climb-proposed
492
- // candidates fail the seed check and never reach the expensive identity
493
- // and frame-consensus gates.
494
- //
495
- // Frame unanimity is different: once any candidate reaches that gate, it
496
- // must be evaluated against the COMPLETE collected candidate population,
497
- // not only the prefix whose bytes happened to be loaded earlier. The full
498
- // phrase-scale population is therefore materialised once, lazily, on the
499
- // first unanimous() call and reused afterward.
500
- //
501
- // Null results are memoised too, so an empty or over-cap candidate is never
502
- // read repeatedly by the candidate loop and the population materialiser.
503
- const candidateByteMemo = new Map();
504
- /** Read one candidate at most once. Returns null when it exceeds the
505
- * phrase-scale cap or has no content. */
506
- const bytesOfCandidate = (sid) => {
507
- const cached = candidateByteMemo.get(sid);
508
- if (cached !== undefined)
509
- return cached;
510
- const b = candidateBytes(sid);
511
- candidateByteMemo.set(sid, b);
512
- return b;
513
- };
514
- let framePopulation = null;
515
- /** Return the complete phrase-scale candidate population.
516
- *
517
- * This is intentionally lazy: queries that never reach frame unanimity
518
- * keep the cheap per-candidate seed path. Once required, every candidate
519
- * is bounded by candidateBytes(), loaded at most once, and all subsequent
520
- * unanimity checks observe the same order-independent population.
521
- */
522
- const ensureFramePopulation = () => {
523
- if (framePopulation !== null) {
524
- return framePopulation;
525
- }
526
- const complete = new Map();
527
- for (const sid of candidates) {
528
- const bytes = bytesOfCandidate(sid);
529
- if (bytes !== null) {
530
- complete.set(sid, bytes);
531
- }
532
- }
533
- framePopulation = complete;
534
- if (diagnostics) {
535
- diagnostics.phraseScale = complete.size;
536
- }
537
- return complete;
538
- };
539
- // FRAME UNANIMITY: a substitution U → C inside the frame (Lf, Rf) is
540
- // groundable only when the collected candidates — the store's own sample
541
- // of contexts sharing the query's content — are unanimous about the
542
- // filler: every occurrence of Lf…Rf across them holds either U (the
543
- // query's own word, corroboration) or C. A THIRD distinct filler means
544
- // the frame is a VALUE SLOT ("was born in _" held Germany, Poland,
545
- // England, Serbia — observed live), and picking one value would assert
546
- // knowledge the store does not have. Consensus of the store's own
547
- // instances, no similarity judgement, no tuned constant.
548
- // Requires a genuine CORROBORATING sighting, not merely the absence of a
549
- // conflicting one: scanning only the handful of resonance/climb-proposed
550
- // candidates means the frame can easily occur NOWHERE else among them
551
- // (observed live: "of Fra[nce]" -> "of Spain si[nce]" passed vacuously —
552
- // the frame "tal …nce " never recurred among the collected candidates at
553
- // all, so there was no consensus, only an absence of disagreement, yet
554
- // the substitution was accepted). "Unanimous" must mean the store's own
555
- // instances agree, which requires at least one instance to consult.
556
- const unanimous = (u, c, lf, rf) => {
557
- const population = ensureFramePopulation();
558
- for (const bytes of population.values()) {
559
- let from = 0;
560
- for (;;) {
561
- const i = indexOf(bytes, lf, from);
562
- if (i < 0)
563
- break;
564
- from = i + 1;
565
- const start = i + lf.length;
566
- const j = indexOf(bytes.subarray(start, start + reachCap + rf.length), rf, 0);
567
- if (j < 0)
568
- continue;
569
- const filler = bytes.subarray(start, start + j);
570
- if (filler.length === 0)
571
- continue;
572
- if (!bytesEqual(filler, u) && !bytesEqual(filler, c))
573
- return false;
574
- }
575
- }
576
- return true;
577
- };
578
- // (A candidate need NOT contain the query's rarest window literally: the
579
- // rarest window may sit INSIDE the very word being substituted (observed
580
- // live: "chemical symbol for water" whose rarest window "l sy" spans
581
- // "symbol" — the trained formula-question can never contain it). A
582
- // candidate that instead dodges the query's known content by writing it
583
- // off as gaps is refused by dismissedKnownContent below, which subsumes
584
- // the old rarest-window containment gate: rare windows inside an accepted
585
- // substitution are accounted for; rare windows outside the accepted spans
586
- // force refusal (the Matrix-synopsis junk stays dead by exactly that
587
- // check — verified live).
588
- let best = null;
589
- let bestAccounted = 0;
590
- const queryHaloMemo = new Map();
591
- const candidateHaloMemo = new Map();
592
- for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
593
- const sid = candidates[candidateIndex];
594
- // Read bytes lazily — most climb-proposed candidates have no picked
595
- // anchor window and will never pass the seed check below, so their
596
- // bytes are never read at all.
597
- const cBytes = bytesOfCandidate(sid);
598
- if (cBytes === null)
599
- continue;
600
- // Seed at the rarest picked anchor that literally occurs in this
601
- // candidate.
602
- let seed = null;
603
- for (const a of picked) {
604
- const co = indexOf(cBytes, query.subarray(a.off, a.off + W), 0);
605
- if (co >= 0) {
606
- seed = { qo: a.off, co };
607
- break;
608
- }
609
- }
610
- if (seed === null)
611
- continue;
612
- if (diagnostics)
613
- diagnostics.seeded++;
614
- const { matched, gaps } = align(ctx, query, cBytes, seed.qo, seed.co);
615
- if (diagnostics)
616
- diagnostics.aligned++;
617
- // Investment gate: even treating every two-sided mismatch as a valid
618
- // synonym, can this alignment satisfy the bridge's final coverage rule?
619
- // Distributional span composition performs bounded ancestor climbs; never
620
- // pay for it on a candidate arithmetic already proves cannot win.
621
- let matchStart = query.length;
622
- let matchEnd = 0;
623
- let potential = 0;
624
- for (const [s, e] of matched) {
625
- matchStart = Math.min(matchStart, s);
626
- matchEnd = Math.max(matchEnd, e);
627
- potential += e - s;
628
- }
629
- for (const g of gaps) {
630
- if (g.qe > g.qs && g.ce > g.cs)
631
- potential += g.qe - g.qs;
632
- }
633
- if (matchStart > W || query.length - matchEnd > W ||
634
- !dominates(potential, query.length))
635
- continue;
636
- // Gate each mismatch: a corroborated, geometrically-identified
637
- // substitution counts as accounted; anything else stays a gap.
638
- //
639
- // A raw mismatch is the MINIMAL byte diff ("big" ↔ "lar" inside
640
- // biggest/largest), usually below the scale at which either side is a
641
- // corpus unit. The true unit is found by EXPANSION: absorb flanking
642
- // bytes from the adjacent matched runs (equal on both sides by
643
- // construction, so both spans grow identically) until the query side
644
- // attests and the pair clears the concept bar — smallest expansion
645
- // first, capped at chainReach like the mismatch itself. Absorbed
646
- // bytes were already matched, so coverage is unchanged.
647
- const subs = [];
648
- let ok = true;
649
- for (const g of gaps) {
650
- const uLen = g.qe - g.qs, cLen = g.ce - g.cs;
651
- if (uLen === 0 || cLen === 0 || uLen > reachCap || cLen > reachCap) {
652
- // Pure insertion/deletion or over-long mismatch. Query-side: one
653
- // perception window (the identityBar tolerance). Candidate-side:
654
- // one chain reach (W², the two-level composite bound) — a genuine
655
- // paraphrase inserts inflection-scale material ("does water boil"
656
- // ↔ "should water be boiled"), while a divergent candidate jumps
657
- // hundreds of bytes between the query's frames.
658
- if (uLen > W || cLen > reachCap)
659
- ok = false;
660
- continue;
661
- }
662
- // RAW BALANCE gate (closes the OPEN GAP above): the two sides of a
663
- // genuine lexical substitution swap comparable amounts of content —
664
- // "big"/"lar" (3/3 bytes, before expansion absorbs the shared "gest"
665
- // suffix to reach an attestable "biggest"/"largest"). A candidate
666
- // whose two sentences simply diverge into unrelated continuations
667
- // produces a LOPSIDED raw mismatch instead — the live wrong answer's
668
- // raw gap was "Fra"/"Spai" widened to (3,8) by the align sweep
669
- // finding a coincidental "nce " match years later in "since" — 3
670
- // bytes of query content standing in for 8 bytes of candidate
671
- // content is not a word swap, it is two different sentences that
672
- // happen to share a few letters. Uses the SAME dominates() bar
673
- // (part*2 > whole) applied throughout the codebase, symmetrically:
674
- // the smaller raw side must be more than half the larger. Applies
675
- // to the RAW gap for GEOMETRIC identity, before expansion — expansion
676
- // only ever grows both sides by IDENTICAL absorbed bytes, so it cannot
677
- // fix an imbalance that was already there. Distributional synonym
678
- // evidence is exempt: two phrases may occupy the same role at very
679
- // different lengths.
680
- let accepted = false;
681
- const balanced = dominates(Math.min(uLen, cLen), Math.max(uLen, cLen));
682
- const maxExtra = reachCap - Math.max(uLen, cLen);
683
- outer: for (let extra = 0; extra <= maxExtra; extra++) {
684
- for (let a = 0; a <= extra; a++) {
685
- const b = extra - a;
686
- const qs2 = g.qs - a, qe2 = g.qe + b;
687
- const cs2 = g.cs - a, ce2 = g.ce + b;
688
- if (qs2 < 0 || qe2 > query.length)
689
- continue;
690
- if (cs2 < 0 || ce2 > cBytes.length)
691
- continue;
692
- // INTERIOR gate: a substitution must sit INSIDE matched
693
- // structure — at least one full window of matched bytes must
694
- // remain adjacent on BOTH sides after absorption. Every junk
695
- // substitution observed live sat at the query's edge, with only
696
- // terminal punctuation beyond it ("…born in [England].",
697
- // "…capital of [Zamunda]?"): an edge mismatch is the query
698
- // trailing off into different content, not a word standing in a
699
- // shared frame.
700
- const leftOk = matched.some(([s, e]) => e >= qs2 && qs2 - s >= W);
701
- const rightOk = matched.some(([s, e]) => s <= qe2 && e - qe2 >= W);
702
- if (!leftOk || !rightOk)
703
- continue;
704
- if (!attestedQ(qs2, qe2))
705
- continue;
706
- const u = query.subarray(qs2, qe2);
707
- const cSpan = cBytes.subarray(cs2, ce2);
708
- const geometric = cosine(perceive(ctx, u).v, perceive(ctx, cSpan).v);
709
- const qKey = `${qs2}:${qe2}`;
710
- let qHalo = queryHaloMemo.get(qKey);
711
- if (qHalo === undefined) {
712
- qHalo = spanHalo(ctx, query, qs2, qe2);
713
- queryHaloMemo.set(qKey, qHalo);
714
- }
715
- const cKey = `${sid}:${cs2}:${ce2}`;
716
- let cHalo = candidateHaloMemo.get(cKey);
717
- if (cHalo === undefined) {
718
- cHalo = spanHalo(ctx, cBytes, cs2, ce2);
719
- candidateHaloMemo.set(cKey, cHalo);
720
- }
721
- const distributional = qHalo !== null && cHalo !== null
722
- ? cosine(qHalo, cHalo)
723
- : 0;
724
- if (diagnostics) {
725
- diagnostics.synonymChecks++;
726
- diagnostics.bestSynonym = Math.max(diagnostics.bestSynonym, distributional);
727
- }
728
- // Graded identity: byte geometry remains the cheap first tier;
729
- // VSA company is the synonym tier when differently-spelled forms
730
- // occupy the same learnt distributional role.
731
- if ((!balanced || geometric < bar) &&
732
- distributional < synonymBar) {
733
- continue;
734
- }
735
- if (!unanimous(u, cSpan, query.subarray(qs2 - W, qs2), query.subarray(qe2, qe2 + W)))
736
- continue;
737
- subs.push({ qs: qs2, qe: qe2, cs: cs2, ce: ce2 });
738
- accepted = true;
739
- break outer;
740
- }
741
- }
742
- if (!accepted && (uLen > W || cLen > reachCap))
743
- ok = false;
744
- }
745
- // A candidate with ZERO gaps needs no substitution and might seem like
746
- // the strongest possible bridge, but accepting it here is a trap: this
747
- // mechanism runs only where recall's own resonance/echo tiers already
748
- // declined to ground a same-shape, zero-substitution match — usually
749
- // because the query is a strict byte-PREFIX of several candidates
750
- // (many trained "The capital of X is Y." facts share the query "The
751
- // capital of France is" as a substring once the true France fact is
752
- // filtered out for lacking a continuation edge) and nothing here
753
- // corroborates picking one candidate's completion over another's
754
- // (observed live: prefix-completion bridged to an unrelated "London"
755
- // trivia distractor over the true France fact, which precedes it in
756
- // resonance rank but has no outgoing edge to bridge through). This
757
- // mechanism exists to explain SUBSTITUTIONS; a query needing none is
758
- // recall's job, not the bridge's.
759
- if (!ok)
760
- continue;
761
- if (diagnostics)
762
- diagnostics.structurallyValid++;
763
- // Coverage: matched runs plus accepted substitutions must dominate the
764
- // query, every interior gap already proved ≤ W above, and the EDGES
765
- // must be explained to the same one-window tolerance — the same "at
766
- // most one river window of foreign content" identityBar prices. The
767
- // live junk this closes: alignments that matched a query's scaffolding
768
- // and one substitution but left the query's whole trailing content
769
- // ("…planet orbiting our sun.", 24 bytes) unexplained, yet still
770
- // half-dominated the byte count.
771
- const spans = [
772
- ...matched,
773
- ...subs.map((s) => [s.qs, s.qe]),
774
- ].sort((x, y) => x[0] - y[0]);
775
- let covered = 0;
776
- let reachEnd = 0;
777
- for (const [s, e] of spans) {
778
- if (e <= reachEnd)
779
- continue;
780
- covered += e - Math.max(s, reachEnd);
781
- reachEnd = Math.max(reachEnd, e);
782
- }
783
- if (diagnostics) {
784
- diagnostics.bestCovered = Math.max(diagnostics.bestCovered, covered);
785
- const candidateGapBytes = gaps.reduce((n, g) => n + g.ce - g.cs, 0);
786
- diagnostics.closest.push({
787
- id: sid,
788
- covered,
789
- leading: spans[0][0],
790
- trailing: query.length - reachEnd,
791
- gaps: gaps.length,
792
- substitutions: subs.length,
793
- queryGapBytes: gaps.reduce((n, g) => n + g.qe - g.qs, 0),
794
- candidateGapBytes,
795
- gapRanges: gaps.map((g) => [g.qs, g.qe, g.cs, g.ce]),
796
- candidateSurplus: cBytes.length - covered - candidateGapBytes,
797
- gapsExplained: gaps.every((g) => explainedSpan(cBytes, g.cs, g.ce)),
798
- });
799
- diagnostics.closest.sort((a, b) => b.covered - a.covered ||
800
- a.leading + a.trailing - b.leading - b.trailing ||
801
- a.id - b.id);
802
- if (diagnostics.closest.length > W)
803
- diagnostics.closest.length = W;
804
- }
805
- if (spans[0][0] > W || query.length - reachEnd > W)
806
- continue;
807
- if (!dominates(covered, query.length))
808
- continue;
809
- if (diagnostics)
810
- diagnostics.coverageValid++;
811
- // ZERO-SUBSTITUTION ADMISSION — an IDENTITY claim, not a substitution.
812
- //
813
- // A candidate needing no substitution is normally refused (see the trap
814
- // above), and that refusal is right for the case it was written for: the
815
- // query is a strict byte-PREFIX of several candidates, each of which
816
- // continues differently, and nothing here corroborates picking one
817
- // continuation over another. But that trap has a signature — the
818
- // candidate carries substantial content BEYOND the alignment, and that
819
- // surplus is exactly the "answer" the bridge would be inventing.
820
- //
821
- // The opposite shape is not ambiguous at all: the alignment explains BOTH
822
- // strings end to end, and the only thing between them is sub-quantum glue
823
- // — typographic punctuation the fold treats as structure. Then the two
824
- // are the SAME learnt form, and grounding through its edge returns that
825
- // form's own trained answer, never a chosen-among-many completion.
826
- //
827
- // Why the ladder cannot reach these otherwise: the gist is a STRUCTURAL
828
- // signature, so a mid-string insertion shifts every fold boundary after
829
- // it. Measured: `Who wrote Romeo and Juliet?` against the trained
830
- // `Who wrote "Romeo and Juliet"?` — two inserted quote characters — scores
831
- // cos 0.377, BELOW unrelated neighbours like "Who wrote the opera
832
- // Carmen??" (0.603). Recall's identity tiers gate on identityBar (0.969
833
- // here) and its reach tiers on 0.875, so no gist-based tier can ever see
834
- // it; only byte-exact alignment can, which is what this function does.
835
- //
836
- // The claim is deliberately strict, in three parts:
837
- //
838
- // • QUERY SIDE — EXACT. Every byte of the query must be a literal
839
- // match against the candidate: covered === query.length, no slack at
840
- // all, not even sub-quantum. The query is what we are answering, so
841
- // an identity claim about it may write off NOTHING. This is stricter
842
- // than the ≤ W edge tolerance the substituted path uses, and it has
843
- // to be: with a one-window allowance, `what is 2^10?` matched the
844
- // trained `what is 2+2?` — "^10" against "+2", four bytes, both sides
845
- // below W — and answered "2+2 is 4.", outweighing cover's authoritative
846
- // ALU result. Below W, byte OVERLAP is chance rather than evidence;
847
- // that never made a below-W DIFFERENCE meaningless, and digits are the
848
- // case that proves it.
849
- // • CANDIDATE SIDE, INTERIOR — each gap must be an EXPLAINED span (see
850
- // explainedSpan): sub-quantum glue, or corpus-global scaffolding.
851
- // This side is asymmetric ON PURPOSE. Material the CANDIDATE has and
852
- // the query omits is not something the asker asked about: if it is
853
- // scaffolding, dropping it changes nothing ("What is *the process of*
854
- // photosynthesis?"); if it is discriminative, the candidate answers a
855
- // DIFFERENT, narrower question ("Is *heavy* water wet?") and must be
856
- // refused. Only the corpus can tell those apart, and it does.
857
- // • CANDIDATE SIDE, SURPLUS — its bytes are the matched runs
858
- // (byte-identical to the query's, hence the same total length) plus
859
- // its own gap spans; anything past that is surplus, and surplus is
860
- // the prefix trap. A prefix-completion candidate fails here by the
861
- // whole length of the completion it wanted to supply — which is why
862
- // admitting scaffolding interiors does not reopen that trap.
863
- //
864
- // Ordered cheapest-first: the two arithmetic tests run before
865
- // explainedSpan, whose per-window `reachOf` climbs are the only costly
866
- // part (shared through the response/conversation reach memo, and reached
867
- // only by a candidate that already survived every structural gate).
868
- if (subs.length === 0) {
869
- if (covered !== query.length)
870
- continue;
871
- const cGap = gaps.reduce((n, g) => n + (g.ce - g.cs), 0);
872
- if (cBytes.length - covered - cGap > W)
873
- continue;
874
- if (!gaps.every((g) => explainedSpan(cBytes, g.cs, g.ce)))
875
- continue;
876
- }
877
- if (diagnostics)
878
- diagnostics.identityValid++;
879
- // KNOWN content may never be dismissed — see dismissedKnownContent
880
- // (the live case: "what is the capital of france" aligning into a
881
- // Matrix synopsis by writing off "ance" — a stored window of the
882
- // trained "France" — as a gap, while genuinely novel spans like
883
- // test/49's untrained "Name" remain tolerable).
884
- if (dismissedKnownQ(spans))
885
- continue;
886
- if (diagnostics)
887
- diagnostics.knownContentValid++;
888
- if (covered > bestAccounted) {
889
- bestAccounted = covered;
890
- best = { id: sid, accounted: spans, subs };
891
- if (diagnostics)
892
- diagnostics.bestRank = candidateIndex;
893
- }
894
- }
895
- if (best !== null) {
896
- ctx.trace?.step("substitutionBridge", [rItem(query, "query")], [
897
- rNode(ctx, best.id, "bridged-context"),
898
- ...best.subs.map((s) => rItem(query.subarray(s.qs, s.qe), "substituted")),
899
- ], `a trained context accounts for the query up to ${best.subs.length} ` +
900
- `corroborated substitution(s) — grounding through its learnt edges`, undefined, diagnostics);
901
- }
902
- else {
903
- ctx.trace?.step("substitutionBridge", [rItem(query, "query")], [], "candidate contexts were proposed, but none passed the bridge's " +
904
- "structural identity and corroboration gates", undefined, diagnostics);
905
- }
906
- return best;
907
- }