@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,331 +0,0 @@
1
- // pipeline.ts — the think pipeline (Section 5 of the mind).
2
- //
3
- // think() is the whole file's job: one lightest-derivation choice among
4
- // UNIFORM mechanisms. The pipeline sees mechanisms through the
5
- // PipelineMechanism interface only — it never imports a mechanism-specific
6
- // type and never has a special-case branch for any mechanism. Adding a
7
- // mechanism means registering one object; removing one means dropping it
8
- // from the list. The mechanisms themselves live in mechanisms/ (one file
9
- // each); the shared pre-computation they exchange lives in Precomputed
10
- // (pipeline-mechanism.ts).
11
- import { PASS, STEP } from "./graph-search.js";
12
- import { gistOf, read, resolve } from "./primitives.js";
13
- import { recognise } from "./recognition.js";
14
- import { fuseAttention, reason } from "./reasoning.js";
15
- import { unexplainedSpans } from "./rationale.js";
16
- import { rItem } from "./trace.js";
17
- import { hubBound } from "./traverse.js";
18
- import { Precomputed } from "./pipeline-mechanism.js";
19
- import { coverMechanism } from "./mechanisms/cover.js";
20
- import { castMechanism } from "./mechanisms/cast.js";
21
- import { confluenceMechanism } from "./mechanisms/confluence.js";
22
- import { extractionMechanism } from "./mechanisms/extraction.js";
23
- import { recallMechanism } from "./mechanisms/recall.js";
24
- // Re-exports: cover's pre-resolution helpers and the ALU adapter kept
25
- // importable from the pipeline module (their historical home).
26
- export { resolveConcepts, resolveConnectors } from "./mechanisms/cover.js";
27
- export { aluToMechanism } from "./mechanisms/alu.js";
28
- // ── Extension dispatch (pre-loop parse) ─────────────────────────────────────
29
- async function collectComputed(ctx, mechanisms, query) {
30
- const out = [];
31
- const meter = ctx.meter;
32
- for (const m of mechanisms) {
33
- if (!m.parse)
34
- continue;
35
- const spans = meter
36
- ? await meter.time(`${m.name}.parse`, () => m.parse(query))
37
- : await m.parse(query);
38
- out.push(...spans);
39
- }
40
- return out;
41
- }
42
- // ── Built-in mechanisms ─────────────────────────────────────────────────────
43
- // ORDER MATTERS, but only through the uniform floor/worthRunning pruning —
44
- // no mechanism is special-cased. Cover runs FIRST: when a computed
45
- // extension result (e.g. ALU) exists, cover masks it in at near-zero cost
46
- // (see mechanisms/cover.ts), which becomes `best` before any other mechanism
47
- // invests in its own precomputation. CAST's and confluence's floors (2*STEP,
48
- // 3*STEP) then fail `worthRunning` and are skipped by the SAME admissible-
49
- // floor pruning every mechanism is already subject to — not by asking
50
- // "is this an extension?". Grade TIES keep the earlier candidate, so this
51
- // order is also the tie-break priority: cover, cast, confluence, extraction,
52
- // recall.
53
- export const defaultMechanisms = [
54
- coverMechanism,
55
- castMechanism,
56
- confluenceMechanism,
57
- extractionMechanism,
58
- recallMechanism,
59
- ];
60
- /** Think: a single lightest-derivation exploration of the Sema graph.
61
- *
62
- * Every answer travels the same path:
63
- * 1. Pre-computation — recognise, extension parse, guide; everything
64
- * expensive stays lazy on Precomputed until a mechanism asks.
65
- * 2. Grounding — every mechanism yields candidates weighed in the one
66
- * cost ladder; the lightest grounding derivation wins.
67
- * 3. Post-grounding — diagnostics (narrowDecision, thinGrounding),
68
- * reasoning (multi-hop), fusion (multi-topic). */
69
- export async function think(ctx, query, mechs) {
70
- if (query.length === 0)
71
- return null;
72
- ctx._edgeGuide = gistOf(ctx, query);
73
- ctx._edgeChoice.clear();
74
- const t = ctx.trace?.enter("think", [rItem(query, "query")]);
75
- const done = (answer, note) => {
76
- t?.done(answer
77
- ? [rItem(answer, "answer", resolve(ctx, answer) ?? undefined)]
78
- : [], note);
79
- return answer;
80
- };
81
- // ── Pre-computation ──────────────────────────────────────────────────
82
- const mechanisms = mechs ?? defaultMechanisms;
83
- const rec = recognise(ctx, query);
84
- // Phase 1: collect computed spans from mechanisms that implement parse()
85
- const computed = await collectComputed(ctx, mechanisms, query);
86
- if (computed.length > 0) {
87
- ctx.trace?.step("computeExtensions", [rItem(query, "query")], computed.map((u) => rItem(query.subarray(u.i, u.j), "operand", undefined, [u.i, u.j])), `extensions recognised and evaluated ${computed.length} computation(s)`);
88
- for (const u of computed) {
89
- ctx.trace?.step("evalComputation", [rItem(query.subarray(u.i, u.j), "expression", undefined, [u.i, u.j])], [rItem(u.bytes, "result", resolve(ctx, u.bytes) ?? undefined)], "evaluate the recognised operation to its authoritative result");
90
- }
91
- }
92
- // Phase 2: the shared pre-computation container. Eager fields only
93
- // (recognition, computed spans, guide) — every expensive analysis
94
- // (consensus climb, weave, span-shape classification) is a lazily-cached
95
- // method on Precomputed, first-touched by whichever mechanism's floor
96
- // survives its cheap gates and the worthRunning check. A query no
97
- // mechanism climbs for (e.g. one an extension decided) never climbs.
98
- const pre = new Precomputed(ctx, query, rec, computed, ctx._edgeGuide);
99
- const grade = (w) => Math.floor(w / STEP);
100
- const unaccounted = (spans) => unexplainedSpans(query.length, spans)
101
- .reduce((sum, [s, e]) => sum + (e - s), 0);
102
- const weigh = (accounted, moves) => moves + PASS * unaccounted(accounted);
103
- const candidates = [];
104
- let best = null;
105
- const consider = (c) => {
106
- if (c.bytes.length === 0)
107
- return;
108
- if (ctx.meter)
109
- ctx.meter.candidates++;
110
- candidates.push(c);
111
- if (best === null) {
112
- best = c;
113
- return;
114
- }
115
- const g = grade(c.weight), gb = grade(best.weight);
116
- if (g < gb) {
117
- best = c;
118
- return;
119
- }
120
- // TIE-BREAK: AT EQUAL GRADE, PREFER THE ANSWER THAT INVENTS LESS.
121
- //
122
- // The ladder prices what a candidate leaves UNACCOUNTED, which is the
123
- // right primary question but cannot separate two candidates that leave
124
- // the same bytes unaccounted — and then the winner is whichever mechanism
125
- // happened to be considered first, which is not a reason.
126
- //
127
- // What still separates them is what they DID with those bytes. A
128
- // candidate that carries an unexplained span into its answer is passing
129
- // the asker's own words back as if they were derived; one that leaves
130
- // them out has made a smaller, honest claim. Measured on test/22's
131
- // two-fact chain: cover and recall both graded 11001 over 11 unexplained
132
- // bytes, cover answering "The capital of France is Paris famous for" (11
133
- // bytes of scaffolding) against recall's crossing of the hop (0). Order
134
- // alone decided it, and the shallower reading won.
135
- //
136
- // This never overrides the ladder — it only orders within one grade, so
137
- // coverage and moves still dominate exactly as before.
138
- if (g === gb && (c.scaffolding ?? 0) < (best.scaffolding ?? 0))
139
- best = c;
140
- };
141
- const worthRunning = (floor) => best === null || grade(floor) < grade(best.weight);
142
- // Phase 3: grounding loop
143
- // Per-mechanism accounting (src/meter.ts). The market's whole premise is
144
- // that mechanisms compete on one cost scale — so the profiling read-out is
145
- // also per-mechanism, uniformly: the loop never asks which one it holds.
146
- const meter = ctx.meter;
147
- for (const mech of mechanisms) {
148
- const floor = meter
149
- ? await meter.time(`${mech.name}.floor`, () => mech.floor(ctx, query, pre, worthRunning))
150
- : await mech.floor(ctx, query, pre, worthRunning);
151
- if (meter) {
152
- if (floor === null)
153
- meter.mechanismSkips++;
154
- else
155
- meter.mechanismFloors++;
156
- }
157
- if (floor === null) {
158
- ctx.trace?.step("skipMechanism", [], [], `${mech.name} skipped — structural precondition failed`);
159
- continue;
160
- }
161
- if (!worthRunning(floor)) {
162
- ctx.trace?.step("skipMechanism", [], [], `${mech.name} skipped — floor ${floor} cannot beat incumbent (grade ${grade(best.weight)})`);
163
- continue;
164
- }
165
- if (meter)
166
- meter.mechanismRuns++;
167
- const results = meter
168
- ? await meter.time(`${mech.name}.run`, () => mech.run(ctx, query, pre))
169
- : await mech.run(ctx, query, pre);
170
- for (const r of results) {
171
- const weight = r.weight ?? weigh(r.accounted, r.moves);
172
- consider({
173
- bytes: r.bytes,
174
- provenance: r.provenance ?? mech.provenance,
175
- weight,
176
- used: r.used,
177
- accounted: r.accounted,
178
- unexplained: r.unexplained,
179
- complete: r.complete,
180
- scaffolding: r.scaffolding,
181
- });
182
- }
183
- }
184
- // (TS cannot see the closure assignments into `best` and narrows it to its
185
- // initial null, so the read-back needs the assertion.)
186
- const decided = best;
187
- if (candidates.length > 1) {
188
- // The runner-up is computed BEFORE the decideGrounding step so its grade
189
- // margin can ride along in the step's structured data payload; the
190
- // computation itself is pure and was always unconditional — only its
191
- // position moved.
192
- let runnerUp = null;
193
- if (decided !== null) {
194
- for (const c of candidates) {
195
- if (c === decided)
196
- continue;
197
- if (runnerUp === null || grade(c.weight) < grade(runnerUp.weight)) {
198
- runnerUp = c;
199
- }
200
- }
201
- }
202
- const margin = decided !== null && runnerUp !== null
203
- ? grade(runnerUp.weight) - grade(decided.weight)
204
- : null;
205
- ctx.trace?.step("decideGrounding", candidates.map((c) => rItem(c.bytes, `${c.provenance} (weight ${c.weight.toFixed(3)}${c.unexplained ? `, unexplained: "${c.unexplained}"` : ""})`)), decided ? [rItem(decided.bytes, decided.provenance)] : [], "the lightest grounding derivation wins — every mechanism weighed in the one cost ladder", undefined, {
206
- version: 1,
207
- candidates: candidates.map((c) => ({
208
- provenance: c.provenance,
209
- weight: c.weight,
210
- grade: grade(c.weight),
211
- unexplainedBytes: unaccounted(c.accounted),
212
- decided: c === decided,
213
- })),
214
- ...(margin !== null ? { runnerUpMargin: margin } : {}),
215
- });
216
- if (decided !== null && runnerUp !== null && margin !== null) {
217
- if (margin <= 1) {
218
- ctx.trace?.step("narrowDecision", [
219
- rItem(decided.bytes, `${decided.provenance} (weight ${decided.weight.toFixed(3)})`),
220
- ], [
221
- rItem(runnerUp.bytes, `${runnerUp.provenance} (weight ${runnerUp.weight.toFixed(3)})`),
222
- ], `margin ${margin} grade-unit(s) — the decision could change with one more training fact`, undefined, { version: 1, margin });
223
- }
224
- }
225
- }
226
- if (decided === null) {
227
- done(null, "no mechanism grounded an answer");
228
- return null;
229
- }
230
- // Honesty density
231
- {
232
- const covered = query.length - unaccounted(decided.accounted);
233
- const density = query.length > 0 ? covered / query.length : 1;
234
- const thinBar = 1 / ctx.space.maxGroup;
235
- if (density < thinBar) {
236
- ctx.trace?.step("thinGrounding", [rItem(decided.bytes, decided.provenance)], [], `grounded but thin — density ${density.toFixed(3)} is below 1/W (${thinBar.toFixed(3)})`);
237
- }
238
- }
239
- const answer = decided.bytes;
240
- const provenance = decided.provenance;
241
- const castUsed = decided.used ?? new Set();
242
- // ── Post-grounding, gated by provenance ──────────────────────────────
243
- const preConsumed = provenance === "cast" || provenance === "join"
244
- ? castUsed
245
- : provenance === "recall" || provenance === "recall-echo"
246
- ? new Set()
247
- : new Set(recognise(ctx, answer).sites.map((s) => s.payload));
248
- // A grounding that DECLARED itself complete is not extended: the answer is
249
- // already a trained form's own continuation, reached through an identity
250
- // claim about the query, so a multi-hop pivot could only chain past the
251
- // fact that produced it (see MechanismResult.complete).
252
- // WHAT THE MECHANISM WITHHELD, NOT WHAT IT VOICED. A pivot must not
253
- // re-open content a grounding deliberately kept out: comparison cites two
254
- // analogs and refuses their own downstream facts, so pivoting into one is
255
- // the mechanism's own refusal undone one step later (test/29 C2 pivoted
256
- // through `speare` — a stored fragment of the analog `William Shakespeare`
257
- // — into the biography CAST had declined).
258
- //
259
- // Reading the used anchors' OWN bytes here says something stronger and
260
- // wrong: that nothing INSIDE what was voiced may be pivoted through. A
261
- // comparison's seat sentence legitimately contains further terms with
262
- // their own unrelated facts, and C3 pins exactly that — `Mona Lisa`, inside
263
- // the voiced seat `The Mona Lisa was painted by Leonardo da Vinci.`, leads
264
- // on to `Mona Lisa hangs in the Louvre`, which is about neither analog.
265
- // The withheld content is the used anchors' CONTINUATIONS, so that is what
266
- // the containment rule reads: `speare` is contained in `Shakespeare wrote
267
- // 39 plays` and stays refused, while `Mona Lisa` appears in no withheld
268
- // continuation and the genuine further hop fires.
269
- //
270
- // Only a mechanism carrying its own `used` set (cast/join) gets this: there
271
- // `preConsumed` is a deliberate, short list of the anchors the answer
272
- // speaks for, so the fan-out is bounded. For every other provenance
273
- // `preConsumed` is derived by re-recognising the answer — "everything in
274
- // it", not "what it voiced" — and a containment rule over that would
275
- // suppress every pivot the answer legitimately contains.
276
- const voiced = (provenance === "cast" || provenance === "join")
277
- ? [...castUsed].flatMap((id) => ctx.store.nextFirst(id, hubBound(ctx)).map((n) => read(ctx, n)))
278
- : [];
279
- const reasoned = decided.complete ? answer : meter
280
- ? await meter.time("reason", () => reason(ctx, query, answer, preConsumed, pre, voiced))
281
- : await reason(ctx, query, answer, preConsumed, pre, voiced);
282
- // Fuse only when the query has a genuine REMAINDER no mechanism's
283
- // structural evidence touched at all. `decided.accounted` alone
284
- // undercounts this: it is a COST-LADDER quantity (cover.ts prices its
285
- // masked/computed spans at near-zero and deliberately leaves them out of
286
- // `accounted` so PASS-bridged bytes are still charged), not a coverage
287
- // one — a query fully explained by one computed span plus bridged
288
- // connectors can report `accounted: []` while nothing is actually left
289
- // unexplained. The genuine remainder is what NEITHER the winning
290
- // candidate's accounted spans NOR any recognised extension's computed
291
- // span (`pre.computed` — every mechanism's parse() output, ALU included)
292
- // ever touched. A remainder under one river-fold quantum (W, the same
293
- // floor cover.ts's restatedSpan and the honesty-density bar above both
294
- // use) is bridging punctuation/whitespace, never a second topic —
295
- // observed: a single space between two fully-computed arithmetic spans
296
- // ("2+2 3+3") registered as "unaccounted" and pulled in an unrelated
297
- // corpus fact, corrupting "4 6" into "4 63".
298
- const explained = [
299
- ...decided.accounted,
300
- ...pre.computed.map((u) => [u.i, u.j]),
301
- ];
302
- const remainder = unaccounted(explained);
303
- // Whether the winning candidate's entire recognised substance is
304
- // COMPUTED — every accounted span exactly a pre.computed span, nothing
305
- // from a genuinely recognised/climbed site. fuseAttention's lone-root
306
- // shortcut assumes a single point of attention already IS primary's own
307
- // source; that assumption is exactly backwards for a pure computation
308
- // (an ALU result has no anchor of its own) — see fuseAttention's
309
- // `unclimbed` parameter, gated there by Attention.breadth so a
310
- // coincidental echo (which this flag alone cannot distinguish) is still
311
- // rejected.
312
- const unclimbed = decided.accounted.length > 0 &&
313
- decided.accounted.every(([i, j]) => pre.computed.some((u) => u.i === i && u.j === j));
314
- // Where the winning grounding stands in the query — fusion places primary
315
- // by it (see fuseAttention's `primarySpans`). `accounted` is the
316
- // cost-ladder read and is authoritative when non-empty; when it is empty
317
- // the grounding is a pure COMPUTATION, whose evidence is its computed span.
318
- // Exactly the cost-ladder-vs-coverage distinction `explained` above draws,
319
- // read here for POSITION instead of for coverage — and resolved here, where
320
- // both readings are in hand, rather than inside fuseAttention.
321
- const primarySpans = decided.accounted.length > 0
322
- ? decided.accounted
323
- : pre.computed.map((u) => [u.i, u.j]);
324
- const fused = remainder < ctx.space.maxGroup
325
- ? reasoned
326
- : meter
327
- ? await meter.time("fuse", () => fuseAttention(ctx, query, reasoned, pre, unclimbed, primarySpans))
328
- : await fuseAttention(ctx, query, reasoned, pre, unclimbed, decided.accounted);
329
- done(fused, "grounded, reasoned forward, fused across points of attention");
330
- return { bytes: fused, provenance };
331
- }
@@ -1,59 +0,0 @@
1
- import type { MindContext } from "./types.js";
2
- /** Trained forms the query may OPEN, proposed from the write side's own
3
- * leaf-id window index — the supply of last resort for {@link
4
- * prefixCompletion}.
5
- *
6
- * WHY A SECOND SUPPLY EXISTS. The ranked list this mechanism normally reads
7
- * is a resonance list, and resonance cannot rank a proper prefix: measured on
8
- * the trained store, cos(prefix, form) falls from 0.9629 at a one-byte
9
- * truncation to 0.6206 at three bytes, against a reachThreshold of 0.8750.
10
- * Three bytes of truncation put the answer out of reach on GEOMETRY, not on a
11
- * bug, so no k and no re-ranking recovers it.
12
- *
13
- * WHY THIS ROUTE WORKS WHERE THE FOLD DOES NOT. A query's own fold is
14
- * useless here: content addressing is not phrase-position-invariant, so a
15
- * standalone prefix folds to a DIFFERENT node than the same bytes sitting
16
- * inside a longer deposit, and neither the prefix's own node nor its
17
- * ancestors lead to the deposit (measured: the 22-byte prefix of the
18
- * photosynthesis form resolves, is shared by 6 contexts, and does not have
19
- * the form among its ancestors). Leaf ids ARE position-invariant — they are
20
- * content-addressed on single bytes — and `indexSubSpans` already interns a
21
- * flat branch over every canonical WINDOW of a deposit's leaf-id stream, with
22
- * containment edges to the chunks that window spans. A query that is a
23
- * prefix therefore shares those window nodes exactly, and reaches the deposit
24
- * by climbing containment then parents. Nothing is added to the write side;
25
- * this reads an index training already built.
26
- *
27
- * BOUNDED (§2.8), AND WITH NO NEW THRESHOLD. The window whose containment is
28
- * SMALLEST carries the most evidence, and one saturated at `hubBound` carries
29
- * none — that is the same √N reading of "hub" the rest of the mind uses, not
30
- * a tuned knob. The upward walk spends a budget of `hubBound` nodes and
31
- * fans out by W, so a hub query enumerates nothing and the caller stays
32
- * silent rather than guessing (§2.13). Measured on the trained store: the
33
- * photosynthesis form at a one-byte truncation picks a window with 52
34
- * containers, visits 446 nodes, and yields exactly ONE candidate that
35
- * survives the caller's byte compare — the form itself.
36
- *
37
- * These are PROPOSALS only. Every candidate still faces the byte-exact
38
- * prefix compare and all three guards below, so a wrong proposal costs one
39
- * bounded read and can never be voiced (§2.3). */
40
- export declare function prefixCandidates(ctx: MindContext, query: Uint8Array): number[];
41
- /** A trained form the query opens, and the bytes by which it continues. */
42
- export interface PrefixCompletion {
43
- /** The trained form whose opening the query is — the answer, voiced whole. */
44
- id: number;
45
- /** The form's own bytes. The mechanism grounds a FORM, never a slice of
46
- * one: slicing at the query's end would cut at an offset the geometry has
47
- * no reason to treat as a boundary. */
48
- form: Uint8Array;
49
- /** The bytes past the query — carried for the rationale and for the
50
- * uniqueness comparison, not voiced on its own. */
51
- continuation: Uint8Array;
52
- }
53
- /** The sole trained form the query opens — or null when no candidate opens with
54
- * it, when the continuation is sub-quantum, when a candidate's continuation
55
- * cannot be read through, or when the candidates disagree.
56
- *
57
- * `ranked` must be a list the caller has ALREADY fetched; this mechanism never
58
- * resonates on its own (see the header's cost note). */
59
- export declare function prefixCompletion(ctx: MindContext, query: Uint8Array, ranked: ReadonlyArray<number>): PrefixCompletion | null;
@@ -1,270 +0,0 @@
1
- // prefix-completion.ts — Grounding a query that IS the opening of a trained
2
- // form.
3
- //
4
- // THE SHAPE. `The capital of France is` grounds nothing, while
5
- // `The capital of France is Paris.` is trained and reads back byte-exact. The
6
- // query is not SIMILAR to that form, it is a PROPER PREFIX of it: every query
7
- // byte is a literal match, in order, from offset zero. That is the strongest
8
- // grounding relation in the store — stronger than the bridge's corroborated
9
- // substitution, which pays a CONCEPT per substituted span, and stronger than
10
- // resonance, which only claims an angle. Nothing is invented: the answer IS a
11
- // trained form, voiced whole.
12
- //
13
- // NO NOTION OF TEXT. This mechanism reads bytes and geometry only. It has no
14
- // separator, no character class, no "word": the only structural quantity it
15
- // uses is W, the river's grouping window, which is the same capacity the
16
- // perception tree groups by and the same bar the argument-binding tier holds
17
- // its constituents to. A completion shorter than one grouping window carries
18
- // no structure the geometry can perceive, whatever the modality — that is a
19
- // statement about the fold, not about punctuation. Presentation (what is
20
- // "spacing", what is "case") belongs to the injected canon and to the modality
21
- // entry point, never here; see src/canon.ts.
22
- //
23
- // WHY THE EARLIER TIERS CANNOT DO IT. Two independent reasons, both measured:
24
- //
25
- // 1. `resolve(prefix)` is null. A proper prefix of a deposited stream has no
26
- // branch of its own unless it was itself deposited, so the exact tiers
27
- // have nothing to find.
28
- // 2. The form is not among the resonance candidates AT ALL. Measured on the
29
- // trained store: cos(query, that form) = 0.5752, yet the form is absent
30
- // from `resonate(k)` at k = 24, 256 AND 2048 — while forms scoring LOWER
31
- // (Germany 0.5670, Yemen 0.5591) are returned. `k` only reorders WITHIN
32
- // the IVF clusters already probed, exactly as Store.resonate's doc warns,
33
- // so no k recovers it. With `exhaustive` it ranks 8.
34
- //
35
- // So this is a RETRIEVABILITY gap, not a semantic one, and it is repaired by
36
- // reading the candidate list recall's refusal path has ALREADY fetched
37
- // exhaustively for the substitution bridge — never by resonating on its own.
38
- // Measured cost of the scan over those 570 candidates: 2.9 ms warm, 20.4 ms
39
- // cold, against a ~700 ms refusal path. Issuing a FRESH exhaustive call would
40
- // cost 490 ms median against 13 ms non-exhaustive (36×), which is why this tier
41
- // takes the candidate list as an argument and adds nothing to it.
42
- //
43
- // THREE GUARDS, each falsified into existence by measurement — do not drop any:
44
- //
45
- // 1. AN UNREADABLE CONTINUATION VETOES. Reads are bounded (a stored span can
46
- // run to hundreds of kilobytes), so a candidate that opens with the query
47
- // but SATURATES the read continues in a way nobody can see. It is a
48
- // standing disagreement: if any such candidate exists, nothing is grounded.
49
- // It must NOT be quietly skipped, and that is not a stylistic point — the
50
- // skip is what MANUFACTURES a fragment. Measured on a one-deposit fixture
51
- // whose form exceeds the cap: the query matched BOTH the whole 138-byte
52
- // form (saturating) AND an interior fold node of 34 bytes (unsaturated,
53
- // continuing `" Paris, an"`). Skipping the saturated candidate removed the
54
- // only evidence that disagreed, uniqueness then passed on the interior
55
- // node, and a mid-form slice was voiced as an answer. Suppressing the
56
- // disagreement is what created the fabrication.
57
- // (Testing instead whether a candidate is a "complete form" via the fold
58
- // does NOT work and was measured: content addressing makes an interior
59
- // node resolve to ITSELF, so self-resolution says nothing about
60
- // completeness.)
61
- // 2. THE CONTINUATION MUST REACH ONE GROUPING WINDOW. A trained
62
- // `What is the capital of France??` opens with `What is the capital of
63
- // France?` and continues by a single byte. Below W the continuation is
64
- // sub-quantum — the fold groups nothing from it — and voicing it produces
65
- // the degenerate reply that is a known failure smell.
66
- // 3. UNIQUENESS. Several trained forms may open with the query and continue
67
- // differently, and then the corpus does not say which continuation the
68
- // asker means. Distinct continuations ⇒ refuse. This is the documented
69
- // PREFIX TRAP, and it is real — just not for every prefix. Measured: of
70
- // 15 battery probes exactly ONE yields a unique continuation, and all
71
- // three honest-silence probes yield none (including `What is the capital
72
- // of Zamunda?`, whose top hit scores 0.83).
73
- //
74
- // Uniqueness is judged on the continuation BYTES, not on the candidate id: the
75
- // same continuation reached through two trained forms is one answer, not an
76
- // ambiguity.
77
- import { bytesEqual } from "../bytes.js";
78
- import { rItem } from "./trace.js";
79
- import { canonicalWindows, leafIdPrefix } from "./canonical.js";
80
- import { hubBound } from "./traverse.js";
81
- /** Trained forms the query may OPEN, proposed from the write side's own
82
- * leaf-id window index — the supply of last resort for {@link
83
- * prefixCompletion}.
84
- *
85
- * WHY A SECOND SUPPLY EXISTS. The ranked list this mechanism normally reads
86
- * is a resonance list, and resonance cannot rank a proper prefix: measured on
87
- * the trained store, cos(prefix, form) falls from 0.9629 at a one-byte
88
- * truncation to 0.6206 at three bytes, against a reachThreshold of 0.8750.
89
- * Three bytes of truncation put the answer out of reach on GEOMETRY, not on a
90
- * bug, so no k and no re-ranking recovers it.
91
- *
92
- * WHY THIS ROUTE WORKS WHERE THE FOLD DOES NOT. A query's own fold is
93
- * useless here: content addressing is not phrase-position-invariant, so a
94
- * standalone prefix folds to a DIFFERENT node than the same bytes sitting
95
- * inside a longer deposit, and neither the prefix's own node nor its
96
- * ancestors lead to the deposit (measured: the 22-byte prefix of the
97
- * photosynthesis form resolves, is shared by 6 contexts, and does not have
98
- * the form among its ancestors). Leaf ids ARE position-invariant — they are
99
- * content-addressed on single bytes — and `indexSubSpans` already interns a
100
- * flat branch over every canonical WINDOW of a deposit's leaf-id stream, with
101
- * containment edges to the chunks that window spans. A query that is a
102
- * prefix therefore shares those window nodes exactly, and reaches the deposit
103
- * by climbing containment then parents. Nothing is added to the write side;
104
- * this reads an index training already built.
105
- *
106
- * BOUNDED (§2.8), AND WITH NO NEW THRESHOLD. The window whose containment is
107
- * SMALLEST carries the most evidence, and one saturated at `hubBound` carries
108
- * none — that is the same √N reading of "hub" the rest of the mind uses, not
109
- * a tuned knob. The upward walk spends a budget of `hubBound` nodes and
110
- * fans out by W, so a hub query enumerates nothing and the caller stays
111
- * silent rather than guessing (§2.13). Measured on the trained store: the
112
- * photosynthesis form at a one-byte truncation picks a window with 52
113
- * containers, visits 446 nodes, and yields exactly ONE candidate that
114
- * survives the caller's byte compare — the form itself.
115
- *
116
- * These are PROPOSALS only. Every candidate still faces the byte-exact
117
- * prefix compare and all three guards below, so a wrong proposal costs one
118
- * bounded read and can never be voiced (§2.3). */
119
- export function prefixCandidates(ctx, query) {
120
- const store = ctx.store;
121
- const W = ctx.space.maxGroup;
122
- const run = leafIdPrefix(ctx, query);
123
- // The widest canonical window is the most discriminative one the write side
124
- // ever interned; a query too short to spell one carries no window evidence.
125
- const len = canonicalWindows(W)[1];
126
- if (run.length < len)
127
- return [];
128
- const bound = hubBound(ctx);
129
- let best = null;
130
- let bestN = 0;
131
- for (let off = 0; off + len <= run.length; off++) {
132
- const wid = store.findBranch(run.slice(off, off + len));
133
- if (wid === null)
134
- continue;
135
- const n = store.containersSlice(wid, 0, bound).length;
136
- // Empty says the window spans no chunk; saturated says it is a hub, whose
137
- // containment discriminates nothing. Neither is evidence.
138
- if (n === 0 || n >= bound)
139
- continue;
140
- if (best === null || n < bestN) {
141
- best = wid;
142
- bestN = n;
143
- }
144
- }
145
- if (best === null)
146
- return [];
147
- let frontier = store.containersSlice(best, 0, bound);
148
- const seen = new Set(frontier);
149
- let budget = bound;
150
- while (frontier.length > 0 && budget > 0) {
151
- const next = [];
152
- for (const f of frontier) {
153
- if (budget-- <= 0)
154
- break;
155
- for (const p of store.parentsFirst(f, W)) {
156
- if (seen.has(p))
157
- continue;
158
- seen.add(p);
159
- next.push(p);
160
- }
161
- }
162
- frontier = next;
163
- }
164
- return [...seen];
165
- }
166
- /** The sole trained form the query opens — or null when no candidate opens with
167
- * it, when the continuation is sub-quantum, when a candidate's continuation
168
- * cannot be read through, or when the candidates disagree.
169
- *
170
- * `ranked` must be a list the caller has ALREADY fetched; this mechanism never
171
- * resonates on its own (see the header's cost note). */
172
- export function prefixCompletion(ctx, query, ranked) {
173
- const W = ctx.space.maxGroup;
174
- const t = ctx.trace?.enter("prefixCompletion", [rItem(query, "query")]);
175
- const done = (hit, note, data) => {
176
- t?.done(hit === null ? [] : [rItem(hit.continuation, "continuation", hit.id)], note, data);
177
- return hit;
178
- };
179
- // Reads are bounded to phrase scale, the same bound the frame filler uses.
180
- // A query with no room for a whole grouping window past its own length
181
- // cannot clear guard 2, so it is not worth a single read.
182
- const cap = query.length * W;
183
- if (query.length === 0 || cap < query.length + W) {
184
- return done(null, "no room for a perceivable continuation within the cap");
185
- }
186
- // Distinct continuations, each with the first form that offered it. Held as
187
- // a list, not a byte-keyed map: candidates that open with the query are few
188
- // (measured: 1 on the trained store's winning query), and a linear byte
189
- // compare needs no string encoding of content. Uniqueness (guard 3) is
190
- // decided over this list, so the scan cannot stop early — a second
191
- // continuation IS the refusal, and finding it is the point.
192
- const found = [];
193
- let opened = 0;
194
- let unreadable = 0;
195
- let subQuantum = 0;
196
- for (const id of ranked) {
197
- const form = ctx.store.bytesPrefix(id, cap);
198
- if (form.length <= query.length)
199
- continue;
200
- let opens = true;
201
- for (let i = 0; i < query.length; i++) {
202
- if (form[i] !== query[i]) {
203
- opens = false;
204
- break;
205
- }
206
- }
207
- if (!opens)
208
- continue;
209
- opened++;
210
- // Guard 1: a saturated read continues out of sight — a disagreement that
211
- // cannot be resolved, so it ends the search rather than being skipped.
212
- if (form.length >= cap) {
213
- unreadable++;
214
- continue;
215
- }
216
- const rest = form.subarray(query.length);
217
- // Guard 2: below one grouping window there is no structure to voice.
218
- if (rest.length < W) {
219
- subQuantum++;
220
- continue;
221
- }
222
- if (!found.some((f) => bytesEqual(f.continuation, rest))) {
223
- found.push({ id, form, continuation: rest });
224
- }
225
- }
226
- const data = {
227
- candidates: ranked.length,
228
- opened,
229
- unreadable,
230
- subQuantum,
231
- distinctContinuations: found.length,
232
- };
233
- if (unreadable > 0 && found.length > 0) {
234
- return done(null, "a form opens with this query but continues past the read bound — " +
235
- "its continuation cannot be read, so none is licensed", data);
236
- }
237
- // Guard 2b: A SUB-QUANTUM CONTINUATION IS STILL A DISAGREEMENT. Guard 2
238
- // refuses to VOICE a below-window continuation, and rightly — there is no
239
- // structure there to speak. But dropping such a candidate from the
240
- // uniqueness tally silently converts "the corpus offers many continuations,
241
- // most of them unvoiceable" into "the corpus offers exactly one", and
242
- // guard 3 then passes VACUOUSLY on the sole survivor. That is precisely
243
- // the failure guard 1 documents for unreadable continuations — suppressing
244
- // the disagreement is what manufactures the answer — so it is answered the
245
- // same way, and for the same reason.
246
- //
247
- // Measured on a 4,300-fact fixture of "what is the value of <i>?": the
248
- // query "what is the value of" drew candidates continuing " 0?", " 4?",
249
- // " 8?" (3 bytes, sub-quantum at W=4) and " 10?" (4 bytes). The first
250
- // three were dropped, leaving one survivor, and the mechanism reported
251
- // "exactly one trained form" and voiced "the value of 10 is 20" — an
252
- // arbitrary pick from thousands of equally-good readings, with the
253
- // evidence of ambiguity discarded on the way.
254
- //
255
- // Note this can only ever cause SILENCE, never a different answer: it
256
- // withholds a completion the corpus does not uniquely license.
257
- if (subQuantum > 0 && found.length > 0) {
258
- return done(null, "other trained forms open with this query but continue below one " +
259
- "grouping window — the corpus offers competing readings, so no " +
260
- "single completion is licensed", data);
261
- }
262
- // Guard 3: the corpus must agree on ONE continuation.
263
- if (found.length !== 1) {
264
- return done(null, found.length === 0
265
- ? "no trained form opens with this query and continues perceivably"
266
- : "trained forms open with this query but continue differently — " +
267
- "the corpus does not say which continuation is meant", data);
268
- }
269
- return done(found[0], "one trained form opens with this query, and continues perceivably", data);
270
- }