@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,327 +0,0 @@
1
- // extraction.ts — Extraction (Skill) — Section 4 of the mind.
2
- //
3
- // Given a query and its consensus-ranked anchors, find the first span-shaped
4
- // skill exemplar among the ranked anchors and read the analogous span of the
5
- // query. A skill exemplar is a learnt fact whose context and answer together
6
- // form a span-in-context pattern: the answer is a subsequence of the context
7
- // (or one of its pieces is), and the context is the smallest spanning frame
8
- // that contains it.
9
- import { locate } from "../match.js";
10
- import { concatBytes, indexOf } from "../../bytes.js";
11
- import { decodeText, unexplainedLabel } from "../rationale.js";
12
- import { CONCEPT, STEP } from "../graph-search.js";
13
- import { rItem, rNode, traceFail } from "../trace.js";
14
- // ── Extraction ────────────────────────────────────────────────────────────
15
- /** Find the first span-shaped skill exemplar among the ranked anchors from
16
- * climbAttentionAll and read the analogous span from the query. Returns
17
- * the extracted bytes PLUS the query spans the skill ACCOUNTED FOR — the
18
- * located frames AND any read span BOUNDED by located frames on both
19
- * sides, the elementary evidence think's grounding decider weighs. A
20
- * bounded read is explained: the skill located both its borders in the
21
- * query and emitted exactly what sits between them. An OPEN-ENDED read
22
- * (the exemplar's answer reaches the context's end, so the query is read
23
- * to its own end with no located right border) remains a guess about where
24
- * the span stops — it stays unaccounted, priced by exclusion like the
25
- * cover's bridged bytes. (Accounting frames only — the earlier convention
26
- * — let a CAST juxtaposition that merely echoed the query's exact site
27
- * outweigh a correct bounded extraction: the same span counted as
28
- * explained for one mechanism and not the other, and the asymmetry, not
29
- * the answers' merits, decided the grounding.) Null when no skill
30
- * applies. */
31
- export async function extractBySkill(ctx, query, pre) {
32
- const t = ctx.trace?.enter("extractBySkill", [
33
- rItem(query, "query"),
34
- ]);
35
- const fail = traceFail(t);
36
- // Use climbAttentionAll to get the FULL ranked list, not just the
37
- // roots that cleared commitVotes' significance floor. The floor
38
- // gates further points of attention for fusion, but extraction only
39
- // needs ONE anchor that IS a span-shaped skill exemplar — and on
40
- // some seeds the top-voted anchor is not one (e.g. a concept-merge
41
- // nickname outvotes the painting exemplars on shared substrings,
42
- // while the exemplars' votes fall below the floor). Iterating the
43
- // ranked list instead of just the roots lets extraction reach the
44
- // first painting-exemplar anchor regardless of its floor status.
45
- //
46
- const { ranked } = await pre.attention();
47
- if (ranked.length === 0) {
48
- return fail("no consensus anchor — no skill to apply");
49
- }
50
- // Try ranked anchors IN ORDER until one yields a USABLE extraction — not
51
- // merely a span-shaped exemplar, but one whose extracted span clears the
52
- // same one-river-fold quantum (W) cover.ts's restatedSpan gate already
53
- // treats as the floor below which byte overlap is chance, not evidence.
54
- // isSpanShaped (spanShapedOf) is a deliberately permissive sparse-
55
- // subsequence check — see the section note below — so it accepts exemplars
56
- // whose relation to the query is coincidental gap-matching, not genuine
57
- // structure. Stopping at the FIRST such exemplar let a coincidental match
58
- // early in the ranked list win outright and read out a sub-quantum
59
- // fragment (observed: a 3-byte "Hel" pulled from an unrelated exemplar,
60
- // while a later ranked anchor would have read the query's own "Hello…"
61
- // correctly). Trying further anchors when one produces nothing usable is
62
- // the same idiom this loop already uses for non-exemplars — extended to
63
- // cover a bad extraction, not just a structural non-match.
64
- //
65
- // The retry is bounded at pre.k — the SAME evidence-breadth constant every
66
- // other consumer of a ranked list already self-limits to (resonance, the
67
- // weave, the climb itself; see Precomputed.k's own doc comment) — not the
68
- // full ranked list. locate()'s frame match has an EXACT-byte tier with no
69
- // significance correction of its own (short W-byte frames are cheap to
70
- // match by pure chance), so trying every ranked anchor turns that per-
71
- // anchor chance into a near-certainty over enough attempts: on a pure-
72
- // gibberish query, 170 anchors deep found an unrelated Zulu exemplar whose
73
- // short frame happened to byte-match, producing "xyzzy pl" — a coincidence
74
- // no different in kind from the "RaBitQ estimate overshot the reach bar
75
- // and grounded pure gibberish" failure recall.ts's own significance
76
- // correction exists to prevent (see recallByResonance's reach-threshold
77
- // comment). Bounding the search to the ranked list's own top-k restores
78
- // the "genuinely relevant but not root-significant" exemplars this loop
79
- // was built for, without the unbounded tail's chance collisions.
80
- const W = ctx.space.maxGroup;
81
- const searched = ranked.slice(0, pre.k);
82
- let shapeMisses = 0;
83
- let subQuantum = 0;
84
- for (const cand of searched) {
85
- const exemplar = await pre.spanShapedOf(cand.anchor);
86
- if (!exemplar) {
87
- shapeMisses++;
88
- continue;
89
- }
90
- const built = buildFromExemplar(ctx, query, pre, exemplar);
91
- if (built === null || built.bytes.length < W) {
92
- subQuantum++;
93
- continue;
94
- }
95
- // AN UNANCHORED READ IS NOT AN EXTRACTION. This function's contract (see
96
- // the doc above) is that `accounted` carries "the located frames AND any
97
- // read span BOUNDED by located frames on both sides", while an open-ended
98
- // read "remains a guess about where the span stops — it stays unaccounted".
99
- // EMPTY accounted is the degenerate case of that: NO frame of the exemplar
100
- // was located in the query at all, so nothing ties the bytes just read to
101
- // this question — the skill applied its exemplar's geometry to a query it
102
- // never matched.
103
- //
104
- // The live case (analyze_training.ts F, the battery's ONLY wrong non-silent
105
- // answer): "Which city is France's seat of government?" answered "Which ci"
106
- // — a fragment of the query itself — from the exemplar "What is dll", with
107
- // accounted=[] and pieces=1. isSpanShaped is deliberately permissive (a
108
- // sparse-subsequence check), so it accepts exemplars whose relation to the
109
- // query is coincidental gap-matching; requiring at least one LOCATED frame
110
- // is the structural evidence that permissiveness leaves out.
111
- //
112
- // Scoped to extraction ON PURPOSE. The same test at the pipeline's
113
- // post-grounding density check was tried and REVERTED: `accounted` is passed
114
- // empty BY CONVENTION on recall's own tiers (recall.ts's ground(…, [], …)),
115
- // so a density veto there refused six legitimate reverse-recall groundings.
116
- // Here the field is this mechanism's own output and carries its documented
117
- // meaning, so the test is sound exactly where the convention does not reach.
118
- if (built.accounted.length === 0) {
119
- subQuantum++;
120
- continue;
121
- }
122
- if (shapeMisses > 0 || subQuantum > 0) {
123
- ctx.trace?.step("trySkillAnchors", [
124
- rItem(query.subarray(0, 0), `skipped ${shapeMisses + subQuantum}`),
125
- rNode(ctx, cand.anchor, "chosen"),
126
- ], [], `skipped ${shapeMisses} non-exemplar and ${subQuantum} sub-quantum ` +
127
- `anchor(s) before one yielded a usable extraction`);
128
- }
129
- t?.done([rItem(built.bytes, "extracted")], built.pieces === 1
130
- ? `apply a learnt extraction skill — read the analogous span of the query` +
131
- ` framed like "${decodeText(exemplar.answerBytes)}" sits in its exemplar`
132
- : `apply a learnt MULTI-PIECE skill — read ${built.pieces} analogous` +
133
- ` pieces of the query and synthesize them like "${decodeText(exemplar.answerBytes)}"`);
134
- return {
135
- bytes: built.bytes,
136
- accounted: built.accounted,
137
- unexplained: unexplainedLabel(query, built.accounted),
138
- };
139
- }
140
- if (shapeMisses === searched.length) {
141
- ctx.trace?.step("trySkillAnchors", [], [], `none of the top ${searched.length} ranked anchor(s) (of ${ranked.length} total) ` +
142
- `is a span-shaped skill exemplar`);
143
- return fail("no consensus root is a span-shaped skill exemplar");
144
- }
145
- return fail("no ranked anchor yielded an extraction at or above the quantum floor");
146
- }
147
- /** Build the extracted bytes for ONE already-accepted span-shaped exemplar —
148
- * factored out of {@link extractBySkill} so its anchor loop can try
149
- * successive ranked candidates instead of committing to the first
150
- * structural match. Null when the exemplar's answer does not decompose
151
- * against its context, or no piece's frame locates in the query. */
152
- function buildFromExemplar(ctx, query, pre, exemplar) {
153
- const { contextBytes, answerBytes } = exemplar;
154
- const ansCtxRuns = answerRunsInContext(ctx, contextBytes, answerBytes);
155
- if (ansCtxRuns === null || ansCtxRuns.length === 0) {
156
- return null;
157
- }
158
- if (ansCtxRuns.length > 1) {
159
- ctx.trace?.step("decomposeAnswer", [rItem(answerBytes, "multi-piece-answer")], ansCtxRuns.map((r) => rItem(contextBytes.subarray(r.start, r.end), "piece", undefined, [
160
- r.start,
161
- r.end,
162
- ])), `answer splits into ${ansCtxRuns.length} piece(s) within the exemplar context`);
163
- }
164
- const pieces = [];
165
- const accounted = [];
166
- for (let ri = 0; ri < ansCtxRuns.length; ri++) {
167
- const run = ansCtxRuns[ri];
168
- const isLast = ri === ansCtxRuns.length - 1;
169
- const framePreLen = Math.min(run.start, ctx.space.maxGroup);
170
- const framePre = run.start > 0
171
- ? contextBytes.subarray(run.start - framePreLen, run.start)
172
- : null;
173
- const frames = [];
174
- let start = 0;
175
- if (framePre) {
176
- const prePos = locate(ctx, query, framePre, 0, pre.rec.sites);
177
- if (prePos < 0)
178
- continue;
179
- start = prePos + framePre.length;
180
- frames.push([prePos, start]); // the located frame IS matched evidence
181
- }
182
- let end;
183
- if (isLast) {
184
- if (run.end < contextBytes.length) {
185
- const framePostLen = Math.min(contextBytes.length - run.end, ctx.space.maxGroup);
186
- const framePost = contextBytes.subarray(run.end, run.end + framePostLen);
187
- const postPos = locate(ctx, query.subarray(start), framePost, 0, pre.rec.sites);
188
- if (postPos < 0)
189
- continue;
190
- end = start + postPos;
191
- frames.push([end, end + framePost.length]); // matched post-frame
192
- }
193
- else {
194
- end = query.length;
195
- }
196
- }
197
- else {
198
- const nextRun = ansCtxRuns[ri + 1];
199
- const nextPreLen = Math.min(nextRun.start, ctx.space.maxGroup);
200
- const nextPre = contextBytes.subarray(nextRun.start - nextPreLen, nextRun.start);
201
- const nextPos = locate(ctx, query.subarray(start), nextPre, 0, pre.rec.sites);
202
- if (nextPos < 0) {
203
- end = start + run.ansLen;
204
- }
205
- else {
206
- end = start + nextPos;
207
- frames.push([end, end + nextPre.length]); // matched next-frame
208
- }
209
- }
210
- if (start >= end)
211
- continue;
212
- pieces.push(query.subarray(start, end));
213
- accounted.push(...frames);
214
- // Bounded on both sides ⇒ the read span itself is explained (see doc).
215
- // frames carries the pre-border (when the answer is not at the context's
216
- // start) and the located right border (post-frame or next piece's
217
- // pre-frame); only when BOTH borders were located is the read bounded.
218
- const preBounded = run.start === 0 || frames.some(([, e]) => e === start);
219
- const postBounded = frames.some(([b]) => b === end);
220
- if (preBounded && postBounded)
221
- accounted.push([start, end]);
222
- }
223
- if (pieces.length === 0) {
224
- return null;
225
- }
226
- const out = pieces.length === 1 ? pieces[0] : concatBytes(pieces);
227
- return { bytes: out, accounted, pieces: pieces.length };
228
- }
229
- // ── The two span-shape readings: OPEN acceptance vs. STRONG decomposition ──
230
- //
231
- // isSpanShaped and answerRunsInContext read the SAME relation ("the answer is
232
- // drawn from the context") at two deliberately different strengths, and they
233
- // are NOT interchangeable:
234
- //
235
- // • isSpanShaped — the OPEN reading: any in-order embedding (a sparse
236
- // subsequence, arbitrary gaps). O(|context|) byte scan. Used to ACCEPT
237
- // an exemplar candidate.
238
- // • answerRunsInContext — the STRONG reading: a greedy longest-run
239
- // DECOMPOSITION into contiguous pieces. Greedy-longest is strictly
240
- // stronger than subsequence (a long late match can consume context an
241
- // earlier shorter choice needed), so an ACCEPTED exemplar can still fail
242
- // to decompose — extractBySkill then fails with "answer is not a
243
- // subsequence of the context" and think falls through to recall. That
244
- // fall-through is BEHAVIOUR, pinned by the extraction suites: do not
245
- // "unify" the two into one machine — replacing the open reading with the
246
- // strong one silently rejects exemplars extraction today accepts, and
247
- // replacing the strong one with a backtracking embedding changes which
248
- // pieces are read out of the query.
249
- /** Decompose an answer into substrings of its surrounding context, in order —
250
- * the STRONG span-shape reading (see the section note above). Returns null
251
- * when no greedy longest-run decomposition exists. Adjacent runs that
252
- * connect contiguously are merged. */
253
- export function answerRunsInContext(_ctx, context, answer) {
254
- const pos = indexOf(context, answer, 0);
255
- if (pos >= 0) {
256
- return [{ start: pos, end: pos + answer.length, ansLen: answer.length }];
257
- }
258
- const runs = [];
259
- let ai = 0;
260
- let ci = 0;
261
- while (ai < answer.length) {
262
- // Longest match of the remaining answer at any position of the remaining
263
- // context: one direct extend per context position — O(|ctx|·match) per
264
- // run, replacing the previous longest-first indexOf countdown whose
265
- // repeated scans were cubic on long sparse-subsequence answers.
266
- let bestLen = 0;
267
- let bestPos = -1;
268
- for (let p = ci; p < context.length; p++) {
269
- let l = 0;
270
- const maxL = Math.min(context.length - p, answer.length - ai);
271
- if (maxL <= bestLen)
272
- break; // no later position can beat the best
273
- while (l < maxL && context[p + l] === answer[ai + l])
274
- l++;
275
- if (l > bestLen) {
276
- bestLen = l;
277
- bestPos = p;
278
- if (ai + l === answer.length)
279
- break; // the whole remainder matched
280
- }
281
- }
282
- if (bestLen === 0)
283
- return null;
284
- runs.push({ start: bestPos, end: bestPos + bestLen, ansLen: bestLen });
285
- ai += bestLen;
286
- ci = bestPos + bestLen;
287
- }
288
- const merged = [];
289
- for (const r of runs) {
290
- const last = merged[merged.length - 1];
291
- if (last && r.start === last.end) {
292
- last.end = r.end;
293
- last.ansLen += r.ansLen;
294
- }
295
- else {
296
- merged.push({ ...r });
297
- }
298
- }
299
- return merged.length > 0 ? merged : null;
300
- }
301
- // ── Pipeline mechanism ──────────────────────────────────────────────────────
302
- export const extractionMechanism = {
303
- name: "extraction",
304
- provenance: "extract",
305
- async floor(_ctx, _query, pre, worthRunning) {
306
- // Extraction's floor is always exactly CONCEPT+STEP when it exists —
307
- // same investment discipline as CAST's (see cast.ts): when the bound
308
- // already cannot beat the incumbent, return it UNINVESTED (never
309
- // first-touch the climb just to be pruned).
310
- if (!worthRunning(CONCEPT + STEP))
311
- return CONCEPT + STEP;
312
- if ((await pre.attention()).ranked.length === 0)
313
- return null;
314
- return CONCEPT + STEP;
315
- },
316
- async run(ctx, query, pre) {
317
- const ex = await extractBySkill(ctx, query, pre);
318
- if (!ex)
319
- return [];
320
- return [{
321
- bytes: ex.bytes,
322
- accounted: ex.accounted,
323
- moves: CONCEPT + STEP * ex.accounted.length,
324
- unexplained: ex.unexplained,
325
- }];
326
- },
327
- };
@@ -1,16 +0,0 @@
1
- import type { MindContext } from "../types.js";
2
- import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
3
- /** A recall result. */
4
- export interface RecallResult {
5
- bytes: Uint8Array;
6
- echoed: boolean;
7
- accounted: Array<[number, number]>;
8
- moves: number;
9
- unexplained: string;
10
- /** See {@link import("../pipeline-mechanism.js").MechanismResult.complete}
11
- * — set by the IDENTITY-bridge tier alone. */
12
- complete?: boolean;
13
- }
14
- /** Recall the answer by resonating the whole query against the content index. */
15
- export declare function recallByResonance(ctx: MindContext, query: Uint8Array, pre: Precomputed): Promise<RecallResult | null>;
16
- export declare const recallMechanism: PipelineMechanism;