@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,535 +0,0 @@
1
- // frame-filler.ts — compositional substitution grounding (recall's last tier
2
- // before refusal, after the substitution bridge).
3
- //
4
- // THE GAP (analyze_training.ts section G): `What is the capital of the country
5
- // where the Eiffel Tower is?` returns silence, while the answer sits ONE edge
6
- // away — `resolve("What is the capital of France?")` is a trained form with a
7
- // continuation. The query differs from it by a single contiguous span: a
8
- // DEFINITE DESCRIPTION (`the country where the Eiffel Tower is`, 37 B) stands
9
- // where a proper noun (`France`, 6 B) stands in the trained question.
10
- //
11
- // Every existing tier correctly declines. Recall tier 0b needs the constituent
12
- // to be an edge SOURCE (`Eiffel Tower` is out=0, in=1). Every gist tier is
13
- // blind here: cos(query, the trained form) = 0.0076, and `capital of Spain`
14
- // scores 0.0174 — HIGHER than the correct one — so the target is not even in the
15
- // ANN top-24. The substitution bridge finds the alignment and then refuses it on
16
- // RAW BALANCE, `dominates(6, 37)`, which it must: a short span standing for a
17
- // long one is exactly how `France` → `Spain si(nce)` once voiced a wrong fact.
18
- //
19
- // THE REFRAMING. The bridge asks whether the two spans are SIMILAR. A definite
20
- // description and the noun it denotes are not similar, they are CO-REFERENTIAL,
21
- // so no similarity threshold can separate this case from that fabrication. So
22
- // this tier does not try. Instead:
23
- //
24
- // We invent a lookup KEY, never an answer.
25
- //
26
- // Build the query with the candidate filler in the description's place and
27
- // require the STORE ITSELF to already hold that key, byte-exactly, by content
28
- // address. The answer is then the trained continuation of a form the store
29
- // verifiably has — the same grounding tier 0 performs — so nothing is
30
- // synthesised. What is constructed is only a lookup key, and a key the store
31
- // does not hold is discarded.
32
- //
33
- // FOUR GUARDS, each falsified into existence on the 15.7M-node store. Dropping
34
- // any one of them reintroduces a wrong answer or outright fabrication:
35
- //
36
- // 1. The evidence hit must literally contain the description's RAREST unit.
37
- // Pooling fillers from every ranked hit gives the twohop query 9 resolving
38
- // keys, dominated by `What is the capital of India?` → "New Delhi.". And
39
- // qualifying on any SHARED unit rather than the rarest gives
40
- // `Can you write a short poem?` exactly one key,
41
- // `Can you write hello world in C?` — a confident wrong answer earned on
42
- // the scaffolding unit "write".
43
- // 2. The frame must be NON-EMPTY: the description is a proper sub-span.
44
- // Otherwise two of the twohop keys replace the WHOLE query (`Immanuel
45
- // Kant`, `Africa`), which is not substitution at all.
46
- // 3. The key must RESOLVE byte-exactly and lead somewhere.
47
- // 4. Exactly ONE stored form may survive. `What is the capital of Zamunda?`
48
- // produces 24 resolving keys in the weaker variants (Chile, India, Japan,
49
- // Italy …) — fabrication, refused here by ambiguity. This is the same
50
- // discipline tier 0b applies ("two distinct maximal arguments mean the
51
- // query asks about neither alone").
52
- //
53
- // A NOTE ON WHY RESOLUTION ALONE IS NOT THE SAFETY ARGUMENT. Holding the frame
54
- // fixed and varying only the filler makes byte-exact resolution look like a
55
- // perfect filter — every wrong filler tried returned null. That is misleading:
56
- // when the DESCRIPTION is searched too, 95,836 candidate keys were tried for the
57
- // twohop query and 9 resolved. Resolution is necessary, never sufficient; the
58
- // guards above are what make it sound.
59
- //
60
- // COST — nothing on any answering path (this runs only where the alternative was
61
- // silence), and no new retrieval: the ranked hits are the ones recall already
62
- // computed. On the refusal path, measured over 19 queries (every currently-empty
63
- // battery probe, all three silence probes, three dialogue turns, and a 125-byte
64
- // worst case): mean 22.7 ms, worst 452 probes / 102 ms, and 10 of the 19 need
65
- // ZERO probes because guard 1 exits first. Two things keep it there and both are
66
- // load-bearing, not optimisations:
67
- //
68
- // • fillers are MAXIMAL absent runs, not every sub-span of a hit (8,020 probes
69
- // → 452). The twohop win survives because a sub-quantum unit (< W)
70
- // terminates a run: in `The most well-known landmark in France is the Eiffel
71
- // Tower.`, `in` breaks the run, so `France` IS itself a maximal run.
72
- // • rarity is memoised per response. On the 125-byte query 3,882 rarity reads
73
- // collapse to 10 lookups, and that query drops from 309 ms to 22 ms.
74
- //
75
- // The probe budget is `hubBound` (√N), the same breadth every other bounded
76
- // search here self-limits to. Exhausting it REFUSES rather than answers:
77
- // truncating the search would leave uniqueness (guard 4) unestablished, and an
78
- // unestablished uniqueness claim is exactly the ambiguity the guard exists to
79
- // catch.
80
- import { indexOf } from "../bytes.js";
81
- import { leafIdRun } from "./canonical.js";
82
- import { hubBound } from "./traverse.js";
83
- import { alignRuns } from "./match.js";
84
- import { dominates } from "../geometry.js";
85
- import { foldTree, perceive } from "./primitives.js";
86
- import { rItem } from "./trace.js";
87
- /** A stable memo key for a byte span — latin1, so no UTF-8 validation and no
88
- * allocation beyond the string itself. */
89
- function spanKey(bytes, from, to) {
90
- let s = "";
91
- for (let i = from; i < to; i++)
92
- s += String.fromCharCode(bytes[i]);
93
- return s;
94
- }
95
- /** Find the query's own most discriminative unit and the trained contexts that
96
- * hold it, then try the store for the query with a candidate filler in the
97
- * described span's place. Returns the sole surviving stored form, or null. */
98
- export function frameFillerSubstitution(ctx, query, ranked) {
99
- const W = ctx.space.maxGroup;
100
- const _t0 = Date.now();
101
- const t = ctx.trace?.enter("frameFiller", [rItem(query, "query")]);
102
- const done = (hit, note, data) => {
103
- t?.done(hit === null ? [] : [rItem(hit.filler, "filler", hit.id)], note, data);
104
- return hit;
105
- };
106
- // ── CONSTITUENCY BY AGREEMENT ─────────────────────────────────────────
107
- // Read the candidate contexts once, bounded to phrase scale (a stored span
108
- // can run to hundreds of kilobytes, and a form an order of magnitude longer
109
- // than the question is not a candidate for BEING it with one span replaced).
110
- const capBytes = query.length * W;
111
- const hitMemo = new Map();
112
- const hitBytes = (sid) => {
113
- const seen = hitMemo.get(sid);
114
- if (seen !== undefined)
115
- return seen;
116
- const b = ctx.store.bytesPrefix(sid, capBytes + 1);
117
- const v = b.length === 0 || b.length > capBytes ? null : b;
118
- hitMemo.set(sid, v);
119
- return v;
120
- };
121
- const contexts = [];
122
- for (const sid of ranked) {
123
- const h = hitBytes(sid);
124
- if (h !== null)
125
- contexts.push(h);
126
- }
127
- /** How many of `others` an alignment covers each byte of `subject` with —
128
- * the same per-byte depth the weave accumulates, over the same literal
129
- * alignment. */
130
- const depthOver = (subject, others) => {
131
- const depth = new Uint16Array(subject.length);
132
- for (const other of others) {
133
- if (other === subject)
134
- continue;
135
- for (const r of alignRuns(ctx, subject, other)) {
136
- for (let i = r.qs; i < r.qe && i < depth.length; i++)
137
- depth[i]++;
138
- }
139
- }
140
- return depth;
141
- };
142
- /** The maximal runs of `subject` that the majority does NOT share — its
143
- * content, as opposed to the frame. This is the constituent notion: a span
144
- * no character class produced, only agreement. */
145
- const contentRuns = (subject, others, from = 0, to = subject.length) => {
146
- // A single exemplar agrees with nothing, so nothing can be called frame
147
- // and no constituent is established — the honest reading is "none".
148
- if (others.length < 2)
149
- return [];
150
- const depth = depthOver(subject, others);
151
- const out = [];
152
- let start = -1;
153
- for (let i = from; i < to; i++) {
154
- const frame = dominates(depth[i], others.length);
155
- if (!frame) {
156
- if (start < 0)
157
- start = i;
158
- }
159
- else if (start >= 0) {
160
- out.push([start, i]);
161
- start = -1;
162
- }
163
- }
164
- if (start >= 0)
165
- out.push([start, to]);
166
- return out;
167
- };
168
- // THE FRAME COHORT. A frame is only established among exemplars that are
169
- // instances of the SAME frame — "more than half the aligned structures share
170
- // it" says nothing when the structures share nothing to begin with. Two
171
- // readings were measured and BOTH fail:
172
- //
173
- // • ALL resonance candidates. They are merely near in gist, so a majority
174
- // never forms, every byte reads as content, any span becomes a filler —
175
- // and it does not merely fail to answer, it FABRICATES ("Tell me the name
176
- // of the biggest planet orbiting our sun." grounded a list of animals).
177
- // • candidates holding the query's discriminative content. These are
178
- // exemplars about the same THING, not instances of the same FRAME: the
179
- // seven holding "Eiffel" share `" the Eiffel Tower"` and nothing else, so
180
- // a whole clause reads as content and no constituent is isolated.
181
- //
182
- // The cohort of a subject is its STRUCTURAL NEIGHBOURS — the candidates whose
183
- // alignment covers the most of it — because instances of one frame are
184
- // exactly the forms that share that frame's bytes. Two weaker readings were
185
- // measured and both fail: ALL candidates share nothing, so a majority never
186
- // forms, every byte reads as content and the tier FABRICATES; candidates
187
- // holding the query's rarest content are exemplars about the same THING, not
188
- // the same FRAME (the seven holding "Eiffel" share `" the Eiffel Tower"` and
189
- // nothing else), so no constituent is isolated.
190
- //
191
- // THE CUT is half-dominance against the BEST neighbour, not against the
192
- // subject's length. Coverage is bounded by how much frame two forms can
193
- // share at all — measured, the best neighbour covered 23 of 59 bytes — so
194
- // `dominates(n, subject.length)` can never fire and the cohort is always
195
- // empty. Read against the best coverage the profile actually offers, the
196
- // same convention becomes scale-free and needs no constant: a form sharing
197
- // more than half of what the closest instance shares is another instance.
198
- const coverageOf = (subject, other, keepEdges = null) => {
199
- const seen = new Uint8Array(subject.length);
200
- for (const r of alignRuns(ctx, subject, other)) {
201
- if (keepEdges !== null) {
202
- keepEdges.add(r.qs);
203
- keepEdges.add(r.qe);
204
- }
205
- for (let i = r.qs; i < r.qe && i < seen.length; i++)
206
- seen[i] = 1;
207
- }
208
- let n = 0;
209
- for (const x of seen)
210
- n += x;
211
- return n;
212
- };
213
- // WHERE ANY EXEMPLAR'S SHARED MATERIAL STARTS OR STOPS. Collected over EVERY
214
- // candidate, not just the cohort: the cut decides whose AGREEMENT establishes
215
- // the frame, which is a different question from where a boundary EXISTS. One
216
- // exemplar ending a run at an offset is already evidence of an edge there,
217
- // however unrelated it is otherwise — measured, drawing edges from the cohort
218
- // alone loses the boundary between `"is"` and `"?"` (2 candidates of 563
219
- // attest it, 0 of 131 in the cohort), and without it the two-hop description
220
- // cannot be expressed at all.
221
- const edgesMemo = new Map();
222
- const cohortMemo = new Map();
223
- const cohortOf = (subject) => {
224
- const seen = cohortMemo.get(subject);
225
- if (seen !== undefined)
226
- return seen;
227
- const eset = new Set([0, subject.length]);
228
- edgesMemo.set(subject, eset);
229
- let best = 0;
230
- const scored = [];
231
- for (const c of contexts) {
232
- if (c === subject)
233
- continue;
234
- const n = coverageOf(subject, c, eset);
235
- if (n < W)
236
- continue;
237
- if (n > best)
238
- best = n;
239
- scored.push({ c, n });
240
- }
241
- const out = scored.filter((x) => dominates(x.n, best)).map((x) => x.c);
242
- cohortMemo.set(subject, out);
243
- return out;
244
- };
245
- /** Split each run at the boundaries other exemplars attest for `subject` — a
246
- * run is a stretch the cohort does not share, not itself a constituent, so
247
- * taking it whole asks the evidence for a span no exemplar holds. */
248
- const cutAtEdges = (subject, runs) => {
249
- const eset = edgesMemo.get(subject);
250
- if (eset === undefined)
251
- return runs;
252
- const inner = [...eset].sort((a, b) => a - b);
253
- const out = [];
254
- for (const [rs, re] of runs) {
255
- let prev = rs;
256
- for (const o of inner) {
257
- if (o <= rs || o >= re)
258
- continue;
259
- if (o - prev >= W)
260
- out.push([prev, o]);
261
- prev = o;
262
- }
263
- if (re - prev >= W)
264
- out.push([prev, re]);
265
- out.push([rs, re]);
266
- }
267
- return out;
268
- };
269
- const queryContent = contentRuns(query, cohortOf(query));
270
- // Corpus rarity of a unit, by how many trained forms contain its first
271
- // window — the same container-count reading the bridge's anchor picking uses.
272
- // Memoised per call: the same units recur across every candidate description.
273
- const rarityMemo = new Map();
274
- let rarityReads = 0;
275
- const rarityOf = (from, to) => {
276
- if (to - from < W)
277
- return Infinity;
278
- const key = spanKey(query, from, to);
279
- const seen = rarityMemo.get(key);
280
- if (seen !== undefined)
281
- return seen;
282
- rarityReads++;
283
- let value = Infinity;
284
- const ids = leafIdRun(ctx, query, from, from + W);
285
- if (ids !== null) {
286
- const wid = ctx.store.findBranch(ids);
287
- if (wid !== null)
288
- value = ctx.store.containers(wid).length;
289
- }
290
- rarityMemo.set(key, value);
291
- return value;
292
- };
293
- /** The most discriminative unit of `[from, to)`, as its span, or null when it
294
- * has none. Rarest first; at EQUAL rarity the LONGER unit wins, because the
295
- * longer form carries more content at the same corpus frequency. The
296
- * tie-break is load-bearing on a small corpus, where every unit's container
297
- * count collapses to 1 and first-wins would pick the query's opening unit
298
- * ("What") over its subject ("Eiffel") — the subject is what a description
299
- * must be about. On a large corpus the counts separate on their own (54 vs
300
- * 1,586 for exactly that pair) and the tie-break never engages. */
301
- const rarestUnit = (from, to) => {
302
- let best = null;
303
- let bestRarity = Infinity;
304
- let bestAttested = 0;
305
- let bestLen = 0;
306
- // A content run is a stretch the cohort does not share; it is not itself a
307
- // constituent, and taking it whole asks the evidence for a span no exemplar
308
- // holds (measured: `" Eiffel Tower is?"` qualified NO candidate, so the tier
309
- // never probed). Cut each run at the boundaries other exemplars attest —
310
- // the same edge set the descriptions are enumerated over — so the unit is a
311
- // span the corpus has actually seen begin and end.
312
- //
313
- // A unit may span ANY two attested edges, not just adjacent ones. Slicing
314
- // only between consecutive edges makes the unit set depend on how DENSE the
315
- // evidence is rather than on what it says: measured, at k = 24 the query
316
- // carries 17 edges and `"Eiffel Tower"` is one slice (elected, attested),
317
- // while at k = 571 it carries 55 and every consecutive slice is 1-3 bytes —
318
- // all under the constituent bar — leaving only the whole unattested run and
319
- // electing nothing at all. More evidence made the tier blinder. Taking
320
- // every edge-bounded sub-span removes that dependence: the corpus decides
321
- // which spans exist, never how finely it happened to mark them.
322
- const pieces = [];
323
- for (const [cs0, ce0] of queryContent) {
324
- const inner = bs.filter((o) => o > cs0 && o < ce0);
325
- let prev = cs0;
326
- for (const o of [...inner, ce0]) {
327
- pieces.push([prev, o]);
328
- prev = o;
329
- }
330
- pieces.push([cs0, ce0]);
331
- }
332
- for (const [cs0, ce0] of pieces) {
333
- const s = Math.max(cs0, from);
334
- const e = Math.min(ce0, to);
335
- // ATTESTED, or it is not evidence. Rarity is read over the span's FIRST
336
- // window, so every longer span sharing that window scores identically —
337
- // and the longer-wins tie-break below then elects the longest of them,
338
- // which is a claim about bytes the measurement never looked at. Measured
339
- // live: the elected unit was `"Eiffel Tower is?"`, held by 0 of the 24
340
- // candidates, so guard 1 rejected every one and the tier never probed
341
- // (`descs=14, qualified=0, probes=0`). Requiring the unit to occur in the
342
- // evidence is not an extra gate — guard 1 demands exactly this — it just
343
- // has to hold at ELECTION time, or election spends itself on a span no
344
- // candidate can qualify.
345
- let attested = 0;
346
- for (const c of contexts) {
347
- if (indexOf(c, query.subarray(s, e), 0) >= 0)
348
- attested++;
349
- }
350
- if (attested === 0)
351
- continue;
352
- // THE CONSTITUENT BAR — two quanta, the same reading argument binding
353
- // holds its constituents to. Content runs are not units of a modality's
354
- // making, so a run may be as short as one window, and a single window is
355
- // too weak to say what a description is ABOUT: measured, the W-byte
356
- // fragment `phot` qualified `What is photosynthesis?` against an
357
- // unrelated "photo-sharing app" and fabricated an answer.
358
- if (e - s < 2 * W)
359
- continue;
360
- const r = rarityOf(s, e);
361
- if (r === Infinity)
362
- continue;
363
- // Rarity is read over the FIRST window, so spans sharing it are
364
- // indistinguishable to the measurement; among them the only measured
365
- // difference is how much evidence actually holds the span. Preferring the
366
- // LONGER one asserts bytes never looked at — measured, it elected
367
- // `"Eiffel Tower "` (trailing space, 1 context) over `"Eiffel Tower"`
368
- // (2 contexts), so the one candidate that could complete the description
369
- // never qualified. Length breaks only a genuine tie in both.
370
- if (r < bestRarity ||
371
- (r === bestRarity &&
372
- (attested > bestAttested ||
373
- (attested === bestAttested && e - s > bestLen)))) {
374
- bestRarity = r;
375
- bestAttested = attested;
376
- bestLen = e - s;
377
- best = [s, e];
378
- }
379
- }
380
- return best;
381
- };
382
- const qEdges = edgesMemo.get(query) ?? new Set([0, query.length]);
383
- for (const [cs0, ce0] of queryContent) {
384
- qEdges.add(cs0);
385
- qEdges.add(ce0);
386
- }
387
- const bs = [...qEdges].sort((a, b) => a - b);
388
- // The query's own discriminative content — every candidate description must
389
- // contain it, or the substitution is not about what the query is asking.
390
- const queryRare = rarestUnit(0, query.length);
391
- if (queryRare === null) {
392
- return done(null, "no corpus-attested unit in the query — nothing to describe", {
393
- contexts: contexts.length,
394
- qc: queryContent.length,
395
- edges: bs.length,
396
- runs: queryContent.map(([a, b]) => spanKey(query, a, b)),
397
- });
398
- }
399
- let probes = 0;
400
- let descs = 0, qualified = 0, fillers = 0;
401
- const chosen = new Map();
402
- const fillerSeen = new Set();
403
- const budget = hubBound(ctx);
404
- // resolved form id -> the description span and filler that reached it
405
- const found = new Map();
406
- // Candidate description edges: every offset some exemplar's shared material
407
- // begins or ends at, plus the query's own extremes.
408
- for (let i = 0; i < bs.length; i++) {
409
- for (let j = i + 1; j < bs.length; j++) {
410
- const [dStart, dEnd] = [bs[i], bs[j]];
411
- // GUARD 2 — the frame must be non-empty: replacing the whole query is
412
- // not substitution.
413
- if (dStart === 0 && dEnd === query.length)
414
- continue;
415
- if (dEnd - dStart < W)
416
- continue;
417
- // The description must carry the query's discriminative content.
418
- if (dStart > queryRare[0] || dEnd < queryRare[1])
419
- continue;
420
- const dRare = rarestUnit(dStart, dEnd);
421
- if (dRare === null)
422
- continue;
423
- descs++;
424
- {
425
- const u = spanKey(query, dRare[0], dRare[1]);
426
- chosen.set(u, (chosen.get(u) ?? 0) + 1);
427
- }
428
- const rareUnit = query.subarray(dRare[0], dRare[1]);
429
- for (const sid of ranked) {
430
- // PHRASE SCALE — the same bound the bridge puts on a candidate's bytes
431
- // (`capBytes = query.length * W`): a form an order of magnitude longer
432
- // than the question is not a candidate for BEING that question with one
433
- // span replaced. Reading candidates in full instead was measured at
434
- // +650 ms on the winning query, since a stored span can run to hundreds
435
- // of kilobytes.
436
- const hit = hitBytes(sid);
437
- if (hit === null)
438
- continue;
439
- // GUARD 1 — this hit must literally hold the description's rarest unit.
440
- if (indexOf(hit, rareUnit, 0) < 0)
441
- continue;
442
- qualified++;
443
- // Fillers: this hit's CONTENT — the spans its fellow candidates do not
444
- // share. What the exemplars have in common is the frame they are all
445
- // instances of; what is left distinguishes THIS one, and that is the
446
- // constituent standing where the query's description stands.
447
- const runs = cutAtEdges(hit, contentRuns(hit, cohortOf(hit)));
448
- for (const [fs, fe] of runs) {
449
- if (fe - fs < W)
450
- continue;
451
- fillers++;
452
- if (fillerSeen.size < 40)
453
- fillerSeen.add(spanKey(hit, fs, fe));
454
- const filler = hit.subarray(fs, fe);
455
- if (indexOf(query, filler, 0) >= 0)
456
- continue;
457
- if (probes >= budget) {
458
- // Uniqueness cannot be established on a truncated search, and an
459
- // unestablished uniqueness claim is the ambiguity guard 4 exists
460
- // to refuse.
461
- return done(null, `probe budget (${budget}) exhausted — uniqueness unestablished`, {
462
- version: 1,
463
- probes,
464
- rarityReads,
465
- resolved: found.size,
466
- contexts: contexts.length,
467
- edges: bs.length,
468
- qc: queryContent.length,
469
- descs,
470
- qualified,
471
- fillers,
472
- });
473
- }
474
- probes++;
475
- // The KEY: the query with this filler in the described span's place.
476
- const key = new Uint8Array(dStart + filler.length + (query.length - dEnd));
477
- key.set(query.subarray(0, dStart), 0);
478
- key.set(filler, dStart);
479
- key.set(query.subarray(dEnd), dStart + filler.length);
480
- // GUARD 3 — the store must already hold it, and it must lead
481
- // somewhere. EXACT content address only, deliberately not
482
- // resolve(): that falls through to canonResolve on a miss, and a
483
- // constructed key misses by design — 451 of the 452 probes on the
484
- // winning query do — so each miss would pay a canon index query.
485
- // Measured: +650 ms on that query, for a claim WEAKER than the one
486
- // this guard wants. A canon hit would mean the store holds a
487
- // case/width variant of a key we invented; guard 3 asks for the key
488
- // itself.
489
- const id = foldTree(ctx, perceive(ctx, key), 0).node;
490
- if (id === null || !ctx.store.hasNext(id))
491
- continue;
492
- if (!found.has(id)) {
493
- found.set(id, {
494
- id,
495
- described: [dStart, dEnd],
496
- filler: filler.slice(),
497
- });
498
- }
499
- }
500
- }
501
- }
502
- }
503
- const data = {
504
- version: 1,
505
- probes,
506
- rarityReads,
507
- resolved: found.size,
508
- budget,
509
- contexts: contexts.length,
510
- edges: bs.length,
511
- qc: queryContent.length,
512
- descs,
513
- qualified,
514
- fillers,
515
- fillerSeen: [...fillerSeen],
516
- chosen: [...chosen.entries()].map(([u, n]) => {
517
- const b = new Uint8Array(u.length);
518
- for (let i = 0; i < u.length; i++)
519
- b[i] = u.charCodeAt(i);
520
- const inAny = contexts.filter((c) => indexOf(c, b, 0) >= 0).length;
521
- return `${JSON.stringify(u)} x${n} inContexts=${inAny}`;
522
- }),
523
- ms: Date.now() - _t0,
524
- };
525
- // GUARD 4 — exactly one trained form, or the query is ambiguous about its own
526
- // subject and neither is licensed.
527
- if (found.size === 1) {
528
- const hit = [...found.values()][0];
529
- return done(hit, "frame-filler substitution — the store holds this query with a " +
530
- "corroborated filler in the described span's place", data);
531
- }
532
- return done(null, found.size === 0
533
- ? "no filler makes this query a stored form"
534
- : `${found.size} fillers make this query a stored form — ambiguous subject`, data);
535
- }