@hviana/sema 0.5.2 → 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 (157) hide show
  1. package/AGENTS.md +115 -53
  2. package/HOW_IT_WORKS.md +291 -184
  3. package/jsr.json +6 -0
  4. package/package.json +1 -1
  5. package/src/mind/bridge.ts +10 -104
  6. package/src/mind/match.ts +497 -7
  7. package/src/mind/{prefix-completion.ts → mechanisms/prefix-completion.ts} +66 -92
  8. package/src/mind/mechanisms/recall.ts +38 -129
  9. package/src/mind/mechanisms/reference.ts +343 -0
  10. package/src/mind/mind.ts +12 -8
  11. package/src/mind/pipeline-mechanism.ts +120 -3
  12. package/src/mind/pipeline.ts +16 -2
  13. package/src/mind/traverse.ts +92 -1
  14. package/src/store.ts +13 -4
  15. package/test/33-multi-candidate.test.mjs +21 -11
  16. package/test/70-prefix-completion.test.mjs +1 -1
  17. package/test/72-prefix-candidate-supply.test.mjs +7 -9
  18. package/test/74-prefix-trap-not-sprung-early.test.mjs +1 -1
  19. package/test/76-reference-binding.test.mjs +543 -0
  20. package/dist/example/demo.d.ts +0 -1
  21. package/dist/example/demo.js +0 -39
  22. package/dist/example/train_base.d.ts +0 -93
  23. package/dist/example/train_base.js +0 -2269
  24. package/dist/src/alphabet.d.ts +0 -7
  25. package/dist/src/alphabet.js +0 -33
  26. package/dist/src/alu/src/alu.d.ts +0 -185
  27. package/dist/src/alu/src/alu.js +0 -440
  28. package/dist/src/alu/src/expr.d.ts +0 -61
  29. package/dist/src/alu/src/expr.js +0 -318
  30. package/dist/src/alu/src/index.d.ts +0 -11
  31. package/dist/src/alu/src/index.js +0 -19
  32. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  33. package/dist/src/alu/src/kernel-arith.js +0 -264
  34. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  35. package/dist/src/alu/src/kernel-bits.js +0 -152
  36. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  37. package/dist/src/alu/src/kernel-logic.js +0 -60
  38. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  39. package/dist/src/alu/src/kernel-nd.js +0 -208
  40. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  41. package/dist/src/alu/src/kernel-numeric.js +0 -366
  42. package/dist/src/alu/src/operation.d.ts +0 -168
  43. package/dist/src/alu/src/operation.js +0 -189
  44. package/dist/src/alu/src/parser.d.ts +0 -221
  45. package/dist/src/alu/src/parser.js +0 -577
  46. package/dist/src/alu/src/resonance.d.ts +0 -55
  47. package/dist/src/alu/src/resonance.js +0 -126
  48. package/dist/src/alu/src/text.d.ts +0 -31
  49. package/dist/src/alu/src/text.js +0 -73
  50. package/dist/src/alu/src/value.d.ts +0 -109
  51. package/dist/src/alu/src/value.js +0 -300
  52. package/dist/src/alu/test/alu.test.d.ts +0 -1
  53. package/dist/src/alu/test/alu.test.js +0 -764
  54. package/dist/src/bytes.d.ts +0 -14
  55. package/dist/src/bytes.js +0 -59
  56. package/dist/src/canon.d.ts +0 -45
  57. package/dist/src/canon.js +0 -85
  58. package/dist/src/config.d.ts +0 -111
  59. package/dist/src/config.js +0 -91
  60. package/dist/src/derive/src/deduction.d.ts +0 -136
  61. package/dist/src/derive/src/deduction.js +0 -159
  62. package/dist/src/derive/src/index.d.ts +0 -8
  63. package/dist/src/derive/src/index.js +0 -11
  64. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  65. package/dist/src/derive/src/priority-queue.js +0 -73
  66. package/dist/src/derive/src/rewrite.d.ts +0 -56
  67. package/dist/src/derive/src/rewrite.js +0 -100
  68. package/dist/src/derive/src/trie.d.ts +0 -90
  69. package/dist/src/derive/src/trie.js +0 -217
  70. package/dist/src/derive/test/derive.test.d.ts +0 -1
  71. package/dist/src/derive/test/derive.test.js +0 -122
  72. package/dist/src/extension.d.ts +0 -37
  73. package/dist/src/extension.js +0 -7
  74. package/dist/src/geometry.d.ts +0 -233
  75. package/dist/src/geometry.js +0 -1089
  76. package/dist/src/index.d.ts +0 -17
  77. package/dist/src/index.js +0 -19
  78. package/dist/src/ingest-cache.d.ts +0 -41
  79. package/dist/src/ingest-cache.js +0 -165
  80. package/dist/src/meter.d.ts +0 -176
  81. package/dist/src/meter.js +0 -274
  82. package/dist/src/mind/articulation.d.ts +0 -6
  83. package/dist/src/mind/articulation.js +0 -99
  84. package/dist/src/mind/attention.d.ts +0 -430
  85. package/dist/src/mind/attention.js +0 -2418
  86. package/dist/src/mind/bridge.d.ts +0 -39
  87. package/dist/src/mind/bridge.js +0 -998
  88. package/dist/src/mind/canonical.d.ts +0 -34
  89. package/dist/src/mind/canonical.js +0 -93
  90. package/dist/src/mind/frame-filler.d.ts +0 -15
  91. package/dist/src/mind/frame-filler.js +0 -535
  92. package/dist/src/mind/graph-search.d.ts +0 -294
  93. package/dist/src/mind/graph-search.js +0 -996
  94. package/dist/src/mind/index.d.ts +0 -9
  95. package/dist/src/mind/index.js +0 -5
  96. package/dist/src/mind/junction.d.ts +0 -137
  97. package/dist/src/mind/junction.js +0 -358
  98. package/dist/src/mind/learning.d.ts +0 -75
  99. package/dist/src/mind/learning.js +0 -265
  100. package/dist/src/mind/match.d.ts +0 -192
  101. package/dist/src/mind/match.js +0 -666
  102. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  103. package/dist/src/mind/mechanisms/alu.js +0 -36
  104. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  105. package/dist/src/mind/mechanisms/cast.js +0 -1186
  106. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  107. package/dist/src/mind/mechanisms/confluence.js +0 -271
  108. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  109. package/dist/src/mind/mechanisms/cover.js +0 -232
  110. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  111. package/dist/src/mind/mechanisms/extraction.js +0 -327
  112. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  113. package/dist/src/mind/mechanisms/recall.js +0 -558
  114. package/dist/src/mind/mind.d.ts +0 -386
  115. package/dist/src/mind/mind.js +0 -754
  116. package/dist/src/mind/pipeline-mechanism.d.ts +0 -183
  117. package/dist/src/mind/pipeline-mechanism.js +0 -521
  118. package/dist/src/mind/pipeline.d.ts +0 -49
  119. package/dist/src/mind/pipeline.js +0 -331
  120. package/dist/src/mind/prefix-completion.d.ts +0 -59
  121. package/dist/src/mind/prefix-completion.js +0 -270
  122. package/dist/src/mind/primitives.d.ts +0 -85
  123. package/dist/src/mind/primitives.js +0 -333
  124. package/dist/src/mind/rationale.d.ts +0 -139
  125. package/dist/src/mind/rationale.js +0 -163
  126. package/dist/src/mind/reasoning.d.ts +0 -42
  127. package/dist/src/mind/reasoning.js +0 -305
  128. package/dist/src/mind/recognition.d.ts +0 -20
  129. package/dist/src/mind/recognition.js +0 -696
  130. package/dist/src/mind/resonance.d.ts +0 -35
  131. package/dist/src/mind/resonance.js +0 -365
  132. package/dist/src/mind/trace.d.ts +0 -15
  133. package/dist/src/mind/trace.js +0 -73
  134. package/dist/src/mind/traverse.d.ts +0 -158
  135. package/dist/src/mind/traverse.js +0 -716
  136. package/dist/src/mind/types.d.ts +0 -418
  137. package/dist/src/mind/types.js +0 -179
  138. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  139. package/dist/src/rabitq-ivf/src/database.js +0 -201
  140. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  141. package/dist/src/rabitq-ivf/src/index.js +0 -4
  142. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  143. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  144. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  145. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  146. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  147. package/dist/src/rabitq-ivf/src/rabitq.js +0 -313
  148. package/dist/src/sema.d.ts +0 -41
  149. package/dist/src/sema.js +0 -77
  150. package/dist/src/store-sqlite.d.ts +0 -184
  151. package/dist/src/store-sqlite.js +0 -942
  152. package/dist/src/store.d.ts +0 -762
  153. package/dist/src/store.js +0 -1823
  154. package/dist/src/vec.d.ts +0 -31
  155. package/dist/src/vec.js +0 -109
  156. package/src/mind/frame-filler.ts +0 -604
  157. package/test/69-frame-filler.test.mjs +0 -115
@@ -1,2418 +0,0 @@
1
- // attention.ts — Consensus climb / attention pipeline (Section 4 of the mind).
2
- //
3
- // Every region of the query's perceived tree casts a resonance vote for the
4
- // context (learnt fact) it best climbs to. Votes are pooled through the very
5
- // deduction engine (lightestDerivation) that GraphSearch covers with — so a
6
- // pooled-evidence decision is one weighted rule of the SAME deduction system,
7
- // not a hand-rolled tally. The result is one or more independent points of
8
- // attention for the rest of the pipeline to follow.
9
- import { isChunk } from "../sema.js";
10
- import { lightestDerivation, } from "../derive/src/index.js";
11
- import { composeStructuralGist, consensusFloor, dominates, estimatorNoise, } from "../geometry.js";
12
- import { foldTree, gistOf, latin1Key, perceive, read, resolve, } from "./primitives.js";
13
- import { recognise } from "./recognition.js";
14
- import { leafIdRun } from "./canonical.js";
15
- import { corpusN, edgeAncestors, hubBound, sharedReachMemo, } from "./traverse.js";
16
- import { cachedRead, junctionContainersFrom, junctionSeeds, junctionSynonyms, loadJunctionSynonymSides, walkCache, } from "./junction.js";
17
- import { indexOf } from "../bytes.js";
18
- import { rItem, rNode, traceDerivation } from "./trace.js";
19
- function newTraceDraft(perceivedCount) {
20
- return {
21
- perceivedCount,
22
- regions: [],
23
- crossRegionJunctionVotes: [],
24
- crossRegionProbes: [],
25
- supersededOrdinaryVotes: 0,
26
- anchors: [],
27
- };
28
- }
29
- /** Serialise the shared `reachMemo` into the plain, authoritative saturation
30
- * profile (spec §5) — every distinct node any tier's `edgeAncestors` call
31
- * climbed from during this response, in insertion (first-consulted) order. */
32
- function serialiseReaches(reachMemo) {
33
- const out = [];
34
- for (const [node, r] of reachMemo) {
35
- out.push({
36
- node,
37
- roots: [...r.roots],
38
- contextsReached: r.contextsReached,
39
- saturated: r.saturated,
40
- ...(r.saturation ? { saturation: r.saturation } : {}),
41
- ...(r.visited !== undefined
42
- ? { visited: r.visited, maxDepth: r.maxDepth }
43
- : {}),
44
- });
45
- }
46
- return out;
47
- }
48
- // ── Public entry points ───────────────────────────────────────────────────
49
- /** Climb the query's perceived byte regions up the structural DAG via
50
- * resonance, pool the evidence, and return only the ROOT points of
51
- * attention — those that cleared commitVotes' significance floor. */
52
- export async function climbAttention(ctx, query, k, mode = "inverse") {
53
- return (await climbAttentionAll(ctx, query, k, mode)).roots;
54
- }
55
- /** Full read-out of one consensus climb: both the roots (dominant points of
56
- * attention) and the entire ranked list. Cached via ctx.climbMemo, ALWAYS —
57
- * see {@link recognise} for why this memo (and recognise()'s own) is never
58
- * gated on tracing. The short of it: computeAttention's collectRegions
59
- * votes over what walking the query's perceived tree EMITS, and foldTree's
60
- * subtree-resolution fast path used to skip that walk on a warm cache, so a
61
- * second climb over identical bytes saw less evidence than the first — which
62
- * a conversation's shared prefix subtrees guaranteed by the second turn.
63
- * foldTree now takes that fast path only when nothing is watching the walk
64
- * (see primitives.ts), so the climb is idempotent on its own and this memo
65
- * is an accelerator again. It stays unconditional anyway: attaching a trace
66
- * must not change which regions attention weighs.
67
- *
68
- * A cache hit still emits a trace step — abbreviated, since the full
69
- * per-sub-region voting detail {@link traceAttention} builds isn't preserved
70
- * by the cached read-out — so a traced response is never silently blacked
71
- * out for a repeated query. */
72
- export async function climbAttentionAll(ctx, query, k, mode = "inverse") {
73
- // Content-keyed memo — works for both single-turn respond() and multi-turn
74
- // respondTurn().
75
- if (ctx.climbMemo) {
76
- const contentKey = latin1Key(query);
77
- const modeKey = `${k}:${mode}`;
78
- let byRead = ctx.climbMemo.get(contentKey);
79
- if (byRead === undefined) {
80
- ctx.climbMemo.set(contentKey, byRead = new Map());
81
- }
82
- const hit = byRead.get(modeKey);
83
- if (hit !== undefined) {
84
- if (ctx.meter)
85
- ctx.meter.climbHits++;
86
- // Cache-hit exit (spec §9): the abbreviated payload shape — only what
87
- // is actually stored in the cached AttentionRead is reported. No
88
- // candidate, reach, saturation, pooling or anchor detail is fabricated
89
- // (that per-region detail was never retained by the memo).
90
- const data = ctx.trace
91
- ? {
92
- version: 1,
93
- cache: { hit: true, detailAvailable: false },
94
- config: { annK: k, crossRegionProbeLimit: k, mode },
95
- candidates: { perceived: 0, recognised: 0, total: 0 },
96
- result: hit,
97
- }
98
- : undefined;
99
- ctx.trace?.step("climbConsensus", [rItem(query, "query")], hit.roots.map((r) => rNode(ctx, r.anchor, "anchor", r.vote)), `(cached) consensus already computed for this query — ` +
100
- `${hit.roots.length} point(s) of attention`, undefined, data);
101
- return hit;
102
- }
103
- const read = await computeAttention(ctx, query, k, mode);
104
- byRead.set(modeKey, read);
105
- return read;
106
- }
107
- return computeAttention(ctx, query, k, mode);
108
- }
109
- // ── Pipeline ──────────────────────────────────────────────────────────────
110
- export async function computeAttention(ctx, query, k, mode) {
111
- if (ctx.meter)
112
- ctx.meter.climbs++;
113
- const regions = collectRegions(ctx, query);
114
- const perceivedCount = regions.length;
115
- // Recognised sites carry structural evidence that perceived sub-regions
116
- // miss: a word crossing a W-boundary is split into chunks whose partial
117
- // gists may not resonate distinctively, but the SITE (content-addressed,
118
- // exact) names the whole form. Adding sites as climb regions lets the
119
- // consensus vote with the full word, at zero cost — recognition is already
120
- // memoised per response (ctx.recogniseMemo), and gistOf for short sites is
121
- // O(|span|·D). Sites that overlap perceived regions add corroborating
122
- // evidence; sites in gaps (like cross-boundary words) fill them.
123
- const rec = recognise(ctx, query);
124
- for (const s of rec.sites) {
125
- regions.push({
126
- v: gistOf(ctx, query.subarray(s.start, s.end)),
127
- start: s.start,
128
- end: s.end,
129
- // NOT a chunk — a precondition, not a judgement about the evidence.
130
- // `chunk` admits a region into the saturated-INTERVAL builder (see
131
- // crossRegionVotes), which walks regions as a SEQUENCE and merges
132
- // neighbouring saturated ones into runs. Its own contract requires the
133
- // regions it reads to be DISJOINT and in byte order — true of
134
- // leaf-parents, false of sites, which overlap each other and the chunks
135
- // ("red", "circle" and "red circle" are all present at once).
136
- //
137
- // Admitting them was measured both ways and is unprincipled in each
138
- // direction: a saturated site EXTENDS a run and masks votes that should
139
- // have won (test/37 lost all three — roots became "red " and "hat"
140
- // instead of "red circle" and "2"), while a non-saturated one BREAKS a
141
- // run and unmasks votes that should have been dropped, which is the only
142
- // reason it appeared to fix test/34. Either way the outcome turns on
143
- // where an overlapping span happens to fall in the array — the same
144
- // positional accident this work exists to remove.
145
- chunk: false,
146
- known: true, // a recognised site IS a stored form
147
- // …and CARRY WHICH ONE. `known: true` claimed exactness while the
148
- // identity itself was dropped, leaving the climb to re-derive it from
149
- // the gist through the ANN — so which stored node an exact site voted
150
- // with turned on approximate rank. Measured on test/34: the site
151
- // "square" ([10,16), payload 40) resonated to "quare" (119) instead;
152
- // the exact junction tier then found no container holding both "blue"
153
- // and 119, fell through to the single-synonym tier, and "blue then
154
- // square" attended to "red square" — a context NEITHER attribute
155
- // attends to alone. This is the same exact-first economy chunks
156
- // already get from canonicalChunkId, and it REMOVES an ANN query
157
- // rather than adding one.
158
- id: s.payload,
159
- });
160
- }
161
- // The trace draft (spec §9): allocated ONLY when a trace was requested —
162
- // every downstream consumer gates its own writes on `td?` / `if (td)`, so
163
- // an untraced climb pays zero allocation for this instrumentation.
164
- const td = ctx.trace
165
- ? newTraceDraft(perceivedCount)
166
- : undefined;
167
- const cfg0 = {
168
- k,
169
- mode,
170
- perceivedCount,
171
- totalRegions: regions.length,
172
- };
173
- if (regions.length === 0) {
174
- traceAttention(ctx, [], [], [], undefined, td, cfg0);
175
- return { roots: [], ranked: [] };
176
- }
177
- const N = corpusN(ctx);
178
- // One climb per distinct anchor for the WHOLE query: regions sharing a
179
- // chunk, and canonicalChunkId's prefix probes, all hit this memo instead of
180
- // re-reading the anchor's full edge fan-out from the store. The memo is
181
- // the SHARED one (traverse.ts) — response-scoped for respond(),
182
- // conversation-scoped across turns, and the same map confluence prices
183
- // commonality against; it used to be a private per-climb Map, so a
184
- // conversation re-climbed its own repeated regions from cold on every
185
- // turn. A traced response still gets a fresh one — see sharedReachMemo.
186
- const reachMemo = sharedReachMemo(ctx);
187
- const rvs = ctx.meter
188
- ? await ctx.meter.time("climb.voteRegions", () => voteRegions(ctx, query, regions, k, mode, N, reachMemo, td))
189
- : await voteRegions(ctx, query, regions, k, mode, N, reachMemo, td);
190
- // ── Cross-region: DIRECT region-to-region interaction ─────────────────
191
- // Two regions whose individual climbs land on DIFFERENT contexts leave
192
- // their JOINT context — the learnt whole that contains BOTH — with no
193
- // vote. crossRegionVotes recovers it by the bridge's content-addressed
194
- // junction ascent (see the note above the function).
195
- const crossArgs = () => crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td);
196
- const cross = ctx.meter
197
- ? await ctx.meter.time("climb.crossRegion", crossArgs)
198
- : await crossArgs();
199
- // A vote SUPERSEDED by exact joint evidence (its bytes literally live
200
- // inside the joint container, yet it climbed elsewhere — grid aliasing)
201
- // is dropped, not down-weighted: the joint container explains it away.
202
- const allVotes = cross.votes.length > 0
203
- ? [
204
- ...rvs.votes.filter((v) => !cross.superseded.has(v)),
205
- ...cross.votes,
206
- ]
207
- : rvs.votes;
208
- // Mark, on the per-region trace, the source region of every superseded
209
- // ordinary vote (spec §4's final rule) — an explicit pass over the exact
210
- // set crossRegionVotes' explaining-away logic removed, never inferred
211
- // from `absorbed`.
212
- if (td && cross.superseded.size > 0) {
213
- for (const rv of cross.superseded) {
214
- const region = td.regions.find((r) => r.span[0] === rv.start && r.span[1] === rv.end);
215
- if (region)
216
- region.superseded = true;
217
- }
218
- }
219
- // ──────────────────────────────────────────────────────────────────────
220
- const cfg = { ...cfg0, N, reachMemo };
221
- if (allVotes.length === 0) {
222
- traceAttention(ctx, regions, rvs.voters, [], undefined, td, cfg);
223
- return { roots: [], ranked: [] };
224
- }
225
- const sat = detectSaturated(ctx, regions, rvs.saturated);
226
- if (td) {
227
- td.saturation = {
228
- regionIntervals: sat.intervals.map((iv) => ({ ...iv })),
229
- hasLeading: sat.hasLeading,
230
- leadingEnd: sat.leadingEnd,
231
- };
232
- }
233
- const pooled = poolVotes(ctx, allVotes, sat, N, td);
234
- return commitVotes(ctx, pooled, sat, regions, rvs.voters, N, td, cfg);
235
- }
236
- export function collectRegions(ctx, query) {
237
- const regions = [];
238
- // A region that DOMINATES the query (covers more than half — the shared
239
- // {@link dominates} test liftAnswer uses for a span that swallows its
240
- // surroundings) can never itself discriminate between several topics the
241
- // query weaves; voting with it only when it is the sole structure (no
242
- // narrower region exists) keeps a flat/short query's single point of
243
- // attention intact without letting a broad, non-discriminative wrapper
244
- // dilute a multi-topic query's vote or masquerade as a genuine second
245
- // point of attention.
246
- // foldTree (not walkTree): the same post-order walk, but each node also
247
- // resolves content-addressed against the store — `known` is what lets the
248
- // climb keep exact evidence at full weight while margin-damping the
249
- // approximate kind (see voteRegions). One findLeaf/findBranch per tree
250
- // node, the same lookups a deposit pays.
251
- foldTree(ctx, perceive(ctx, query), 0, (n, start, end, node) => {
252
- if (n.kids === null)
253
- return;
254
- // The dominance filter is about WRAPPERS, not about size. A chunk is the
255
- // smallest grouped unit — it wraps no other region — so it can never be the
256
- // "broad, non-discriminative wrapper" this rule exists to exclude, however
257
- // much of a short query it happens to cover. Testing it by span alone was
258
- // safe only while chunks were exactly W bytes: content-defined segments run
259
- // up to the keyring's seat count, so on a 15-byte query the 8-byte segment
260
- // "is frigi" counted as dominant and was discarded, leaving CAST one point
261
- // of attention where it needs two (test/29 D1/D2). Composites are still
262
- // filtered exactly as before.
263
- if (isChunk(n) || !dominates(end - start, query.length) ||
264
- regions.length === 0) {
265
- regions.push({
266
- v: n.v,
267
- start,
268
- end,
269
- chunk: isChunk(n),
270
- known: node !== null,
271
- });
272
- }
273
- // MEASURED AND REFUTED — subdividing a long segment into W-scale tiles.
274
- // A content segment runs from W−1 up to the keyring's seat count (2W) and
275
- // folds FLAT, so its only sub-units are single bytes; the grid's regions
276
- // were always exactly W. Offering each segment's W-byte tiles as extra
277
- // regions (gists only, no stored nodes, anchored on the segment's own
278
- // content-defined start so invariance is kept) does restore that finer
279
- // grain: on `How is ice like steel?` the climb went from ONE ranked anchor
280
- // to three, and test/33's own CAST-candidate spread was recovered.
281
- //
282
- // It is still wrong, and net worse (measured: test/29 went 9/2 to 7/4).
283
- // canonicalWindows governs EXACT identity lookup, which recognition
284
- // already probes at every offset — it says nothing about the grain of an
285
- // approximate gist, so "the write side's unit scale" was two machineries
286
- // conflated. What the tiles actually do is reintroduce a fixed stride
287
- // inside the segment, and the extra votes reorder the climb: on
288
- // `How is Shakespeare like Leonardo da Vinci?` the short name deposits
289
- // outranked the exemplar sentences, claimed their aligned runs first, and
290
- // left the sentences CAST needs with no free run at all (C2, C3). A
291
- // region must come from the fold, not from a stride over it.
292
- });
293
- // ─── FORMS THE QUERY'S OWN CUT SPLIT ────────────────────────────────────
294
- // The walk above enumerates FOLD NODES ONLY, so a stored form the query's
295
- // content-defined cut happens to split is not addressable at all — however
296
- // discriminative it is. Measured: `request_id=1042` against a 200-record
297
- // log, the query's best match, cut as `...uest_id=|10|42 and r`; "1042"
298
- // reaches exactly ONE context of 205 (maximal IDF) and cast no vote, while
299
- // the scaffolding "=10" — which matches every record 1000–1099 — did. The
300
- // climb was voting on the only evidence it could address, and that was the
301
- // non-discriminative kind.
302
- //
303
- // The WRITE path already made these reachable: canonicalWindows interns a
304
- // form at both lengths precisely so one straddling a cut resolves from
305
- // either side. The read path simply never used the guarantee. So this is
306
- // recovered here by lookup — the fold, its invariants and the write path
307
- // are untouched.
308
- //
309
- // Admitting every resolvable window is REFUTED (it is the ascent-sites
310
- // failure): on a 5-context corpus a 26-byte query yielded 17 "unique"
311
- // windows that were all fragments of ONE word (" pai" "pain" "aint" …).
312
- // No per-window threshold separates that from the log case — the two need
313
- // the same windows ADMITTED and COLLAPSED at identical per-window IDF. It
314
- // is a REDUNDANCY problem, so overlapping admitted windows are COALESCED
315
- // into maximal spans: the log query then yields the two disjoint records it
316
- // names, and the 17 fragments yield the one span " painted the Mona Lisa".
317
- const W = ctx.space.maxGroup;
318
- if (query.length > W) {
319
- const N = corpusN(ctx);
320
- const reachMemo = sharedReachMemo(ctx);
321
- // Coalesce while sweeping left to right: a window overlapping (or just
322
- // touching) the span under construction extends it. Merging cannot
323
- // inflate what the climb pays for this evidence — the merged span votes
324
- // as ITSELF, and a longer span is at least as discriminative as its most
325
- // discriminative part, i.e. its reach is bounded by the MIN over the
326
- // windows that built it.
327
- const spans = [];
328
- // COVERAGE BY PREFIX MAXIMUM, NOT BY RESCANNING THE REGIONS.
329
- // The containment test below is the loop's hot path — it rejects 97% of
330
- // windows — and asking it as `regions.some(...)` re-walked every region
331
- // at every offset: O(|query| · |regions|). That is quadratic in the
332
- // input, and the region count grows with it — measured 1,510 regions on
333
- // an 8,195-byte query, i.e. ~12.4M predicate evaluations in ONE call,
334
- // against the constant-KB/s law test/14 asserts.
335
- //
336
- // A region contains the window [o, o+W) exactly when it starts at or
337
- // before `o` and ends at or after `o+W`. So the only thing the test
338
- // needs from the regions is, per offset, the FARTHEST end among those
339
- // starting at or before it — a prefix maximum, built in one pass and
340
- // read in O(1). Identical verdict by construction, no behaviour change.
341
- const maxEndFrom = new Int32Array(query.length + 1);
342
- for (const r of regions) {
343
- if (r.start <= query.length && r.end > maxEndFrom[r.start]) {
344
- maxEndFrom[r.start] = r.end;
345
- }
346
- }
347
- for (let i = 1; i <= query.length; i++) {
348
- if (maxEndFrom[i - 1] > maxEndFrom[i])
349
- maxEndFrom[i] = maxEndFrom[i - 1];
350
- }
351
- for (let o = 0; o + W <= query.length; o++) {
352
- // A window some fold region wholly contains offers no address the walk
353
- // above did not already offer.
354
- if (maxEndFrom[o] >= o + W)
355
- continue;
356
- const ids = leafIdRun(ctx, query, o, o + W);
357
- if (ids === null)
358
- continue;
359
- const wid = ctx.store.findBranch(ids);
360
- if (wid === null)
361
- continue;
362
- const reach = edgeAncestors(ctx, wid, N, reachMemo);
363
- // Saturated = the climb ABSTAINED; no roots = it reached nothing that
364
- // could corroborate anything. Neither is evidence.
365
- if (reach.saturated || reach.roots.length === 0)
366
- continue;
367
- const last = spans[spans.length - 1];
368
- if (last && o <= last.end)
369
- last.end = o + W;
370
- else
371
- spans.push({ start: o, end: o + W });
372
- }
373
- for (const { start, end } of spans) {
374
- // The same wrapper filter the fold regions pass through.
375
- if (dominates(end - start, query.length) && regions.length > 0)
376
- continue;
377
- regions.push({
378
- v: gistOf(ctx, query.subarray(start, end)),
379
- start,
380
- end,
381
- // NOT a chunk: `chunk` means "a smallest grouped unit the FOLD
382
- // produced", and this span was assembled here. Setting it is
383
- // REFUTED — it cost 5 tests (honest silence, fusion direction, both
384
- // test/50 probes) where chunk:false costs none.
385
- chunk: false,
386
- known: true,
387
- // EVIDENCE, NOT A POINT OF ATTENTION — see Region.corroborating.
388
- corroborating: true,
389
- });
390
- }
391
- }
392
- return regions;
393
- }
394
- export async function voteRegions(ctx, query, regions, k, mode, N, reachMemo, td) {
395
- if (ctx.meter)
396
- ctx.meter.climbRegions += regions.length;
397
- const regionSaturated = new Array(regions.length).fill(false);
398
- const regionVotes = [];
399
- const regionVoter = ctx.trace ? regions.map(() => null) : [];
400
- const W = ctx.space.maxGroup;
401
- for (let ri = 0; ri < regions.length; ri++) {
402
- // `v`/`start`/`end` are rebindable: a long approximate segment may vote
403
- // with the sub-span that actually carries its evidence — see below.
404
- let { v, start, end } = regions[ri];
405
- const { chunk } = regions[ri];
406
- // BELOW ONE RIVER WINDOW, BYTE IDENTITY IS NOT EVIDENCE. The same
407
- // principle identityBar states and recognition's own `emit` already
408
- // enforces on sites ("below one river window, byte overlap is chance"),
409
- // applied to what the climb calls EXACT. It was unnecessary while the
410
- // fold grouped at fixed arity — every chunk was then exactly W bytes —
411
- // but content-defined cuts run from W-1 up to the keyring's seat count,
412
- // so sub-window segments now exist, and a 3-byte string is interned by
413
- // triviality rather than by evidence.
414
- //
415
- // Such a region is NOT dropped: it still votes on its gist, through the
416
- // contrastive-margin gate every approximate region pays. Dropping them
417
- // outright was measured and REFUTED — the suite fell 441 -> 406, because
418
- // short regions do carry real evidence; what they must not carry is the
419
- // EXACT tier's full mutual weight and its exemption from the margin.
420
- //
421
- // Measured on test/50's junk query: the 3-byte chunk "of " voted exact
422
- // at mutual 1.00 with idf 4.22, and an unrelated haiku exemplar's pooled
423
- // vote went 1.13 -> 5.94 — past consensusFloor (5.82), making a junk root
424
- // TRUSTED and licensing CAST to compare content the query never named.
425
- // consensusFloor did not drift; what fed it stopped being evidence.
426
- //
427
- // A region spanning the WHOLE query is exempt, exactly as the site rule
428
- // exempts a whole-query span: it is then not a fragment of something
429
- // longer, it is the question ("red" asked on its own — test/34).
430
- const subWindow = end - start < W &&
431
- !(start === 0 && end === query.length);
432
- // EXACTNESS IS A PROPERTY OF THE CONTENT, NOT OF THIS QUERY'S GROUPING.
433
- // `known` used to mean "these bytes resolve to ONE stored node", which
434
- // conflates two different things: whether the store has seen the content,
435
- // and whether this query's cut happened to group it the same way the
436
- // deposit did. Under fixed-arity folding those coincided; under
437
- // content-defined cuts they routinely do not.
438
- //
439
- // Measured over 42 voting regions (attributes / capitals / artists),
440
- // against a graded reading — what fraction of the region's river windows
441
- // are content-addressed:
442
- //
443
- // known=true cov=1.0 90% cov=0 0% 0<cov<1 10%
444
- // known=false cov=1.0 5% cov=0 52% 0<cov<1 43%
445
- //
446
- // The 5% are regions where EVERY window resolves — the content is
447
- // entirely in the store — yet the region was called unknown purely
448
- // because this cut grouped it differently, so it paid the contrastive
449
- // margin as though it were an approximate gist. That is grouping churn
450
- // taxed as uncertainty.
451
- //
452
- // Only the fully-addressed case is promoted here: every window resolving
453
- // is exact evidence about the content by the same content-addressing the
454
- // whole-region test uses, just read at the window scale identityBar
455
- // already calls the floor below which overlap is chance. The partial band
456
- // (43%) is deliberately NOT promoted — it is genuinely mixed evidence and
457
- // the margin is the right price for it. Paid only when the cheap whole-
458
- // region test already failed, and bounded by the region's own length.
459
- // HOW MUCH OF THIS REGION IS CONTENT-ADDRESSED — a fraction, not a bit.
460
- // Measured over 42 voting regions, `known` as a boolean loses a wide band:
461
- // 43% of "unknown" regions are PARTIALLY addressed and 5% are fully
462
- // addressed while failing the whole-region test (grouping churn). Promoting
463
- // the partial band wholesale was measured too and is over-crediting — it
464
- // buys test/00 with a region attested 1 window in 5, granting a 20%-attested
465
- // region the same full exemption a fully-attested one gets.
466
- //
467
- // So the coverage SCALES the bar instead of switching it: a region pays the
468
- // estimator's noise floor in proportion to how much of it is NOT
469
- // content-addressed. cov=1 pays nothing (identical to the old exemption),
470
- // cov=0 pays the full floor (identical to the old gate), cov=0.2 pays 0.8
471
- // of it. No new constant — estimatorNoise is unchanged and the coverage is
472
- // read off the store by the same content addressing `known` already used.
473
- const windowCoverage = () => {
474
- if (end - start < W)
475
- return 0;
476
- let tot = 0, hit = 0;
477
- for (let o = start; o + W <= end; o++) {
478
- tot++;
479
- if (resolve(ctx, query.subarray(o, o + W)) !== null)
480
- hit++;
481
- }
482
- return tot === 0 ? 0 : hit / tot;
483
- };
484
- // A sub-window region pays in full: below one river window its byte
485
- // identity is chance, so it has no coverage to claim.
486
- const cov = subWindow ? 0 : (regions[ri].known ? 1 : windowCoverage());
487
- const known = cov >= 1 && !subWindow;
488
- // Trace-only bookkeeping for this region — allocated only under `td`
489
- // (i.e. only when ctx.trace is set); see ConsensusRegionTrace/
490
- // RegionOutcome (spec §4). `examinedIds` tracks distinct ANN hits
491
- // whose edgeAncestors reach was actually CONSULTED here (not merely
492
- // returned by resonate) — the fallback/margin loops below add to it.
493
- const examinedIds = td ? new Set() : undefined;
494
- let annQueried = false;
495
- let fallbackKind;
496
- const recordRegion = (outcome, extra = {}) => {
497
- if (!td)
498
- return;
499
- td.regions[ri] = {
500
- index: ri,
501
- source: ri < td.perceivedCount ? "perceived" : "recognised",
502
- span: [start, end],
503
- chunk,
504
- known,
505
- canonicalId: canonicalId ?? undefined,
506
- canonicalUsable,
507
- canonicalFailed,
508
- annQueried,
509
- annHitsReturned: hits ? hits.length : 0,
510
- annHitsExamined: examinedIds ? examinedIds.size : 0,
511
- outcome,
512
- ordinaryVoteProduced: outcome === "voted",
513
- superseded: false,
514
- ...extra,
515
- };
516
- };
517
- // EXACT-FIRST: a chunk whose canonical anchor is content-addressed needs
518
- // no estimator — identity is exact, so its score is 1 BY DEFINITION (the
519
- // estimated cosine of a form with itself, minus quantisation noise, and
520
- // the caveat atop geometry.ts forbids trusting the estimate over the
521
- // exact resolution anyway). The ANN query is deferred behind
522
- // `ensureHits` and paid only when actually consulted: the orphan
523
- // fallback, the contrastive margin (approximate regions only), or a
524
- // region with no usable canonical. On chunk-heavy queries this removes
525
- // the resonate() call for most exact regions — the single largest
526
- // remaining inference sink — with the anchor choice unchanged (the
527
- // canonical branch already ignored hits[0]).
528
- let canonicalId = subWindow
529
- ? null
530
- : (chunk
531
- ? canonicalChunkId(ctx, query.subarray(start, end), N, reachMemo)
532
- : (regions[ri].id ?? null));
533
- let canonicalUsable = canonicalId !== null &&
534
- (ctx.store.hasParents(canonicalId) ||
535
- ctx.store.hasContainers(canonicalId));
536
- let hits = null;
537
- const ensureHits = async () => {
538
- if (hits === null) {
539
- hits = await ctx.store.resonate(v, k);
540
- annQueried = true;
541
- }
542
- return hits;
543
- };
544
- // A DILUTED SEGMENT VOTES WITH THE SPAN THAT CARRIES ITS EVIDENCE.
545
- //
546
- // A content segment runs up to the keyring's seat count and folds FLAT, so
547
- // its gist superposes every one of its bytes: an entity inside a longer
548
- // segment is averaged together with whatever scaffolding shares the
549
- // segment, and the resonance reads the average. Measured on
550
- // `How is ice like steel?` against a store holding `Steel is hard`: the
551
- // segment `ike stee` resonates to `Ice is c` at 0.297 — the WRONG deposit —
552
- // with `Steel ` fourth at 0.123, while the sub-span `stee` resonates to
553
- // `Steel ` at 0.627. The evidence is there; the whole-segment read cannot
554
- // see it, and `Steel is hard` received no vote at all (test/29 C1).
555
- //
556
- // Entered only after the EXACT path has already failed — a chunk with a
557
- // usable canonical identity has a content-addressed handle on its own bytes
558
- // and needs no estimator at all — so this is honest degradation, not extra
559
- // work on regions that already resolved. The candidates are the segment's
560
- // two EDGE sub-spans at the write side's own unit scale (W) — the scale
561
- // `canonicalWindows` interns, and the only one at which a sub-span could
562
- // carry a stored identity; a segment of W or less has no interior at all.
563
- // Edges because a content cut lands INSIDE a unit, so the remnant it split
564
- // sits against the cut: `steel` is cut after `stee`. Offering every
565
- // interior offset instead was measured and is worse — it re-anchors
566
- // segments on spans no boundary ever separated, and broke three of
567
- // test/17's vote-distribution and root-count assertions (428/1 → 424/5).
568
- //
569
- // Selection is by the SAME quantity the region's vote is weighted by —
570
- // score² · idf — never by score alone: the scaffolding window `is i`
571
- // resonates at 0.832, far above `stee`, and is worth nothing because its
572
- // reach is the whole corpus. Nothing new is being measured here; the
573
- // choice the code did not previously make is made with the criterion it
574
- // already uses. The region's SPAN narrows with its gist, so breadth,
575
- // clusters and cross-region pairing all see where the evidence really sits.
576
- if (!canonicalUsable && chunk && !known && end - start > W) {
577
- const weigh = (h) => {
578
- const r = edgeAncestors(ctx, h.id, N, reachMemo);
579
- if (r.saturated || r.roots.length === 0)
580
- return null;
581
- const idf = Math.log(N / Math.max(1, r.contextsReached));
582
- if (idf <= 0)
583
- return null;
584
- return { w: h.score * h.score * idf, id: h.id };
585
- };
586
- // The whole-segment candidate reuses the ranking the region needs
587
- // anyway, so only the two edge probes are new work.
588
- const scoreOf = async (gist) => {
589
- const h = await ctx.store.resonate(gist, 1);
590
- return h.length === 0 ? null : weigh(h[0]);
591
- };
592
- const h0 = await ensureHits();
593
- let best = h0.length > 0 ? weigh(h0[0]) : null;
594
- let bestSpan = null;
595
- for (const s0 of [start, end - W]) {
596
- const sub = gistOf(ctx, query.subarray(s0, s0 + W));
597
- const cand = await scoreOf(sub);
598
- if (cand !== null && (best === null || cand.w > best.w)) {
599
- best = cand;
600
- bestSpan = [s0, s0 + W, sub];
601
- }
602
- }
603
- if (bestSpan !== null) {
604
- [start, end, v] = bestSpan;
605
- hits = null; // the whole-segment ranking no longer describes this span
606
- canonicalId = canonicalChunkId(ctx, query.subarray(start, end), N, reachMemo);
607
- canonicalUsable = canonicalId !== null &&
608
- (ctx.store.hasParents(canonicalId) ||
609
- ctx.store.hasContainers(canonicalId));
610
- }
611
- }
612
- const canonicalFailed = chunk && canonicalId === null;
613
- let voterId;
614
- let score;
615
- let scoreId; // the node the score was measured against
616
- let selectedSource;
617
- if (canonicalUsable) {
618
- voterId = canonicalId;
619
- score = 1;
620
- scoreId = canonicalId;
621
- selectedSource = "canonical";
622
- }
623
- else {
624
- const h = await ensureHits();
625
- if (h.length === 0) {
626
- recordRegion("no-ann-hit");
627
- continue;
628
- }
629
- voterId = h[0].id;
630
- score = h[0].score;
631
- scoreId = h[0].id;
632
- selectedSource = "ann";
633
- examinedIds?.add(voterId);
634
- }
635
- let reach = edgeAncestors(ctx, voterId, N, reachMemo);
636
- // A region's vote must not die with the TOP hit: `hits[1..k]` were
637
- // already fetched, and the top-ranked anchor being a structural orphan
638
- // (no edge-bearing ancestors) is an accident of the approximate ranking,
639
- // not evidence the region relates to nothing. Walk the remaining hits —
640
- // nearest first, climbs memoised — until one climbs. A SATURATED reach
641
- // is not an orphan: it is a deliberate abstention, kept as-is.
642
- if (reach.roots.length === 0 && !reach.saturated) {
643
- for (const h of await ensureHits()) {
644
- if (h.id === voterId)
645
- continue;
646
- const r2 = edgeAncestors(ctx, h.id, N, reachMemo);
647
- examinedIds?.add(h.id);
648
- if (r2.saturated || r2.roots.length > 0) {
649
- ctx.trace?.step("anchorFallback", [rNode(ctx, voterId, "orphan-anchor", score)], [rNode(ctx, h.id, "anchor", h.score)], "the top-ranked anchor climbs to no context — a lower-ranked hit votes instead");
650
- reach = r2;
651
- voterId = h.id;
652
- score = h.score;
653
- scoreId = h.id;
654
- selectedSource = "ann";
655
- fallbackKind = "orphan";
656
- break;
657
- }
658
- }
659
- }
660
- else if (!canonicalUsable && reach.saturated) {
661
- // TIE-BAND saturation fallback. A saturated top hit abstains the whole
662
- // region (a hub's reach concludes nothing) — but the hub may only CLAIM
663
- // that abstention when it is DISTINGUISHABLY the nearest anchor. The
664
- // resonance ranking is an estimate: the difference between two scores
665
- // against the same query carries √2× the estimator's per-score error,
666
- // ≈ 1/√D ({@link estimatorNoise}) — so any hit within that band of the
667
- // top is the SAME rank at measurement resolution, and letting the hub
668
- // win the tie decides the region by quantisation accident (observed:
669
- // a 0.1σ rank inversion flipped a pinned behaviour when the query
670
- // estimator sharpened from 4 to 8 bits). Walk the tied hits, nearest
671
- // first; the first that climbs somewhere non-saturated votes for the
672
- // region. Beyond the band the hub is genuinely nearest and its
673
- // abstention stands. A KNOWN (content-addressed) region never enters:
674
- // its anchor is exact, not an estimate.
675
- const band = estimatorNoise(ctx.store.D);
676
- for (const h of await ensureHits()) {
677
- if (h.id === voterId)
678
- continue;
679
- if (h.score < score - band)
680
- break; // hits are nearest-first
681
- const r2 = edgeAncestors(ctx, h.id, N, reachMemo);
682
- examinedIds?.add(h.id);
683
- if (!r2.saturated && r2.roots.length > 0) {
684
- ctx.trace?.step("anchorFallback", [rNode(ctx, voterId, "saturated-anchor", score)], [rNode(ctx, h.id, "anchor", h.score)], "the top-ranked anchor is a saturated hub tied within estimator noise — the tied hit votes instead");
685
- reach = r2;
686
- voterId = h.id;
687
- score = h.score;
688
- scoreId = h.id;
689
- selectedSource = "ann";
690
- fallbackKind = "saturated-tie";
691
- break;
692
- }
693
- }
694
- }
695
- regionSaturated[ri] = reach.saturated;
696
- const selected = !td
697
- ? undefined
698
- : (() => {
699
- const rank = selectedSource === "ann"
700
- ? hits?.findIndex((h) => h.id === voterId)
701
- : undefined;
702
- return {
703
- source: selectedSource,
704
- node: voterId,
705
- score,
706
- ...(rank !== undefined ? { rank } : {}),
707
- ...(fallbackKind ? { fallback: fallbackKind } : {}),
708
- };
709
- })();
710
- if (reach.roots.length === 0) {
711
- recordRegion("no-structural-reach", { selected, reachNode: voterId });
712
- continue;
713
- }
714
- if (reach.saturated) {
715
- recordRegion("saturated-abstention", { selected, reachNode: voterId });
716
- continue;
717
- }
718
- // One IDF per region — dfWeight() and the focus weight used to compute
719
- // the same logarithm independently.
720
- const idf = Math.log(N / Math.max(1, reach.contextsReached));
721
- const df = Math.log(1 + reach.contextsReached);
722
- const wf = mode === "direct" ? df : mode === "combined" ? idf + df : idf;
723
- if (wf <= 0) {
724
- recordRegion("nonpositive-df-weight", {
725
- selected,
726
- reachNode: voterId,
727
- idf,
728
- dfWeight: wf,
729
- });
730
- continue;
731
- }
732
- // CONTRASTIVE-MARGIN GATE — the compensation the linear (byte-proportional)
733
- // fold demands, applied to APPROXIMATE evidence only. Under the linear
734
- // fold a resonance score reads "fraction of aligned shared bytes", so a
735
- // NOVEL span sharing a frame with several stored exemplars scores high
736
- // against each of them without being evidence of ANY of them: the shared
737
- // scaffolding, not the span's own content, carries the similarity. Such a
738
- // frame region resonates ~equally to every framed exemplar, so its top hit
739
- // barely beats the best DIFFERENT-conclusion rival (a different climb
740
- // root-set) — its discriminative margin, score MINUS that rival, collapses
741
- // toward zero. A region votes only when that margin clears the estimator's
742
- // own noise floor (1/√D — see {@link estimatorNoise}); below it the margin
743
- // is quantisation noise, not evidence. A KNOWN region (content-addressed,
744
- // exact) skips the contrast: it IS learnt content, not an approximation.
745
- //
746
- // The margin GATES; it does NOT scale the weight. A surviving region votes
747
- // at its genuine strength (score²·wf) — the SAME scale {@link
748
- // consensusFloor} is derived for. Using the margin as a MULTIPLIER
749
- // (score·margin) conflated "discriminative" with "strong": a genuinely
750
- // discriminative span whose frame-rival happened to score close got a tiny
751
- // vote, systematically compressing correct scaffolding-dominated groundings
752
- // (reordered / paraphrased queries) below the floor so they grounded
753
- // nothing. Gating at the noise floor keeps frame-echo suppression (a frame
754
- // region's margin ≈ 0 is gated out) without penalising honest evidence.
755
- let contrastiveMargin;
756
- let contrastiveRival;
757
- if (!known) {
758
- let margin = score;
759
- const hitsForRival = await ensureHits();
760
- for (let hi = 0; hi < hitsForRival.length; hi++) {
761
- const h = hitsForRival[hi];
762
- if (h.id === voterId)
763
- continue;
764
- const r2 = edgeAncestors(ctx, h.id, N, reachMemo);
765
- examinedIds?.add(h.id);
766
- if (r2.saturated || r2.roots.length === 0)
767
- continue; // concludes nothing
768
- if (sameRoots(r2.roots, reach.roots))
769
- continue; // same conclusion
770
- margin = score - h.score; // hits are nearest-first: the best rival
771
- if (td) {
772
- contrastiveRival = { node: h.id, rank: hi, score: h.score };
773
- }
774
- break;
775
- }
776
- contrastiveMargin = margin;
777
- // Scaled by what this region does NOT address — see `cov` above.
778
- const noiseFloor = estimatorNoise(ctx.store.D) * (1 - cov);
779
- if (margin <= noiseFloor) {
780
- recordRegion("contrastive-margin-rejection", {
781
- selected,
782
- reachNode: voterId,
783
- idf,
784
- dfWeight: wf,
785
- contrastiveMargin: margin,
786
- contrastiveNoiseFloor: noiseFloor,
787
- ...(contrastiveRival ? { contrastiveRival } : {}),
788
- });
789
- continue;
790
- }
791
- }
792
- // MUTUAL-EXPLANATION WEIGHT (angle + magnitude). Under the linear fold
793
- // cos = shared/(‖r‖·‖h‖) with ‖·‖² = content bytes, so the old score²
794
- // was already — implicitly — (shared/len_r)·(shared/len_h): the fraction
795
- // of the REGION the hit explains times the fraction of the HIT the
796
- // region pins down. Made explicit, each factor is computed from the two
797
- // magnitudes (the region's own span; the hit's, read from the store —
798
- // contentLen, √bytes being the linear fold's gist norm) and CAPPED at 1:
799
- // the estimated cosine can imply more shared content than the smaller
800
- // side even holds, and the uncapped square silently credited that
801
- // impossible surplus — a small region echoing inside a large context, or
802
- // the reverse, voted above its physical evidence. In the uncapped
803
- // regime this is exactly score², the scale {@link consensusFloor} is
804
- // derived for. (The margin gate above deliberately stays in raw cosine
805
- // units: it tests the ESTIMATOR's noise floor, which lives in cosine
806
- // space; converting each side by its own hit's magnitude would compare
807
- // noise floors of different scales.)
808
- const lenR = Math.max(1, end - start);
809
- // Cap the magnitude read at lenR·D: past it s/ratio ≤ s/√D — below the
810
- // estimator's own noise floor — so the mutual weight is ~0 regardless
811
- // and the clamped value yields exactly that; no full walk of a huge hit.
812
- const ratio = Math.sqrt(Math.max(1, ctx.store.contentLen(scoreId, lenR * ctx.store.D)) / lenR);
813
- const mutual = Math.min(1, score * ratio) * Math.min(1, score / ratio);
814
- const w = (mutual * wf) / reach.roots.length;
815
- const wFocus = (mutual * idf) / reach.roots.length;
816
- regionVotes.push({
817
- start,
818
- end,
819
- canonicalFailed,
820
- roots: reach.roots,
821
- w,
822
- wFocus,
823
- // The pool sees VOTES, not regions — carry the region's standing with it.
824
- ...(regions[ri].corroborating ? { corroborating: true } : {}),
825
- });
826
- if (ctx.trace) {
827
- regionVoter[ri] = { id: voterId, score, w: wf };
828
- }
829
- recordRegion("voted", {
830
- selected,
831
- reachNode: voterId,
832
- idf,
833
- dfWeight: wf,
834
- ...(contrastiveMargin !== undefined
835
- ? {
836
- contrastiveMargin,
837
- contrastiveNoiseFloor: estimatorNoise(ctx.store.D),
838
- ...(contrastiveRival ? { contrastiveRival } : {}),
839
- }
840
- : {}),
841
- mutualWeight: mutual,
842
- voteWeightPerRoot: w,
843
- focusWeightPerRoot: wFocus,
844
- });
845
- }
846
- return {
847
- votes: regionVotes,
848
- saturated: regionSaturated,
849
- voters: regionVoter,
850
- };
851
- }
852
- /** The consensus vote as EVIDENCE POOLING, not shortest path: each surviving
853
- * region is an axiom; it contributes to every root it climbed to (or, for a
854
- * terminal answer node, to the contexts that lead to it) by a `combine:
855
- * "sum"` rule, so independent regions corroborating the same anchor ADD
856
- * rather than compete to be the cheapest route (see {@link Rule.combine} in
857
- * derive/src/deduction.ts). Run through the very engine {@link
858
- * GraphSearch} covers with — `lightestDerivation` — so a pooled-evidence
859
- * decision is, like a followed edge or a spliced connector, one weighted
860
- * rule of the SAME deduction system, not a separate hand-rolled tally that
861
- * merely logs alongside it. `votesIdf`/`support` are the same two
862
- * read-outs {@link commitVotes} always gated on; only how they accumulate
863
- * changed. */
864
- export function poolVotes(ctx, regionVotes, sat, N, td) {
865
- const eligible = [];
866
- for (let ri = 0; ri < regionVotes.length; ri++) {
867
- const rv = regionVotes[ri];
868
- if (rv.canonicalFailed &&
869
- sat.intervals.some((iv) => rv.start >= iv.start && rv.end <= iv.end)) {
870
- continue;
871
- }
872
- eligible.push(ri);
873
- }
874
- if (td) {
875
- td.pooling = {
876
- inputVotes: regionVotes.length,
877
- eligibleVotes: eligible.length,
878
- saturationMaskedVotes: regionVotes.length - eligible.length,
879
- };
880
- }
881
- // The one hub bound (traverse.ts) — N here IS corpusN, threaded down from
882
- // computeAttention. Read once, not per rule application.
883
- const bound = hubBound(ctx);
884
- const key = (it) => it.kind === "region"
885
- ? `r${it.ri}`
886
- : it.kind === "anchor"
887
- ? `a${it.id}`
888
- : `x${it.id}`;
889
- const pool = new Map();
890
- const system = {
891
- key,
892
- *axioms() {
893
- for (const ri of eligible) {
894
- yield { item: { kind: "region", ri }, cost: 0 };
895
- }
896
- },
897
- isGoal: () => false, // exhaust every axiom; there is no single goal to stop at
898
- // Every region axiom ties at cost 0, so the agenda's pop order among them
899
- // is otherwise unspecified; ordering by `ri` here only steers the HEAP
900
- // (never added to a stored cost — see relax's use of h) so pooling fires
901
- // in exactly the regionVotes array order the original loop used, byte-for-
902
- // byte reproducing its accumulation and tie-break order.
903
- heuristic: (it) => it.kind === "region" ? it.ri : 0,
904
- *rules(it) {
905
- if (it.kind !== "region")
906
- return;
907
- const rv = regionVotes[it.ri];
908
- // The same hub bound the rest of the system uses (edgeAncestors' parent
909
- // cutoff, chooseNext's candidate cap): a terminal answer followed by
910
- // more than √N contexts is a non-discriminative hub — spreading a
911
- // region's vote across its FULL corpus-sized fan-in yields O(corpus)
912
- // rule applications per region and near-zero per-target weight anyway.
913
- // Cap the redistribution at the first √N contexts (insertion order,
914
- // the same convention chooseNext caps by). Hoisted out of the
915
- // generator: `rules` is invoked once per popped item, and this used to
916
- // re-derive the bound on every one of them.
917
- for (const r of rv.roots) {
918
- // CAPPED read: only the first hubBound targets are ever credited, so
919
- // only they are read — a common continuation's full reverse fan-in
920
- // is corpus-sized and is never materialised.
921
- const pv = ctx.store.prevFirst(r, bound);
922
- const isAnswer = pv.length > 0 && !ctx.store.hasNext(r);
923
- const targets = isAnswer ? pv : [r];
924
- for (const t of targets) {
925
- yield {
926
- premises: [it],
927
- conclusion: { kind: "anchor", id: t },
928
- cost: rv.w / targets.length,
929
- combine: "sum",
930
- };
931
- yield {
932
- premises: [it],
933
- conclusion: { kind: "anchorFocus", id: t },
934
- cost: rv.wFocus / targets.length,
935
- combine: "sum",
936
- };
937
- }
938
- }
939
- },
940
- pool,
941
- };
942
- lightestDerivation(system);
943
- const votes = new Map();
944
- const votesIdf = new Map();
945
- const support = new Map();
946
- const regionSupport = new Map();
947
- const regionSpans = new Map();
948
- // ONE POOLED AXIOM = ONE REGION VOTE. Counted separately from the spans
949
- // below because the two are different quantities: a JOINT binding is a
950
- // single vote whose evidence sits in several separate places (RegionVote.
951
- // parts), so its span count exceeds its axiom count. Reading the axiom
952
- // count off `regionSpans.length` conflated them and broke the accounting
953
- // both ways — contributingEvidence (absorbed-weighted, one term per
954
- // REGION) could read below it, and it could exceed the query's whole
955
- // candidate-region count.
956
- const regionAxioms = new Map();
957
- // ANCHORS THE QUERY ITSELF POINTED AT. votesIdf is keyed by anchor node,
958
- // but root election has to know something about the REGIONS underneath it:
959
- // whether at least one of them is a structure the query wove, rather than a
960
- // form its cut split and collectRegions recovered (Region.corroborating).
961
- // An anchor standing on corroborating evidence ALONE is a real, well-priced
962
- // vote — it just is not a point of attention the query made, so it must not
963
- // enter the distribution the root cut is read from, nor the breadth ratio.
964
- //
965
- // REFUTED: barring such anchors from ROOT CANDIDACY outright. It defeats
966
- // the purpose — in the log case the CORRECT record (request_id=1042, one
967
- // context of 205) is addressable ONLY through the form the cut split, so
968
- // rejecting it handed the answer back to the near-miss 1050 (vote 5.60 ->
969
- // 3.81). Grounding follows where the evidence points; what a corroborating
970
- // region must not do is make the query look like it wove one more topic
971
- // than it did.
972
- const anchored = new Set();
973
- // The LARGEST single region's contribution to this anchor's pooled vote.
974
- // The pool is a SUM (deliberately — see the pooling note above), so it says
975
- // how much evidence there is in total, never whether any ONE place in the
976
- // query carries evidence on its own. Consumers that hold an anchor to
977
- // consensusFloor(N) = ln(N) + 1/2 need the latter: that bar prices ONE
978
- // region's maximally-discriminative evidence (ln N is the IDF of content
979
- // reaching a single context), so comparing a six-region sum against it is a
980
- // dimensional error. Recorded here, beside the count, because this is the
981
- // only place the per-region contributions are still separable.
982
- const regionPeak = new Map();
983
- const steps = [];
984
- let order = 0;
985
- for (const pc of pool.values()) {
986
- if (pc.item.kind === "anchor") {
987
- votes.set(pc.item.id, pc.cost);
988
- const premises = [];
989
- const seenRi = new Set();
990
- let breadthSum = 0;
991
- const spans = [];
992
- for (const c of pc.contributions) {
993
- const p0 = c.premises[0].item;
994
- if (p0.kind !== "region" || seenRi.has(p0.ri))
995
- continue;
996
- seenRi.add(p0.ri);
997
- const rv = regionVotes[p0.ri];
998
- // Breadth is a ratio over the query's OWN candidate points of
999
- // attention (see below), and a corroborating region is not one of
1000
- // those — it enters neither side of that ratio, so breadth reads
1001
- // exactly as it did before such regions existed. Its evidence still
1002
- // counts everywhere else: it is a premise, and it is a separate
1003
- // PLACE for cluster counting — corroborating is what it is for.
1004
- if (!rv.corroborating) {
1005
- breadthSum += rv.absorbed ?? 1;
1006
- anchored.add(pc.item.id);
1007
- }
1008
- premises.push({ kind: "form", span: [rv.start, rv.end] });
1009
- // A vote knows where its own evidence sits: `parts` when it stands on
1010
- // several separate places (a joint binding), the merged span
1011
- // otherwise. See RegionVote.parts.
1012
- if (rv.parts !== undefined) {
1013
- for (const [s, e] of rv.parts)
1014
- spans.push([s, e]);
1015
- }
1016
- else
1017
- spans.push([rv.start, rv.end]);
1018
- }
1019
- regionSupport.set(pc.item.id, breadthSum);
1020
- // A span is a PLACE, and the same place reached through two different
1021
- // votes (a standalone region and one part of a joint binding) is still
1022
- // one place — listing it twice reports evidence the query does not
1023
- // separately hold. Measured on test/50's fixture: span [18,21)
1024
- // appeared twice among the top anchor's five.
1025
- const seenSpan = new Set();
1026
- regionSpans.set(pc.item.id, spans.filter((sp) => {
1027
- const key = `${sp[0]}:${sp[1]}`;
1028
- if (seenSpan.has(key))
1029
- return false;
1030
- seenSpan.add(key);
1031
- return true;
1032
- }));
1033
- regionAxioms.set(pc.item.id, seenRi.size);
1034
- let peak = 0;
1035
- for (const c of pc.contributions) {
1036
- const p0 = c.premises[0].item;
1037
- if (p0.kind !== "region")
1038
- continue;
1039
- const rv = regionVotes[p0.ri];
1040
- const own = rv.wFocus ?? rv.w;
1041
- if (own > peak)
1042
- peak = own;
1043
- }
1044
- regionPeak.set(pc.item.id, peak);
1045
- steps.push({
1046
- order: order++,
1047
- move: "pool-vote",
1048
- premises,
1049
- conclusion: { kind: "form", span: [-1, -1], node: pc.item.id },
1050
- cost: pc.cost,
1051
- producers: [],
1052
- });
1053
- }
1054
- else if (pc.item.kind === "anchorFocus") {
1055
- votesIdf.set(pc.item.id, pc.cost);
1056
- let bestRv = null;
1057
- for (const c of pc.contributions) {
1058
- const p0 = c.premises[0].item;
1059
- if (p0.kind !== "region")
1060
- continue;
1061
- const rv = regionVotes[p0.ri];
1062
- if (!bestRv || rv.wFocus > bestRv.wFocus)
1063
- bestRv = rv;
1064
- }
1065
- if (bestRv) {
1066
- support.set(pc.item.id, {
1067
- start: bestRv.start,
1068
- end: bestRv.end,
1069
- w: bestRv.wFocus,
1070
- });
1071
- }
1072
- }
1073
- }
1074
- return {
1075
- votes,
1076
- votesIdf,
1077
- support,
1078
- regionSupport,
1079
- regionSpans,
1080
- regionAxioms,
1081
- regionPeak,
1082
- anchored,
1083
- steps,
1084
- };
1085
- }
1086
- /** The number of DISTINCT clusters a root's contributing regions form —
1087
- * see Attention.clusters. Two regions belong to the same cluster iff the
1088
- * gap between them is strictly less than one river-fold quantum W: at
1089
- * that distance there is no room for a genuinely separate, independently
1090
- * perceivable unit of content between them (the same "smallest meaningful
1091
- * distinction" quantum {@link reachThreshold}'s own doc invokes). A gap
1092
- * of a full quantum or more means real, separate structure could sit
1093
- * between the two spans, so they count as independent corroboration.
1094
- * Strict `<` (not `<=`): verified against gap 3.1's own "gender equality"
1095
- * root, whose two genuine clusters sit EXACTLY W bytes apart — `<= W`
1096
- * would wrongly merge them into one and break that pinned requirement. */
1097
- function countClusters(spans, W) {
1098
- if (spans.length === 0)
1099
- return 0;
1100
- const sorted = [...spans].sort((a, b) => a[0] - b[0]);
1101
- let clusters = 1;
1102
- let curEnd = sorted[0][1];
1103
- for (let i = 1; i < sorted.length; i++) {
1104
- const [s, e] = sorted[i];
1105
- if (s - curEnd < W) {
1106
- curEnd = Math.max(curEnd, e);
1107
- }
1108
- else {
1109
- clusters++;
1110
- curEnd = e;
1111
- }
1112
- }
1113
- return clusters;
1114
- }
1115
- export function commitVotes(ctx, pooled, sat, regions, regionVoter, N, td, cfg) {
1116
- const { votes, votesIdf, support, regionSupport, regionSpans, regionAxioms, regionPeak, anchored, steps, } = pooled;
1117
- if (votes.size === 0) {
1118
- traceAttention(ctx, regions, regionVoter, [], steps, td, cfg);
1119
- return { roots: [], ranked: [] };
1120
- }
1121
- // SCALE-INVARIANT confidence — see Attention.breadth's doc. regions.length
1122
- // is the query's OWN full candidate count (most never vote at all), the
1123
- // same denominator the "N of M sub-regions voted" rationale text already
1124
- // reports; regionSupport is that same accounting read PER ANCHOR.
1125
- // Corroborating regions are excluded from the denominator for the same
1126
- // reason they are excluded from the numerator (see poolVotes): they are
1127
- // not candidate points of attention the query wove, so counting them would
1128
- // silently shrink every anchor's breadth — measured: test/36's genuine
1129
- // second topic fell 6/11 -> 6/12 and fusion's dispersion gate dropped it,
1130
- // with nothing else about the climb changed.
1131
- const totalRegions = Math.max(1, regions.filter((r) => !r.corroborating).length);
1132
- const ranked = [...votes.entries()]
1133
- .map(([anchor, vote]) => {
1134
- const s = support.get(anchor);
1135
- return {
1136
- anchor,
1137
- vote,
1138
- peak: regionPeak.get(anchor) ?? 0,
1139
- start: s.start,
1140
- end: s.end,
1141
- breadth: (regionSupport.get(anchor) ?? 0) / totalRegions,
1142
- clusters: countClusters(regionSpans.get(anchor) ?? [], ctx.space.maxGroup),
1143
- };
1144
- })
1145
- .sort((a, b) => b.vote - a.vote);
1146
- const overlaps = (a, b) => a.start < b.end && b.start < a.end;
1147
- // Read the root cut from the anchors the QUERY pointed at. A vote standing
1148
- // only on corroborating evidence (a form the query's cut split, recovered
1149
- // by lookup — Region.corroborating) is evidence for someone else's anchor,
1150
- // never a point of attention of its own: the query never wove it as an
1151
- // independent structure, the fold did that. Letting such votes into
1152
- // idfDesc shifts naturalBreak — they are exact, hence high-IDF, hence they
1153
- // land at the top of the distribution — and a 2-topic query then elects 3
1154
- // roots (test/24:404, and the answered-continuation exclusion probe).
1155
- const idfDesc = [...votesIdf.entries()]
1156
- .filter(([anchor]) => anchored.has(anchor))
1157
- .map(([, v]) => v)
1158
- .sort((a, b) => b - a);
1159
- const rootCut = naturalBreak(idfDesc);
1160
- // A FURTHER point of attention (beyond the dominant one, which always
1161
- // grounds) must clear the same absolute significance floor
1162
- // recallByResonance trusts a climb anchor with — log(N) + 1/2, three-ish
1163
- // halvings of confidence above pure chance at this corpus scale — not
1164
- // merely beat whatever its immediate neighbour in the ratio happens to be.
1165
- // Without it, naturalBreak's ratio is scale-free but not FLOOR-free: on a
1166
- // large, topic-diverse corpus the steepest ratio in a long noise tail can
1167
- // sit far below any real signal, admitting scaffolding echoes as if they
1168
- // were genuine further topics.
1169
- const floor = consensusFloor(N);
1170
- const placed = [];
1171
- const roots = [];
1172
- const recordAnchor = (point, rank, status, dominant, passesNaturalBreak, passesConsensusFloor, pastLeadingSaturation, rejectionReasons) => {
1173
- if (!td)
1174
- return;
1175
- td.anchors.push({
1176
- anchor: point.anchor,
1177
- rank,
1178
- pooledVote: point.vote,
1179
- idfVote: votesIdf.get(point.anchor) ?? 0,
1180
- candidateBreadth: regions.length,
1181
- contributingVotes: regionAxioms.get(point.anchor) ?? 0,
1182
- contributingEvidence: regionSupport.get(point.anchor) ?? 0,
1183
- breadth: point.breadth,
1184
- contributingSpans: regionSpans.get(point.anchor) ?? [],
1185
- clusters: point.clusters,
1186
- commit: {
1187
- status,
1188
- dominant,
1189
- passesNaturalBreak,
1190
- passesConsensusFloor,
1191
- pastLeadingSaturation,
1192
- rejectionReasons,
1193
- },
1194
- });
1195
- };
1196
- for (let rank = 0; rank < ranked.length; rank++) {
1197
- const point = ranked[rank];
1198
- const absorbed = placed.some((p) => overlaps(point, p));
1199
- // Commit decisions are recorded LIVE, inside this loop, in the exact
1200
- // shape the gates below apply them — never reconstructed afterward from
1201
- // the final `roots` (spec §8's explicit requirement).
1202
- let status;
1203
- let dominant = false;
1204
- let passesNaturalBreak;
1205
- let passesConsensusFloor;
1206
- let pastLeadingSaturation;
1207
- const rejectionReasons = [];
1208
- if (absorbed) {
1209
- status = "overlap";
1210
- }
1211
- else {
1212
- const pastLeading = !sat.hasLeading ||
1213
- roots.length === 0 || point.start >= sat.leadingEnd;
1214
- pastLeadingSaturation = pastLeading;
1215
- const vote = votesIdf.get(point.anchor) ?? 0;
1216
- if (roots.length === 0) {
1217
- // The first non-overlapping root is DOMINANT and bypasses the two
1218
- // vote thresholds (it always grounds) — only the leading-saturation
1219
- // gate still applies to it.
1220
- dominant = true;
1221
- if (pastLeading) {
1222
- status = "root";
1223
- }
1224
- else {
1225
- status = "rejected";
1226
- rejectionReasons.push("leading-saturation");
1227
- }
1228
- }
1229
- else {
1230
- passesNaturalBreak = vote >= rootCut;
1231
- passesConsensusFloor = vote >= floor;
1232
- if (passesNaturalBreak && passesConsensusFloor && pastLeading) {
1233
- status = "root";
1234
- }
1235
- else {
1236
- status = "rejected";
1237
- if (!passesNaturalBreak)
1238
- rejectionReasons.push("below-natural-break");
1239
- if (!passesConsensusFloor) {
1240
- rejectionReasons.push("below-consensus-floor");
1241
- }
1242
- if (!pastLeading)
1243
- rejectionReasons.push("leading-saturation");
1244
- }
1245
- }
1246
- if (status === "root") {
1247
- roots.push(point);
1248
- }
1249
- else {
1250
- recordAnchor(point, rank, status, dominant, passesNaturalBreak, passesConsensusFloor, pastLeadingSaturation, rejectionReasons);
1251
- continue;
1252
- }
1253
- }
1254
- recordAnchor(point, rank, status, dominant, passesNaturalBreak, passesConsensusFloor, pastLeadingSaturation, rejectionReasons);
1255
- placed.push(point);
1256
- }
1257
- traceAttention(ctx, regions, regionVoter, roots, steps, td, cfg ? { ...cfg, naturalBreak: rootCut, consensusFloor: floor } : undefined, ranked);
1258
- return { roots, ranked };
1259
- }
1260
- export function detectSaturated(ctx, regions, saturated) {
1261
- // Intervals are built from CHUNK regions only. collectRegions emits the
1262
- // tree in POST-ORDER — a parent region arrives AFTER its children and
1263
- // shares its first child's `start` — so the raw array is not monotone in
1264
- // byte position, and a saturated parent would fuse with a later saturated
1265
- // chunk into an interval swallowing a NON-saturated child. Chunk regions
1266
- // (leaf-parents) are disjoint and already in byte order, and saturation
1267
- // masking exists to drop canonicalFailed CHUNK votes (see poolVotes), so
1268
- // chunks are both the sufficient and the safe basis. A region without a
1269
- // `chunk` flag (a bare {start,end} from a direct caller) is treated as a
1270
- // chunk.
1271
- const intervals = [];
1272
- let intStart = -1;
1273
- let intEnd = -1;
1274
- let totalLen = 0;
1275
- for (let ri = 0; ri < regions.length; ri++) {
1276
- const r = regions[ri];
1277
- totalLen = Math.max(totalLen, r.end);
1278
- if (r.chunk === false)
1279
- continue;
1280
- if (saturated[ri]) {
1281
- if (intStart === -1)
1282
- intStart = r.start;
1283
- intEnd = r.end;
1284
- }
1285
- else {
1286
- if (intStart !== -1) {
1287
- intervals.push({ start: intStart, end: intEnd });
1288
- intStart = -1;
1289
- }
1290
- }
1291
- }
1292
- if (intStart !== -1) {
1293
- intervals.push({ start: intStart, end: intEnd });
1294
- }
1295
- const leading = intervals.length > 0 && intervals[0].start === 0
1296
- ? intervals[0]
1297
- : null;
1298
- const hasLeading = leading !== null &&
1299
- leading.end >= ctx.space.maxGroup &&
1300
- leading.end < totalLen;
1301
- const leadingEnd = leading !== null ? leading.end : 0;
1302
- return { leadingEnd, hasLeading, intervals };
1303
- }
1304
- /** Set equality of two climb root lists (the "same conclusion" test the
1305
- * contrastive margin skips rivals by). */
1306
- function sameRoots(a, b) {
1307
- if (a.length !== b.length)
1308
- return false;
1309
- const s = new Set(a);
1310
- for (const x of b)
1311
- if (!s.has(x))
1312
- return false;
1313
- return true;
1314
- }
1315
- export function canonicalChunkId(ctx, regionBytes, N, reachMemo) {
1316
- const len = Math.min(regionBytes.length, ctx.space.maxGroup);
1317
- // WHICH window anchors a region is decided by reach, not by position. This
1318
- // used to return at the FIRST offset that matched, which was indistinguishable
1319
- // from correct while every region was exactly W bytes — there was only one
1320
- // offset. A content-defined segment is longer, and its first window is
1321
- // whatever happens to start it: for "is frigi" that is " is ", pure
1322
- // scaffolding, which reaches every context, saturates, and makes the whole
1323
- // region ABSTAIN. The region's own content ("frigi") never got a say, and
1324
- // CAST lost a point of attention it needed (test/29 D1/D2).
1325
- //
1326
- // So scan every offset and prefer an anchor that still discriminates: not
1327
- // saturated, and among those the one reaching the FEWEST contexts (§2.7,
1328
- // corpus-global). Only when every window in the region saturates does the
1329
- // old generalising choice stand — there is then no discriminative anchor to
1330
- // find, and abstaining is the honest outcome.
1331
- let discId = null;
1332
- let discReached = Infinity;
1333
- let fallback = null;
1334
- for (let off = 0; off + len <= regionBytes.length; off++) {
1335
- const ids = leafIdRun(ctx, regionBytes, off, off + len);
1336
- // An unknown byte disqualifies THIS window, not the region. This used to
1337
- // abandon the whole region on the first unseen byte, which was
1338
- // indistinguishable from correct while regions were exactly W bytes — there
1339
- // was one window, so failing it was failing the region. A content-defined
1340
- // segment holds several windows, and a single unknown byte near its start
1341
- // was silently costing the region its anchor entirely.
1342
- if (ids === null)
1343
- continue;
1344
- const flatId = ctx.store.findBranch(ids);
1345
- if (flatId === null)
1346
- continue;
1347
- if (len < 2)
1348
- return flatId;
1349
- // Within one window, the widest reach is still the right CANONICAL
1350
- // identity — a chunk's anchor should be its most general stable form.
1351
- let bestId = flatId;
1352
- let bestReach = edgeAncestors(ctx, flatId, N, reachMemo);
1353
- for (let k2 = 1; k2 < len; k2++) {
1354
- const shortIds = ids.slice(0, len - k2);
1355
- const shortId = ctx.store.findBranch(shortIds);
1356
- if (shortId === null)
1357
- continue;
1358
- const shortReach = edgeAncestors(ctx, shortId, N, reachMemo);
1359
- if (shortReach.saturated ||
1360
- shortReach.contextsReached > bestReach.contextsReached) {
1361
- bestId = shortId;
1362
- bestReach = shortReach;
1363
- }
1364
- }
1365
- if (fallback === null)
1366
- fallback = bestId;
1367
- if (!bestReach.saturated && bestReach.contextsReached < discReached) {
1368
- discId = bestId;
1369
- discReached = bestReach.contextsReached;
1370
- // Nothing can discriminate better than reaching ONE context, so the scan
1371
- // stops there rather than pricing the rest of the segment's windows.
1372
- if (discReached <= 1)
1373
- break;
1374
- }
1375
- }
1376
- return discId ?? fallback;
1377
- }
1378
- export function naturalBreak(votes) {
1379
- if (votes.length <= 1)
1380
- return votes[0] ?? 0;
1381
- let breakAt = 1;
1382
- let steepest = Infinity;
1383
- for (let i = 1; i < votes.length; i++) {
1384
- if (votes[i - 1] <= 0)
1385
- break;
1386
- const ratio = votes[i] / votes[i - 1];
1387
- if (ratio < steepest) {
1388
- steepest = ratio;
1389
- breakAt = i;
1390
- }
1391
- }
1392
- return votes[breakAt - 1];
1393
- }
1394
- const VARIANT_KIND_ORDER = {
1395
- "exact-exact": -1,
1396
- "left-synonym": 0,
1397
- "right-synonym": 1,
1398
- "double-synonym": 2,
1399
- };
1400
- /** Same deterministic ordering the old implementation applied to already-
1401
- * materialized variants (§8): semantic confidence desc, then kind
1402
- * (left-synonym, right-synonym, double-synonym), then sibling ids asc. */
1403
- function compareStructuralVariantSpecs(a, b) {
1404
- return b.semanticConfidence - a.semanticConfidence ||
1405
- VARIANT_KIND_ORDER[a.kind] - VARIANT_KIND_ORDER[b.kind] ||
1406
- (a.leftSiblingId ?? -1) - (b.leftSiblingId ?? -1) ||
1407
- (a.rightSiblingId ?? -1) - (b.rightSiblingId ?? -1);
1408
- }
1409
- /** Every single- and double-synonym combination, as cost-free descriptors —
1410
- * no `read`, `gistOf`, `perceive` or `StructuralPart` allocation. Both
1411
- * sibling lists are already bounded by `haloQueryK`, so the O(haloQueryK²)
1412
- * cross-product here is cheap; only the SELECTED specs go on to pay for
1413
- * sibling reconstruction. */
1414
- function buildStructuralVariantSpecs(sides) {
1415
- const specs = [];
1416
- for (const left of sides.leftSiblings) {
1417
- specs.push({
1418
- kind: "left-synonym",
1419
- semanticConfidence: left.score,
1420
- leftSiblingId: left.id,
1421
- });
1422
- }
1423
- for (const right of sides.rightSiblings) {
1424
- specs.push({
1425
- kind: "right-synonym",
1426
- semanticConfidence: right.score,
1427
- rightSiblingId: right.id,
1428
- });
1429
- }
1430
- for (const left of sides.leftSiblings) {
1431
- for (const right of sides.rightSiblings) {
1432
- specs.push({
1433
- kind: "double-synonym",
1434
- semanticConfidence: Math.min(left.score, right.score),
1435
- leftSiblingId: left.id,
1436
- rightSiblingId: right.id,
1437
- });
1438
- }
1439
- }
1440
- specs.sort(compareStructuralVariantSpecs);
1441
- return specs;
1442
- }
1443
- /** A halo sibling's structural gist, bounded to `maxBytes` of stored content
1444
- * and reused across the whole climb. `positiveMemo` (shared across every
1445
- * probe in the climb, passed in by the caller) remembers only successfully
1446
- * reconstructed complete gists together with their complete byte length —
1447
- * a sibling rejected here for being too large for THIS pair's phrase-scale
1448
- * bound may still be admissible for a larger-spanning pair later, so a
1449
- * rejection is never memoized globally, and a sibling cached by a LARGER
1450
- * probe is only reused here when its length still fits THIS probe's
1451
- * (possibly smaller) bound — eligibility must never depend on which probe
1452
- * happened to cache the sibling first. `localMemo` is scoped to one
1453
- * `buildStructuralVariants` call, where every variant shares the same
1454
- * bound, so a `null` there is safe to reuse. */
1455
- function loadBoundedSiblingGist(ctx, id, maxBytes, positiveMemo, localMemo) {
1456
- if (localMemo.has(id)) {
1457
- return localMemo.get(id) ?? null;
1458
- }
1459
- const cached = positiveMemo.get(id);
1460
- if (cached !== undefined) {
1461
- const result = cached.length <= maxBytes ? cached.gist : null;
1462
- localMemo.set(id, result);
1463
- return result;
1464
- }
1465
- const length = ctx.store.contentLen(id, maxBytes + 1);
1466
- if (length <= 0 || length > maxBytes) {
1467
- localMemo.set(id, null);
1468
- return null;
1469
- }
1470
- const bytes = read(ctx, id, maxBytes + 1);
1471
- if (bytes.length === 0 || bytes.length > maxBytes) {
1472
- localMemo.set(id, null);
1473
- return null;
1474
- }
1475
- const gist = gistOf(ctx, bytes);
1476
- positiveMemo.set(id, { gist, length });
1477
- localMemo.set(id, gist);
1478
- return gist;
1479
- }
1480
- /** Build, bound and order every mandatory structural variant (§7-8): the
1481
- * exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
1482
- * synonym variants (single- and double-synonym combined, one shared
1483
- * budget) are appended, ordered by confidence, then kind, then sibling id.
1484
- * Variant selection is entirely lightweight (see {@link
1485
- * buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
1486
- * only for specs actually retained, and at most once per sibling id per
1487
- * climb via `siblingGistMemo`. */
1488
- export function buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo) {
1489
- const leftLen = ra.end - ra.start;
1490
- const rightLen = rb.end - rb.start;
1491
- const exactLeft = { v: ra.v, len: leftLen };
1492
- const exactRight = { v: rb.v, len: rightLen };
1493
- const variants = [
1494
- {
1495
- left: exactLeft,
1496
- right: exactRight,
1497
- kind: "exact-exact",
1498
- semanticConfidence: 1,
1499
- },
1500
- ];
1501
- // Same phrase-scale bound the cross-region junction ladder uses
1502
- // (`maxInterior`): a sibling whose complete stored content exceeds it is
1503
- // not materialized as a structural-resonance endpoint, keeping sibling
1504
- // reconstruction phrase-scale even for a large deposit or conversation
1505
- // root that merely appeared in a halo result.
1506
- const maxSiblingBytes = (leftLen + rightLen) * ctx.space.maxGroup;
1507
- const specs = buildStructuralVariantSpecs(sides);
1508
- const localGistMemo = new Map();
1509
- let retainedSynonyms = 0;
1510
- for (const spec of specs) {
1511
- if (retainedSynonyms >= ctx.cfg.haloQueryK)
1512
- break;
1513
- let left = exactLeft;
1514
- let right = exactRight;
1515
- if (spec.leftSiblingId !== undefined) {
1516
- const gist = loadBoundedSiblingGist(ctx, spec.leftSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
1517
- if (gist === null)
1518
- continue;
1519
- left = { v: gist, len: leftLen };
1520
- }
1521
- if (spec.rightSiblingId !== undefined) {
1522
- const gist = loadBoundedSiblingGist(ctx, spec.rightSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
1523
- if (gist === null)
1524
- continue;
1525
- right = { v: gist, len: rightLen };
1526
- }
1527
- variants.push({
1528
- left,
1529
- right,
1530
- kind: spec.kind,
1531
- semanticConfidence: spec.semanticConfidence,
1532
- leftSiblingId: spec.leftSiblingId,
1533
- rightSiblingId: spec.rightSiblingId,
1534
- });
1535
- retainedSynonyms++;
1536
- }
1537
- return { variants, exactLeft, exactRight };
1538
- }
1539
- /** Deterministic best-of tie-break for two proposals ranked for the SAME
1540
- * candidate id — effectiveScore, then annScore, then semanticConfidence,
1541
- * then variant kind, then sibling ids (§10). */
1542
- function betterProposal(a, b) {
1543
- if (a.effectiveScore !== b.effectiveScore) {
1544
- return a.effectiveScore > b.effectiveScore;
1545
- }
1546
- if (a.annScore !== b.annScore)
1547
- return a.annScore > b.annScore;
1548
- if (a.semanticConfidence !== b.semanticConfidence) {
1549
- return a.semanticConfidence > b.semanticConfidence;
1550
- }
1551
- if (VARIANT_KIND_ORDER[a.variant] !== VARIANT_KIND_ORDER[b.variant]) {
1552
- return VARIANT_KIND_ORDER[a.variant] < VARIANT_KIND_ORDER[b.variant];
1553
- }
1554
- if ((a.leftSiblingId ?? -1) !== (b.leftSiblingId ?? -1)) {
1555
- return (a.leftSiblingId ?? -1) < (b.leftSiblingId ?? -1);
1556
- }
1557
- return (a.rightSiblingId ?? -1) < (b.rightSiblingId ?? -1);
1558
- }
1559
- /** The final approximate tier: compose every retained structural variant,
1560
- * ANN-query each, merge proposals by candidate id, and validate the winner
1561
- * through the SAME structural gates every other tier answers to (saturation,
1562
- * roots, IDF, contrastive margin). Returns null when nothing survives. */
1563
- /** {@link structuralResonance}, charged to its own profiling phase — it is
1564
- * the halo-mediated arm of the cross-region ladder and the one part of it
1565
- * that resonates. */
1566
- async function meteredStructuralResonance(...args) {
1567
- const ctx = args[0];
1568
- return ctx.meter
1569
- ? await ctx.meter.time("climb.structuralResonance", () => structuralResonance(...args))
1570
- : await structuralResonance(...args);
1571
- }
1572
- export async function structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo,
1573
- /** Each side's OWN individual climb roots (from voteRegions), when it cast
1574
- * one — the self-evidence backstop structural-resonance needs and the
1575
- * exact tier gets for free from literal byte containment (§11's whole
1576
- * premise: recover a JOINT context neither side votes for alone). A
1577
- * candidate whose reach is exactly one side's own conclusion is not new
1578
- * evidence of a joint whole; it is that side's resonance rediscovering
1579
- * itself through a synthetic gist still dominated by its own direction. */
1580
- ownRootsA, ownRootsB, trace) {
1581
- const { variants } = buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo);
1582
- if (trace)
1583
- trace.variantBudget = ctx.cfg.haloQueryK;
1584
- const middleBytes = query.subarray(ra.end, rb.start);
1585
- const middlePart = middleBytes.length === 0
1586
- ? null
1587
- : { v: perceive(ctx, middleBytes).v, len: middleBytes.length };
1588
- const proposals = new Map();
1589
- for (const variant of variants) {
1590
- const parts = [variant.left];
1591
- if (middlePart)
1592
- parts.push(middlePart);
1593
- parts.push(variant.right);
1594
- const synthetic = composeStructuralGist(ctx.space, parts);
1595
- const hits = await ctx.store.resonate(synthetic, k);
1596
- if (trace) {
1597
- trace.variants.push({
1598
- kind: variant.kind,
1599
- semanticConfidence: variant.semanticConfidence,
1600
- leftSiblingId: variant.leftSiblingId,
1601
- rightSiblingId: variant.rightSiblingId,
1602
- annHitsReturned: hits.length,
1603
- });
1604
- }
1605
- for (const hit of hits) {
1606
- const candidate = {
1607
- id: hit.id,
1608
- annScore: hit.score,
1609
- semanticConfidence: variant.semanticConfidence,
1610
- effectiveScore: hit.score * variant.semanticConfidence,
1611
- variant: variant.kind,
1612
- leftSiblingId: variant.leftSiblingId,
1613
- rightSiblingId: variant.rightSiblingId,
1614
- };
1615
- const prev = proposals.get(hit.id);
1616
- if (prev === undefined || betterProposal(candidate, prev)) {
1617
- proposals.set(hit.id, candidate);
1618
- }
1619
- }
1620
- }
1621
- if (trace)
1622
- trace.mergedProposals = proposals.size;
1623
- if (proposals.size === 0) {
1624
- if (trace) {
1625
- trace.noiseFloor = estimatorNoise(ctx.store.D);
1626
- trace.outcome = "empty";
1627
- }
1628
- return null;
1629
- }
1630
- const sorted = [...proposals.values()].sort((a, b) => b.effectiveScore - a.effectiveScore || a.id - b.id);
1631
- // One shared shape for every `examined` entry (spec §5): only `outcome`
1632
- // varies across the six exit points below, so build it once instead of
1633
- // repeating the six-field literal at each site.
1634
- const recordExamined = (p, outcome) => {
1635
- if (!trace)
1636
- return;
1637
- trace.examined.push({
1638
- node: p.id,
1639
- variant: p.variant,
1640
- leftSiblingId: p.leftSiblingId,
1641
- rightSiblingId: p.rightSiblingId,
1642
- annScore: p.annScore,
1643
- semanticConfidence: p.semanticConfidence,
1644
- effectiveScore: p.effectiveScore,
1645
- outcome,
1646
- });
1647
- };
1648
- let selected = null;
1649
- let selectedReach = null;
1650
- let selectedIdf = 0;
1651
- let rival = null;
1652
- for (const p of sorted) {
1653
- const reach = edgeAncestors(ctx, p.id, N, reachMemo);
1654
- if (reach.saturated || reach.roots.length === 0) {
1655
- recordExamined(p, reach.saturated ? "saturated" : "no-roots");
1656
- continue;
1657
- }
1658
- const idf = Math.log(N / Math.max(1, reach.contextsReached));
1659
- if (idf <= 0) {
1660
- recordExamined(p, "nonpositive-idf");
1661
- continue;
1662
- }
1663
- // Self-evidence backstop (see the param doc above): a candidate that is
1664
- // exactly one side's own already-voted conclusion carries no JOINT
1665
- // evidence — skip it as if it never survived.
1666
- if ((ownRootsA && sameRoots(reach.roots, ownRootsA)) ||
1667
- (ownRootsB && sameRoots(reach.roots, ownRootsB))) {
1668
- recordExamined(p, "same-as-endpoint");
1669
- continue;
1670
- }
1671
- if (selected === null) {
1672
- selected = p;
1673
- selectedReach = reach;
1674
- selectedIdf = idf;
1675
- recordExamined(p, "selected");
1676
- }
1677
- else if (!sameRoots(reach.roots, selectedReach.roots)) {
1678
- rival = p;
1679
- recordExamined(p, "contrastive-rival");
1680
- break;
1681
- }
1682
- else {
1683
- recordExamined(p, "same-as-selected");
1684
- }
1685
- }
1686
- if (selected === null || selectedReach === null) {
1687
- if (trace) {
1688
- trace.noiseFloor = estimatorNoise(ctx.store.D);
1689
- trace.outcome = "no-valid-proposal";
1690
- }
1691
- return null;
1692
- }
1693
- const margin = rival
1694
- ? selected.effectiveScore - rival.effectiveScore
1695
- : selected.effectiveScore;
1696
- if (trace) {
1697
- trace.contrastiveMargin = margin;
1698
- trace.noiseFloor = estimatorNoise(ctx.store.D);
1699
- }
1700
- if (margin <= estimatorNoise(ctx.store.D)) {
1701
- if (trace)
1702
- trace.outcome = "margin-rejected";
1703
- return null;
1704
- }
1705
- if (trace)
1706
- trace.outcome = "accepted";
1707
- return { proposal: selected, reach: selectedReach, idf: selectedIdf };
1708
- }
1709
- async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
1710
- // Candidate regions: every region that ALREADY CAST ITS OWN VOTE in
1711
- // voteRegions — individually idf > 0, genuinely discriminative on its own,
1712
- // just not necessarily for the SAME context as its partner. This is the
1713
- // exact shape of the binding problem: "red" alone votes for `red square`,
1714
- // "circle" alone for `circle` — each independently informative, disagreeing
1715
- // on the conclusion — and only their CONJUNCTION resolves to the one
1716
- // context, `red circle`, that actually holds both.
1717
- //
1718
- // A region that never voted (idf == 0 — e.g. a repeated system-prompt
1719
- // prefix shared by every deposit) carries NO individual signal, and must be
1720
- // excluded here too: ascending from a non-discriminative fragment's seeds
1721
- // can still land on some deeper, incidentally-unique DESCENDANT container —
1722
- // its rarity would come entirely from context OUTSIDE the fragments
1723
- // actually composed, manufacturing confidence the query gave no reason to
1724
- // have. Requiring a prior individual vote is the same discipline the noise
1725
- // drop already applies to single regions, extended to compositions — with
1726
- // one graded relaxation: a KNOWN region that did NOT vote (saturated, or
1727
- // idf ≤ 0) may still serve as the WEAK side of a pair whose other side DID
1728
- // vote. Saturation is an abstention about where the region CLIMBS; its
1729
- // content-addressed identity is still exact, and the junction asks a
1730
- // different question — "which whole holds both?" — whose conclusion the
1731
- // container's own idf gate below still guards. Two non-voting regions
1732
- // never pair (that is exactly the shared-prefix trap above), so at least
1733
- // one side is always individually discriminative.
1734
- //
1735
- // Only MAXIMAL spans compose: a span contained in another candidate is a
1736
- // fragment of that candidate's evidence, never independent of it — but
1737
- // containment alone does not establish that relation. An APPROXIMATE
1738
- // container (a fold segment whose gist merely resonated) does not hold the
1739
- // evidence of an EXACT one (a recognised site, content-addressed): its
1740
- // bytes straddle the site rather than explain it, so calling the site a
1741
- // fragment of it discards the only exact reading of those bytes. Measured:
1742
- // on `blue then square` the segment `blue t` swallowed the site `blue`,
1743
- // leaving one candidate and no pair, while on `red then circle` the
1744
- // segment happened to end at `red `'s edge and the same query shape
1745
- // composed — the outcome turned on where a cut fell. This is the same
1746
- // discipline the between-region gate below already states: an approximate
1747
- // region climbing "somewhere" is ordinary noise, not evidence.
1748
- //
1749
- // Shared across every cross-region probe in this climb: a sibling
1750
- // successfully reconstructed while probing one pair must not be read and
1751
- // perceived again while probing another pair in the same climb.
1752
- const siblingGistMemo = new Map();
1753
- const votedSpans = new Set();
1754
- for (const rv of rvs.votes)
1755
- votedSpans.add(`${rv.start},${rv.end}`);
1756
- const seen = new Set();
1757
- const eligible = [];
1758
- const strong = new Set();
1759
- for (let ri = 0; ri < regions.length; ri++) {
1760
- const r = regions[ri];
1761
- const key = `${r.start},${r.end}`;
1762
- const isStrong = votedSpans.has(key);
1763
- if ((!isStrong && !r.known) || seen.has(key))
1764
- continue;
1765
- seen.add(key);
1766
- eligible.push(ri);
1767
- if (isStrong)
1768
- strong.add(ri);
1769
- }
1770
- const cand = eligible.filter((x) => !eligible.some((y) => y !== x &&
1771
- regions[y].start <= regions[x].start &&
1772
- regions[x].end <= regions[y].end &&
1773
- regions[y].end - regions[y].start > regions[x].end - regions[x].start &&
1774
- (regions[y].known || !regions[x].known)));
1775
- const none = { votes: [], superseded: new Set() };
1776
- if (td) {
1777
- td.crossRegionSummary = {
1778
- eligibleRegions: eligible.length,
1779
- maximalRegions: cand.length,
1780
- probeLimit: k,
1781
- probesAttempted: 0, // updated below as probes accrue
1782
- stopReason: cand.length < 2 ? "insufficient-regions" : undefined,
1783
- };
1784
- }
1785
- if (cand.length < 2)
1786
- return none;
1787
- cand.sort((x, y) => regions[x].start - regions[y].start || regions[x].end - regions[y].end);
1788
- const dec = (b) => new TextDecoder().decode(b).replace(/\s+/g, " ").trim();
1789
- const cache = walkCache(ctx);
1790
- // One junctionSeeds per candidate for the WHOLE pairing loop — a candidate
1791
- // recurs in up to |cand|−1 pairs, and its seeds are a pure function of its
1792
- // bytes.
1793
- const seedsMemo = new Map();
1794
- const seedsOf = (ri) => {
1795
- let s = seedsMemo.get(ri);
1796
- if (s === undefined) {
1797
- const r = regions[ri];
1798
- s = junctionSeeds(ctx, query.subarray(r.start, r.end));
1799
- seedsMemo.set(ri, s);
1800
- }
1801
- return s;
1802
- };
1803
- const overlapsSpan = (e, s) => e.start < s.end && s.start < e.end;
1804
- const out = [];
1805
- const superseded = new Set();
1806
- // A candidate consumed by one junction does not seed another: its evidence
1807
- // is already composed at full joint strength, and re-pairing it would vote
1808
- // the same container (or a sub-container of it) twice.
1809
- const consumed = new Set();
1810
- let probes = 0;
1811
- // Once atoms themselves are hubs (N > W²), the cross-region analysis gets
1812
- // one k·W walk allowance per evidence tier. Without a shared allowance,
1813
- // each of k candidate pairs spends the full corpus-derived budget and a
1814
- // cumulative dialogue multiplies bounded work into tens of seconds. Small
1815
- // corpora retain exhaustive exact traversal: below this same scale the
1816
- // budget would be smaller than the structures the tests deliberately build.
1817
- //
1818
- // MEASURED 2026-07-29, NOT YET RESOLVED. This gate never engages at real
1819
- // scale: on the trained store N = 325,608 with k = 24 and W = 4, so the
1820
- // threshold is 96³ = 884,736 and a third of a million contexts still runs
1821
- // unbudgeted at hubBound·W = 2,280 pops PER PAIR — 160,210 junction pops,
1822
- // 5.9s, 31% of think. Sharing one hubBound·W allowance across all pairs
1823
- // instead cuts that to 22,418 pops and 2.6s (think −19%), but is measurably
1824
- // too tight below ~10³ contexts: test/36 (N = 8, budget 8) loses the
1825
- // `red circle` binding root and test/14 (N = 120, budget 40) recalls 39/40.
1826
- // The sharing is the right shape; hubBound·W is the wrong size for it, and
1827
- // fitting a size to those two points would repeat the mistake the cube
1828
- // already makes — pricing the gate on the synthetic corpora.
1829
- const marketScale = k * ctx.space.maxGroup;
1830
- const corpusScale = N > marketScale ** 3;
1831
- const exactBudget = corpusScale ? { n: k * ctx.space.maxGroup } : undefined;
1832
- const synonymBudget = corpusScale ? { n: k * ctx.space.maxGroup } : undefined;
1833
- for (let a = 0; a < cand.length && probes < k; a++) {
1834
- if (consumed.has(cand[a]))
1835
- continue;
1836
- const ra = regions[cand[a]];
1837
- for (let b = a + 1; b < cand.length && probes < k; b++) {
1838
- if (consumed.has(cand[b]))
1839
- continue;
1840
- const rb = regions[cand[b]];
1841
- if (!strong.has(cand[a]) && !strong.has(cand[b]))
1842
- continue;
1843
- if (ra.end >= rb.start)
1844
- continue; // overlap or adjacent — nothing between
1845
- // In a cumulative conversation, an old↔old interaction cannot explain
1846
- // the user turn currently being answered; it was already available
1847
- // before that turn existed. Keep old↔current pairs (the current turn may
1848
- // refer to a prior answer), but do not repeatedly spend the junction
1849
- // budget recomposing two regions wholly before the current boundary.
1850
- if (ctx.currentTurnStart > 0 && rb.end <= ctx.currentTurnStart)
1851
- continue;
1852
- // Candidates strictly BETWEEN ra and rb (cand is sorted by start, so
1853
- // that is exactly cand[a+1 .. b-1]) that already cast their OWN vote —
1854
- // genuine, individually-corroborated evidence about what fills the gap
1855
- // — gate the container search below: a joint container is binding
1856
- // evidence only when it is CONSISTENT with that evidence, i.e. its own
1857
- // bytes actually contain what the between-region says. This is the
1858
- // n-ary composition's normal shape (a between-attribute's bytes DO
1859
- // recur inside the joint container, credited as an "extra" below) as
1860
- // opposed to a container that silently substitutes something else for
1861
- // it (e.g. bridging past "Italy" to a container whose interior is
1862
- // "Japan" — a different, contradicting learnt whole).
1863
- // Only a KNOWN (content-addressed, exact) between-region qualifies —
1864
- // an approximate region's resonance climbing "somewhere" is ordinary
1865
- // noise (any ANN query returns SOME nearest neighbour), not evidence
1866
- // this specific gap already means something specific.
1867
- const between = [];
1868
- for (let m = a + 1; m < b; m++) {
1869
- if (strong.has(cand[m]) && !consumed.has(cand[m]) &&
1870
- regions[cand[m]].known)
1871
- between.push(cand[m]);
1872
- }
1873
- // A single KNOWN region covering both: the whole form is already a
1874
- // stored identity that votes directly; its pieces add nothing.
1875
- if (regions.some((r) => r.known && r.start <= ra.start && rb.end <= r.end))
1876
- continue;
1877
- probes++;
1878
- if (td?.crossRegionSummary) {
1879
- td.crossRegionSummary.probesAttempted = probes;
1880
- }
1881
- // Trace-only per-probe bookkeeping (spec §2-§7) — built incrementally
1882
- // as the ladder runs, pushed exactly once at whichever exit fires
1883
- // below. `pushProbe` is called at every continue/success exit for
1884
- // THIS pair so the invariant `probes.length === probesAttempted`
1885
- // holds regardless of which tier settled it.
1886
- const probe = td
1887
- ? {
1888
- leftRegionIndex: cand[a],
1889
- rightRegionIndex: cand[b],
1890
- betweenRegionIndices: [...between],
1891
- exact: { attempted: false, candidatesReturned: 0 },
1892
- singleSynonym: { attempted: false, candidatesReturned: 0 },
1893
- doubleSynonym: { attempted: false, candidatesReturned: 0 },
1894
- outcome: "structural-rejected",
1895
- }
1896
- : undefined;
1897
- let probePushed = false;
1898
- const pushProbe = (outcome) => {
1899
- if (!td || !probe || probePushed)
1900
- return;
1901
- probe.outcome = outcome;
1902
- td.crossRegionProbes.push(probe);
1903
- probePushed = true;
1904
- };
1905
- const left = query.subarray(ra.start, ra.end);
1906
- const right = query.subarray(rb.start, rb.end);
1907
- // Phrase-scale contract, exactly as the bridge: the glue between the two
1908
- // forms may be up to W× the content it joins.
1909
- const maxInterior = (left.length + right.length) * ctx.space.maxGroup;
1910
- const cap = left.length + right.length + maxInterior;
1911
- // The graded ladder (spec §1): exact DAG junction, then single-synonym,
1912
- // then double-synonym, then — only when every DAG tier found nothing —
1913
- // structural-resonance. `sides` (the two halo sibling lists) is loaded
1914
- // ONCE and reused by junctionSynonyms AND structural-resonance, so no
1915
- // ladder rung repeats a halo ANN query an earlier rung already paid for.
1916
- const sides = await loadJunctionSynonymSides(ctx, left, right);
1917
- let tier = "exact";
1918
- let containers = junctionContainersFrom(ctx, left, right, cap, seedsOf(cand[a]), seedsOf(cand[b]), exactBudget, true);
1919
- if (probe) {
1920
- probe.exact = {
1921
- attempted: true,
1922
- candidatesReturned: containers.length,
1923
- };
1924
- }
1925
- if (containers.length === 0) {
1926
- // Tiers 2-4 — synonym containers (junctionSynonyms itself runs
1927
- // single-synonym first, falling to double-synonym only when
1928
- // single-synonym found nothing — see junction.ts).
1929
- const syn = await junctionSynonyms(ctx, left, right, maxInterior, true, sides, synonymBudget);
1930
- if (probe) {
1931
- const singleAttempted = sides.leftSiblings.length > 0 ||
1932
- sides.rightSiblings.length > 0;
1933
- const singleReturned = syn[0]?.tier === "single-synonym"
1934
- ? syn.length
1935
- : 0;
1936
- const doubleAttempted = singleAttempted && singleReturned === 0 &&
1937
- sides.leftSiblings.length > 0 && sides.rightSiblings.length > 0;
1938
- const doubleReturned = syn[0]?.tier === "double-synonym"
1939
- ? syn.length
1940
- : 0;
1941
- probe.singleSynonym = {
1942
- attempted: singleAttempted,
1943
- candidatesReturned: singleReturned,
1944
- };
1945
- probe.doubleSynonym = {
1946
- attempted: doubleAttempted,
1947
- candidatesReturned: doubleReturned,
1948
- };
1949
- }
1950
- if (syn.length > 0) {
1951
- containers = syn;
1952
- tier = syn[0].tier;
1953
- }
1954
- }
1955
- // Tier 5 — structural-resonance ANN, the FINAL approximate proposal
1956
- // path. Only reached when every DAG tier found NOTHING, and only when
1957
- // there is no already-corroborated region between the endpoints (a
1958
- // between-region with its own vote is evidence the gap already means
1959
- // something specific — an ANN guess must not override it).
1960
- let structuralPick = null;
1961
- if (containers.length === 0) {
1962
- // Structural-resonance composes each side's OWN gist directly (no
1963
- // byte-containment truth backs it, unlike the DAG tiers) — so, unlike
1964
- // the DAG ladder (which tolerates one approximate side because byte
1965
- // containment cannot lie), the ANN tier requires BOTH sides to be
1966
- // KNOWN (content-addressed, exact identities): an approximate chunk
1967
- // fragment's own resonance is noise at any tier, and composing noise
1968
- // into a synthetic gist only manufactures a plausible-looking but
1969
- // spurious ANN neighbour, not evidence of a genuine joint whole.
1970
- // PHRASE-SCALE CONTRACT — the same one the DAG tiers hold their glue
1971
- // to (see maxInterior above): a junction, exact or approximate, is a
1972
- // whole the two forms nearly exhaust, not two arbitrary landmarks
1973
- // anywhere in a long, multi-topic query. Without this, structural-
1974
- // resonance would pair opposite ends of an unrelated scaffolding-
1975
- // dominated query and manufacture a plausible-looking ANN neighbour
1976
- // for a "gap" that never was a phrase.
1977
- // BOTH sides must be independently DISCRIMINATIVE (individually
1978
- // voted — `strong`, not merely a content-addressed `known` chunk):
1979
- // a shared, non-discriminative scaffolding run (a repeated system
1980
- // preamble) can be `known` without ever being distinctive evidence
1981
- // of anything, and composing its own gist into a synthetic query
1982
- // manufactures a plausible-looking but spurious ANN neighbour. The
1983
- // DAG tiers can tolerate one merely-`known` side because byte
1984
- // containment cannot lie; structural-resonance has no such
1985
- // backstop, so both sides earn their place here the same way an
1986
- // ordinary approximate region earns its individual vote.
1987
- const gap = rb.start - ra.end;
1988
- const reasons = [];
1989
- if (between.length > 0)
1990
- reasons.push("between-region");
1991
- if (!strong.has(cand[a]) || !strong.has(cand[b])) {
1992
- reasons.push("not-both-strong");
1993
- }
1994
- if (!ra.known || !rb.known)
1995
- reasons.push("not-both-known");
1996
- if (gap > maxInterior)
1997
- reasons.push("gap-too-large");
1998
- let resonanceTrace;
1999
- if (reasons.length > 0) {
2000
- if (probe) {
2001
- resonanceTrace = {
2002
- variantBudget: ctx.cfg.haloQueryK,
2003
- variants: [],
2004
- mergedProposals: 0,
2005
- examined: [],
2006
- noiseFloor: estimatorNoise(ctx.store.D),
2007
- outcome: "ineligible",
2008
- ineligibleReasons: reasons,
2009
- };
2010
- probe.resonance = resonanceTrace;
2011
- }
2012
- }
2013
- else {
2014
- if (probe) {
2015
- // `outcome`/`noiseFloor` are required fields with no natural
2016
- // "unset" value; structuralResonance (called just below) always
2017
- // overwrites both before returning, on every one of its exit
2018
- // paths — these are never read in their initial form.
2019
- resonanceTrace = {
2020
- variantBudget: ctx.cfg.haloQueryK,
2021
- variants: [],
2022
- mergedProposals: 0,
2023
- examined: [],
2024
- noiseFloor: 0,
2025
- outcome: "empty",
2026
- };
2027
- probe.resonance = resonanceTrace;
2028
- }
2029
- const ownRootsA = rvs.votes.find((v) => v.start === ra.start && v.end === ra.end)?.roots;
2030
- const ownRootsB = rvs.votes.find((v) => v.start === rb.start && v.end === rb.end)?.roots;
2031
- structuralPick = await meteredStructuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo, ownRootsA, ownRootsB, resonanceTrace);
2032
- }
2033
- if (structuralPick === null) {
2034
- pushProbe(reasons.length > 0 ? "resonance-ineligible" : "resonance-rejected");
2035
- continue;
2036
- }
2037
- tier = "structural-resonance";
2038
- }
2039
- let best = null;
2040
- let bestExtras = [];
2041
- let bestCov = -1;
2042
- let reach;
2043
- let idf;
2044
- let confidence;
2045
- if (structuralPick !== null) {
2046
- // A resonance proposal is NOT a Junction — there is no container to
2047
- // read bytes from, so the self-evidence/contradiction/N-ary
2048
- // machinery below (byte-verified against a real container) does not
2049
- // apply; per spec §13, no N-ary extra-region coverage for resonance
2050
- // proposals.
2051
- best = { id: structuralPick.proposal.id, interior: new Uint8Array(0) };
2052
- bestExtras = [];
2053
- bestCov = rb.end - ra.start;
2054
- reach = structuralPick.reach;
2055
- idf = structuralPick.idf;
2056
- confidence = structuralPick.proposal.effectiveScore;
2057
- }
2058
- else {
2059
- // Aggregate structural-tier trace (spec §4) — one per DAG tier that
2060
- // returned at least one container (exact, single-synonym or
2061
- // double-synonym); only aggregate counts and the final outcome are
2062
- // recorded, never every candidate.
2063
- const structuralTrace = probe
2064
- ? {
2065
- tier: tier,
2066
- selfEvidenceRejected: 0,
2067
- contradictionRejected: 0,
2068
- passedGuards: 0,
2069
- outcome: "all-rejected",
2070
- }
2071
- : undefined;
2072
- if (probe)
2073
- probe.structural = structuralTrace;
2074
- // N-ARY selection: the container covering the MOST remaining candidate
2075
- // forms wins (then tightest interior, then lowest id). Reads are
2076
- // cache hits — every container's bytes were already read by the walk.
2077
- //
2078
- // SELF-EVIDENCE GUARD: a junction is BINDING evidence only when the
2079
- // container joins forms the query mentions APART. When the container's
2080
- // own joined occurrence (left..right including its interior) is a
2081
- // literal substring of the query, the query already spells that phrase
2082
- // out contiguously — perception already voted with it, and grid shards
2083
- // of one phrase pairing "around" a gap chunk would merely rediscover
2084
- // the phrase they are shards of, then explain away its rivals.
2085
- for (const c of containers) {
2086
- const bytes = cachedRead(ctx, cache, c.id, cap);
2087
- const li = indexOf(bytes, left, 0);
2088
- const ri = indexOf(bytes, right, 0);
2089
- if (li >= 0 && ri >= 0) {
2090
- const joined = bytes.subarray(Math.min(li, ri), Math.max(li + left.length, ri + right.length));
2091
- if (indexOf(query, joined, 0) >= 0) {
2092
- if (structuralTrace)
2093
- structuralTrace.selfEvidenceRejected++;
2094
- continue; // query says it itself
2095
- }
2096
- }
2097
- // CONTRADICTION GUARD: a between-region already carrying its own
2098
- // vote must actually recur in this container's bytes — otherwise
2099
- // the container is a different learnt whole that happens to share
2100
- // ra/rb, and letting it stand in for the gap would silently
2101
- // override evidence the query itself already resolved there.
2102
- if (between.some((bi) => indexOf(bytes, query.subarray(regions[bi].start, regions[bi].end), 0) < 0)) {
2103
- if (structuralTrace)
2104
- structuralTrace.contradictionRejected++;
2105
- continue;
2106
- }
2107
- if (structuralTrace)
2108
- structuralTrace.passedGuards++;
2109
- let cov = left.length + right.length;
2110
- const extras = [];
2111
- for (const ei of cand) {
2112
- if (ei === cand[a] || ei === cand[b] || consumed.has(ei))
2113
- continue;
2114
- const e = regions[ei];
2115
- if (overlapsSpan(e, ra) || overlapsSpan(e, rb))
2116
- continue;
2117
- const eb = query.subarray(e.start, e.end);
2118
- if (indexOf(bytes, eb, 0) >= 0) {
2119
- extras.push(ei);
2120
- cov += eb.length;
2121
- }
2122
- }
2123
- if (cov > bestCov ||
2124
- (cov === bestCov && best !== null &&
2125
- (c.interior.length < best.interior.length ||
2126
- (c.interior.length === best.interior.length && c.id < best.id)))) {
2127
- best = c;
2128
- bestExtras = extras;
2129
- bestCov = cov;
2130
- }
2131
- }
2132
- if (best === null) {
2133
- // every container was self-evidence / contradiction — outcome
2134
- // stays "all-rejected".
2135
- pushProbe("structural-rejected");
2136
- continue;
2137
- }
2138
- const r = edgeAncestors(ctx, best.id, N, reachMemo);
2139
- if (r.saturated || r.roots.length === 0) {
2140
- if (structuralTrace) {
2141
- structuralTrace.outcome = r.saturated ? "saturated" : "no-roots";
2142
- }
2143
- pushProbe("structural-rejected");
2144
- continue;
2145
- }
2146
- const df = Math.log(N / Math.max(1, r.contextsReached));
2147
- if (df <= 0) {
2148
- if (structuralTrace)
2149
- structuralTrace.outcome = "nonpositive-idf";
2150
- pushProbe("structural-rejected");
2151
- continue;
2152
- }
2153
- if (structuralTrace) {
2154
- structuralTrace.outcome = "accepted";
2155
- structuralTrace.selectedNode = best.id;
2156
- }
2157
- reach = r;
2158
- idf = df;
2159
- // Confidence used by voting (spec §13): exact junction = 1;
2160
- // single/double-synonym = the sibling(s)' score(s), carried on the
2161
- // SynonymJunction the ladder selected.
2162
- confidence = "confidence" in best ? best.confidence : 1;
2163
- }
2164
- // MUTUAL-EXPLANATION WEIGHT — the same formula for every tier, with
2165
- // `confidence` collapsed to certainty (1) for exact evidence: under
2166
- // that collapse this is byte-for-byte the old exact-only formula
2167
- // (min(1,ratio)·min(1,1/ratio)). For structural-resonance,
2168
- // `confidence` is already annScore·semanticConfidence — never
2169
- // multiplied a second time.
2170
- const lenR = Math.max(1, bestCov);
2171
- const ratio = Math.sqrt(Math.max(1, ctx.store.contentLen(best.id, lenR * ctx.store.D)) / lenR);
2172
- const mutual = Math.min(1, confidence * ratio) *
2173
- Math.min(1, confidence / ratio);
2174
- const w = (mutual * idf) / reach.roots.length;
2175
- let spanStart = ra.start;
2176
- let spanEnd = rb.end;
2177
- for (const ei of bestExtras) {
2178
- spanStart = Math.min(spanStart, regions[ei].start);
2179
- spanEnd = Math.max(spanEnd, regions[ei].end);
2180
- }
2181
- // CONSUMPTION IS FOR CONTAINER-BACKED EVIDENCE ONLY. Consuming a
2182
- // candidate says "its evidence is already composed at full joint
2183
- // strength, re-pairing it would vote the same container twice" — a
2184
- // claim only a real container can make. A structural-resonance pick
2185
- // has none (see above: it is NOT a Junction), so consuming its
2186
- // endpoints locks up candidates on the strength of an ANN guess and
2187
- // stops genuine evidence from ever composing them. Measured: on
2188
- // `greet reply-greet then red then circle` the pair
2189
- // `reply-greet` ▸ `red` resonated to `red square` and consumed `red`,
2190
- // after which `red` ▸ `circle` was never probed and the exact junction
2191
- // `red circle` — a stored whole, sitting right there — went unfound.
2192
- // This is spec §15's asymmetry (only exact DAG evidence may explain
2193
- // ordinary votes away) applied to the other way a tier can silence
2194
- // evidence. Both votes now stand and pooling decides between them,
2195
- // which is what the mechanism market is for.
2196
- if (structuralPick === null) {
2197
- consumed.add(cand[a]);
2198
- consumed.add(cand[b]);
2199
- for (const ei of bestExtras)
2200
- consumed.add(ei);
2201
- }
2202
- // EXPLAINING AWAY — see the block comment above the function. Byte
2203
- // containment in the joint container is the relatedness test (the
2204
- // vote's bytes are literally part of the learnt whole), and FULL root
2205
- // disjointness is the disagreement test: a vote sharing even one root
2206
- // with the junction corroborates it and keeps its say elsewhere.
2207
- // Counted BEFORE pushing the junction's own vote below: each ORIGINAL
2208
- // region this ascent explains away is evidence the junction speaks
2209
- // for, not evidence lost — `absorbed` (RegionVote's breadth-accounting
2210
- // field) must credit the junction with all of it, not just the ONE
2211
- // pooled axiom it collapses to.
2212
- // Only EXACT DAG evidence may explain away ordinary votes (spec §15).
2213
- // Single-synonym, double-synonym, and structural-resonance may ADD
2214
- // supporting evidence but never remove it: their evidence is itself
2215
- // approximate (a sibling substitution, or an ANN guess), so treating
2216
- // their byte-containment the way exact containment is treated would
2217
- // let an approximation override a genuine, independently-voted region.
2218
- let explainedAway = 0;
2219
- // Exact set of ORIGINAL region indices this junction explained away —
2220
- // recorded live as `superseded.add` fires (spec §3's explicit rule:
2221
- // never inferred from `absorbed` afterward).
2222
- const explainedAwayIndices = [];
2223
- if (tier === "exact") {
2224
- const containerBytes = cachedRead(ctx, cache, best.id, cap);
2225
- const jointRoots = new Set(reach.roots);
2226
- for (const rv of rvs.votes) {
2227
- if (rv.roots.some((r) => jointRoots.has(r)))
2228
- continue;
2229
- const bytes = query.subarray(rv.start, rv.end);
2230
- if (indexOf(containerBytes, bytes, 0) >= 0 && !superseded.has(rv)) {
2231
- superseded.add(rv);
2232
- explainedAway++;
2233
- if (td) {
2234
- const idx = regions.findIndex((r) => r.start === rv.start && r.end === rv.end);
2235
- if (idx >= 0)
2236
- explainedAwayIndices.push(idx);
2237
- }
2238
- }
2239
- }
2240
- }
2241
- // COMPOSING TWO SPLIT FORMS DOES NOT WEAVE A POINT OF ATTENTION.
2242
- // Region.corroborating marks a form the query's own cut SPLIT and
2243
- // collectRegions recovered by lookup; poolVotes and commitVotes keep
2244
- // such evidence out of the breadth ratio and out of the root cut's
2245
- // distribution. This path bypassed both: a junction vote is minted
2246
- // fresh here and carried nothing, so evidence the query never wove
2247
- // re-entered the root election as a first-class anchor.
2248
- //
2249
- // Measured over the suite: 130 accepted junctions, 44 standing on at
2250
- // least one corroborating region and 12 standing on NOTHING ELSE (both
2251
- // endpoints corroborating, all structural-resonance tier). Those 12
2252
- // are precisely the leak — the query wove neither endpoint.
2253
- //
2254
- // The flag is inherited only when EVERY part is corroborating. One
2255
- // genuine fold region among the parts means the query did point here,
2256
- // and the junction anchors on it; that also preserves the case
2257
- // Region.corroborating's doc calls out as REFUTED to bar (the correct
2258
- // log record reachable only through a split form still grounds, because
2259
- // it grounds as evidence for an anchor, not as a topic of its own).
2260
- // Safe against the explaining-away accounting because that is EXACT
2261
- // tier only (spec §15) and an all-corroborating junction has no exact
2262
- // ordinary vote to absorb.
2263
- const jointCorroborating = [cand[a], cand[b], ...bestExtras]
2264
- .every((ri) => regions[ri].corroborating === true);
2265
- out.push({
2266
- start: spanStart,
2267
- end: spanEnd,
2268
- canonicalFailed: false, // content-addressed: never saturation-masked
2269
- roots: reach.roots,
2270
- w,
2271
- wFocus: w,
2272
- absorbed: 1 + explainedAway,
2273
- ...(jointCorroborating ? { corroborating: true } : {}),
2274
- // The places this junction actually stands on — its two endpoints and
2275
- // any N-ary extras, NOT the merged span [spanStart, spanEnd], which
2276
- // swallows the gap and reads as one neighbourhood. See
2277
- // RegionVote.parts.
2278
- parts: [cand[a], cand[b], ...bestExtras]
2279
- .map((ri) => [
2280
- regions[ri].start,
2281
- regions[ri].end,
2282
- ])
2283
- .sort((x, y) => x[0] - y[0]),
2284
- });
2285
- pushProbe("accepted");
2286
- if (td) {
2287
- td.crossRegionJunctionVotes.push({
2288
- container: best.id,
2289
- span: [spanStart, spanEnd],
2290
- roots: [...reach.roots],
2291
- sourceRegionIndices: [cand[a], cand[b], ...bestExtras],
2292
- explainedAwayRegionIndices: explainedAwayIndices,
2293
- absorbed: 1 + explainedAway,
2294
- tier,
2295
- probe: td.crossRegionProbes.length - 1,
2296
- confidence,
2297
- evidenceBytes: bestCov,
2298
- mutualWeight: mutual,
2299
- voteWeightPerRoot: w,
2300
- });
2301
- }
2302
- const label = [cand[a], cand[b], ...bestExtras]
2303
- .sort((x, y) => regions[x].start - regions[y].start)
2304
- .map((ri) => dec(query.subarray(regions[ri].start, regions[ri].end)))
2305
- .join(" ▸ ");
2306
- const tierNote = tier === "exact"
2307
- ? `junction node ${best.id}` +
2308
- (best.interior.length === 0
2309
- ? " (adjacent)"
2310
- : ` (interior "${dec(best.interior)}")`) +
2311
- ", by content-addressed ascent"
2312
- : tier === "structural-resonance"
2313
- ? `structurally-composed ANN proposal, node ${best.id} — the query ` +
2314
- `structurally composed the endpoint regions, the real middle-` +
2315
- `query structure, and the selected halo-sibling endpoint ` +
2316
- `direction(s) (variant ${structuralPick.proposal.variant}, ` +
2317
- `annScore ${structuralPick.proposal.annScore.toFixed(3)} × ` +
2318
- `semanticConfidence ${structuralPick.proposal.semanticConfidence.toFixed(3)} = effectiveScore ${structuralPick.proposal.effectiveScore.toFixed(3)}); it did not concatenate endpoint bytes or rewrite the query`
2319
- : `${tier} junction node ${best.id}` +
2320
- (best.interior.length === 0
2321
- ? " (adjacent)"
2322
- : ` (interior "${dec(best.interior)}")`) +
2323
- `, by halo-sibling DAG ascent (confidence ${confidence.toFixed(3)})`;
2324
- ctx.trace?.step("crossRegion", [{ text: label, role: "pair" }], reach.roots.map((r) => ({
2325
- text: dec(read(ctx, r)).slice(0, 60),
2326
- node: r,
2327
- role: "joint-context",
2328
- })), `${label} → ${tierNote} → ${reach.roots.length} context(s)` +
2329
- (superseded.size > 0
2330
- ? `; ${superseded.size} aliasing vote(s) explained away`
2331
- : ""));
2332
- break; // ra is consumed — move to the next unconsumed candidate
2333
- }
2334
- }
2335
- if (td)
2336
- td.supersededOrdinaryVotes = superseded.size;
2337
- if (td?.crossRegionSummary) {
2338
- td.crossRegionSummary.stopReason = probes >= k
2339
- ? "probe-limit"
2340
- : "pairs-exhausted";
2341
- }
2342
- return { votes: out, superseded };
2343
- }
2344
- /** Emit the "climbConsensus" step — the human-readable note this always
2345
- * produced, now paired (when `ctx.trace` and `cfg` are both present) with
2346
- * the structured {@link ClimbConsensusData} payload on the SAME step's
2347
- * `data` field. Every exit of {@link computeAttention} funnels through
2348
- * here, so instrumentation and the existing rationale text can never drift
2349
- * apart — see the instrumentation spec's §9 "every exit path". */
2350
- export function traceAttention(ctx, regions, regionVoter, roots, steps = [], td, cfg, ranked = roots) {
2351
- if (!ctx.trace)
2352
- return;
2353
- const voters = [];
2354
- for (let i = 0; i < regions.length; i++) {
2355
- const rv = regionVoter[i];
2356
- if (rv == null)
2357
- continue;
2358
- const item = rNode(ctx, rv.id, "sub-region", rv.score);
2359
- item.text = `${item.text} (df-w ${rv.w.toFixed(2)})`;
2360
- voters.push(item);
2361
- }
2362
- const t = ctx.trace.enter("climbConsensus", voters);
2363
- // The pooled-evidence decision, one DerivationStep per anchor — the same
2364
- // shape {@link GraphSearch}'s own cover steps take (see traceDerivation).
2365
- if (steps.length > 0)
2366
- traceDerivation(ctx, steps);
2367
- const data = (td && cfg)
2368
- ? {
2369
- version: 1,
2370
- cache: { hit: false, detailAvailable: true },
2371
- config: {
2372
- annK: cfg.k,
2373
- crossRegionProbeLimit: cfg.k,
2374
- mode: cfg.mode,
2375
- ...(cfg.N !== undefined ? { corpusN: cfg.N } : {}),
2376
- dimension: ctx.store.D,
2377
- ...(cfg.N !== undefined ? { hubBound: hubBound(ctx) } : {}),
2378
- estimatorNoise: estimatorNoise(ctx.store.D),
2379
- ...(cfg.naturalBreak !== undefined
2380
- ? { naturalBreak: cfg.naturalBreak }
2381
- : {}),
2382
- ...(cfg.consensusFloor !== undefined
2383
- ? { consensusFloor: cfg.consensusFloor }
2384
- : {}),
2385
- },
2386
- candidates: {
2387
- perceived: cfg.perceivedCount,
2388
- recognised: cfg.totalRegions - cfg.perceivedCount,
2389
- total: cfg.totalRegions,
2390
- },
2391
- ...(td.regions.length > 0 ? { regions: td.regions } : {}),
2392
- ...(cfg.reachMemo ? { reaches: serialiseReaches(cfg.reachMemo) } : {}),
2393
- ...(td.crossRegionSummary
2394
- ? {
2395
- crossRegion: {
2396
- eligibleRegions: td.crossRegionSummary.eligibleRegions,
2397
- maximalRegions: td.crossRegionSummary.maximalRegions,
2398
- probeLimit: td.crossRegionSummary.probeLimit,
2399
- probesAttempted: td.crossRegionSummary.probesAttempted,
2400
- junctionVotes: td.crossRegionJunctionVotes,
2401
- supersededOrdinaryVotes: td.supersededOrdinaryVotes,
2402
- probes: td.crossRegionProbes,
2403
- stopReason: td.crossRegionSummary.stopReason ?? "pairs-exhausted",
2404
- },
2405
- }
2406
- : {}),
2407
- ...(td.saturation ? { saturation: td.saturation } : {}),
2408
- ...(td.pooling ? { pooling: td.pooling } : {}),
2409
- ...(td.anchors.length > 0 ? { anchors: td.anchors } : {}),
2410
- result: { roots: [...roots], ranked: [...ranked] },
2411
- }
2412
- : undefined;
2413
- t.done(roots.map((r) => rNode(ctx, r.anchor, "anchor", r.vote)), roots.length === 0
2414
- ? `${regions.length} sub-regions climbed the DAG, but none agreed on a context`
2415
- : roots.length === 1
2416
- ? `${voters.length} of ${regions.length} sub-regions voted; IDF-weighted consensus picked one context (vote ${roots[0].vote.toFixed(2)})`
2417
- : `${voters.length} of ${regions.length} sub-regions voted; consensus ordered ${roots.length} INDEPENDENT points of attention (votes ${roots.map((r) => r.vote.toFixed(2)).join(", ")})`, data);
2418
- }