@hviana/sema 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/AGENTS.md +6 -6
  2. package/HOW_IT_WORKS.md +16 -0
  3. package/jsr.json +1 -1
  4. package/package.json +1 -1
  5. package/src/mind/match.ts +81 -0
  6. package/src/mind/mechanisms/recall.ts +29 -3
  7. package/test/76-reference-binding.test.mjs +72 -0
  8. package/dist/example/demo.d.ts +0 -1
  9. package/dist/example/demo.js +0 -39
  10. package/dist/example/train_base.d.ts +0 -93
  11. package/dist/example/train_base.js +0 -2269
  12. package/dist/src/alphabet.d.ts +0 -7
  13. package/dist/src/alphabet.js +0 -33
  14. package/dist/src/alu/src/alu.d.ts +0 -185
  15. package/dist/src/alu/src/alu.js +0 -440
  16. package/dist/src/alu/src/expr.d.ts +0 -61
  17. package/dist/src/alu/src/expr.js +0 -318
  18. package/dist/src/alu/src/index.d.ts +0 -11
  19. package/dist/src/alu/src/index.js +0 -19
  20. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  21. package/dist/src/alu/src/kernel-arith.js +0 -264
  22. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  23. package/dist/src/alu/src/kernel-bits.js +0 -152
  24. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  25. package/dist/src/alu/src/kernel-logic.js +0 -60
  26. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  27. package/dist/src/alu/src/kernel-nd.js +0 -208
  28. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  29. package/dist/src/alu/src/kernel-numeric.js +0 -366
  30. package/dist/src/alu/src/operation.d.ts +0 -168
  31. package/dist/src/alu/src/operation.js +0 -189
  32. package/dist/src/alu/src/parser.d.ts +0 -221
  33. package/dist/src/alu/src/parser.js +0 -577
  34. package/dist/src/alu/src/resonance.d.ts +0 -55
  35. package/dist/src/alu/src/resonance.js +0 -126
  36. package/dist/src/alu/src/text.d.ts +0 -31
  37. package/dist/src/alu/src/text.js +0 -73
  38. package/dist/src/alu/src/value.d.ts +0 -109
  39. package/dist/src/alu/src/value.js +0 -300
  40. package/dist/src/alu/test/alu.test.d.ts +0 -1
  41. package/dist/src/alu/test/alu.test.js +0 -764
  42. package/dist/src/bytes.d.ts +0 -14
  43. package/dist/src/bytes.js +0 -59
  44. package/dist/src/canon.d.ts +0 -45
  45. package/dist/src/canon.js +0 -85
  46. package/dist/src/config.d.ts +0 -111
  47. package/dist/src/config.js +0 -91
  48. package/dist/src/derive/src/deduction.d.ts +0 -136
  49. package/dist/src/derive/src/deduction.js +0 -159
  50. package/dist/src/derive/src/index.d.ts +0 -8
  51. package/dist/src/derive/src/index.js +0 -11
  52. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  53. package/dist/src/derive/src/priority-queue.js +0 -73
  54. package/dist/src/derive/src/rewrite.d.ts +0 -56
  55. package/dist/src/derive/src/rewrite.js +0 -100
  56. package/dist/src/derive/src/trie.d.ts +0 -90
  57. package/dist/src/derive/src/trie.js +0 -217
  58. package/dist/src/derive/test/derive.test.d.ts +0 -1
  59. package/dist/src/derive/test/derive.test.js +0 -122
  60. package/dist/src/extension.d.ts +0 -37
  61. package/dist/src/extension.js +0 -7
  62. package/dist/src/geometry.d.ts +0 -233
  63. package/dist/src/geometry.js +0 -1089
  64. package/dist/src/index.d.ts +0 -17
  65. package/dist/src/index.js +0 -19
  66. package/dist/src/ingest-cache.d.ts +0 -41
  67. package/dist/src/ingest-cache.js +0 -165
  68. package/dist/src/meter.d.ts +0 -176
  69. package/dist/src/meter.js +0 -274
  70. package/dist/src/mind/articulation.d.ts +0 -6
  71. package/dist/src/mind/articulation.js +0 -99
  72. package/dist/src/mind/attention.d.ts +0 -430
  73. package/dist/src/mind/attention.js +0 -2418
  74. package/dist/src/mind/bridge.d.ts +0 -37
  75. package/dist/src/mind/bridge.js +0 -907
  76. package/dist/src/mind/canonical.d.ts +0 -34
  77. package/dist/src/mind/canonical.js +0 -93
  78. package/dist/src/mind/graph-search.d.ts +0 -294
  79. package/dist/src/mind/graph-search.js +0 -996
  80. package/dist/src/mind/index.d.ts +0 -9
  81. package/dist/src/mind/index.js +0 -5
  82. package/dist/src/mind/junction.d.ts +0 -137
  83. package/dist/src/mind/junction.js +0 -358
  84. package/dist/src/mind/learning.d.ts +0 -75
  85. package/dist/src/mind/learning.js +0 -265
  86. package/dist/src/mind/match.d.ts +0 -351
  87. package/dist/src/mind/match.js +0 -959
  88. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  89. package/dist/src/mind/mechanisms/alu.js +0 -36
  90. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  91. package/dist/src/mind/mechanisms/cast.js +0 -1186
  92. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  93. package/dist/src/mind/mechanisms/confluence.js +0 -271
  94. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  95. package/dist/src/mind/mechanisms/cover.js +0 -232
  96. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  97. package/dist/src/mind/mechanisms/extraction.js +0 -327
  98. package/dist/src/mind/mechanisms/prefix-completion.d.ts +0 -22
  99. package/dist/src/mind/mechanisms/prefix-completion.js +0 -243
  100. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  101. package/dist/src/mind/mechanisms/recall.js +0 -460
  102. package/dist/src/mind/mechanisms/reference.d.ts +0 -6
  103. package/dist/src/mind/mechanisms/reference.js +0 -296
  104. package/dist/src/mind/mind.d.ts +0 -386
  105. package/dist/src/mind/mind.js +0 -754
  106. package/dist/src/mind/pipeline-mechanism.d.ts +0 -238
  107. package/dist/src/mind/pipeline-mechanism.js +0 -622
  108. package/dist/src/mind/pipeline.d.ts +0 -49
  109. package/dist/src/mind/pipeline.js +0 -343
  110. package/dist/src/mind/primitives.d.ts +0 -85
  111. package/dist/src/mind/primitives.js +0 -333
  112. package/dist/src/mind/rationale.d.ts +0 -139
  113. package/dist/src/mind/rationale.js +0 -163
  114. package/dist/src/mind/reasoning.d.ts +0 -42
  115. package/dist/src/mind/reasoning.js +0 -305
  116. package/dist/src/mind/recognition.d.ts +0 -20
  117. package/dist/src/mind/recognition.js +0 -696
  118. package/dist/src/mind/resonance.d.ts +0 -35
  119. package/dist/src/mind/resonance.js +0 -365
  120. package/dist/src/mind/trace.d.ts +0 -15
  121. package/dist/src/mind/trace.js +0 -73
  122. package/dist/src/mind/traverse.d.ts +0 -196
  123. package/dist/src/mind/traverse.js +0 -806
  124. package/dist/src/mind/types.d.ts +0 -418
  125. package/dist/src/mind/types.js +0 -179
  126. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  127. package/dist/src/rabitq-ivf/src/database.js +0 -201
  128. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  129. package/dist/src/rabitq-ivf/src/index.js +0 -4
  130. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  131. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  132. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  133. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  134. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  135. package/dist/src/rabitq-ivf/src/rabitq.js +0 -313
  136. package/dist/src/sema.d.ts +0 -41
  137. package/dist/src/sema.js +0 -77
  138. package/dist/src/store-sqlite.d.ts +0 -184
  139. package/dist/src/store-sqlite.js +0 -942
  140. package/dist/src/store.d.ts +0 -762
  141. package/dist/src/store.js +0 -1823
  142. package/dist/src/vec.d.ts +0 -31
  143. package/dist/src/vec.js +0 -109
@@ -1,35 +0,0 @@
1
- import type { MindContext } from "./types.js";
2
- /** The connector that belongs BETWEEN two adjacent results — the graded
3
- * junction ladder described in the module note above. Returns null when
4
- * the graph holds no evidence that the two ever ran together. */
5
- export declare function bridge(ctx: MindContext, left: Uint8Array, right: Uint8Array, interiorAllowance?: number): Promise<Uint8Array | null>;
6
- /** Join two spans with the learnt connector between them, when one exists —
7
- * the composition step every out-of-search assembly (multi-topic fusion,
8
- * CAST's substitution and comparison) shares. A miss joins the pieces BARE
9
- * and is never silent: it emits the same `bridgeMiss` trace step everywhere,
10
- * so a degraded join is visible in the rationale regardless of which
11
- * mechanism paid it. (The in-search connector splice in graph-search.ts is
12
- * the same concept inside the deduction, where the join is a costed rule.) */
13
- export declare function joinWithBridge(ctx: MindContext, left: Uint8Array, right: Uint8Array): Promise<Uint8Array>;
14
- /** The pivot a produced answer bridges through: the longest UNCONSUMED learnt
15
- * CONTEXT (a node bearing a continuation edge) whose bytes `answer` literally
16
- * contains. Candidates are gathered by resonating the answer's sub-regions
17
- * (breadth-first, leaves skipped, probes capped by branch count), then
18
- * confirmed by exact byte containment — a near-resonance alone never hops.
19
- *
20
- * `voiced` carries the BYTES of the anchors the grounding mechanism declared
21
- * it spoke for, and no candidate CONTAINED IN one of them may be pivoted
22
- * through. Node identity alone is too coarse a reading of "already spoken
23
- * for": the same content is interned at several scales, so a strict fragment
24
- * of a voiced anchor is a different id carrying no evidence the anchor did
25
- * not already carry. Measured on test/29 C2 — CAST voiced "William
26
- * Shakespeare" (id 676) and the pivot hopped through "speare" (id 606, not
27
- * in `consumed`) straight into that analog's own biography, which is exactly
28
- * what the comparison had refused to voice. The rule is CONTAINMENT, not
29
- * overlap, so C3's genuine further hop — "Mona Lisa", a term inside the seat
30
- * sentence but part of NEITHER analog — still fires. */
31
- export declare function pivotInto(ctx: MindContext, answer: Uint8Array, consumed: ReadonlySet<number>, voiced?: readonly Uint8Array[]): Promise<number | null>;
32
- export declare function meaningOf(ctx: MindContext, bytes: Uint8Array, anchors: ReadonlyArray<{
33
- name: string;
34
- form: Uint8Array;
35
- }>): Promise<string | null>;
@@ -1,365 +0,0 @@
1
- // resonance.ts — Pattern A: Resonance Search (Section 3 of the mind).
2
- //
3
- // Address → Resonate → filter by Traverse/Read predicates → transform.
4
- // Used by bridge, recallByResonance, pivotInto, meaningOf.
5
- // (The graded locate() matcher formerly here lives in match.ts.)
6
- import { rItem } from "./trace.js";
7
- import { cosine } from "../vec.js";
8
- import { mergeThreshold } from "../geometry.js";
9
- import { concat2, concatBytes, indexOf } from "../bytes.js";
10
- import { gistOf, read, resolve, walkTree } from "./primitives.js";
11
- import { perceive } from "./primitives.js";
12
- import { argmaxBy, argmaxCosine, candidateGist, hubBound } from "./traverse.js";
13
- import { cachedRead, junctionContainers, junctionSynonyms, walkCache, } from "./junction.js";
14
- import { recognise } from "./recognition.js";
15
- // ── The bridge — the junction between two adjacent results ──────────────────
16
- //
17
- // A GRADED evidence ladder, exact before approximate (the same discipline as
18
- // locate/alignGraded):
19
- //
20
- // 1. JUNCTION CONTAINERS by content-addressed identity. Hash-consing means
21
- // "which learnt wholes ran L and R together?" is a DAG ascent, not a
22
- // similarity guess: any deposit containing L's bytes shares L's node (or
23
- // L's canonical-window ids — position-independent identities), so
24
- // climbing parents + containment links from L and R reaches every
25
- // container exactly. The legacy resonance seed (gist of the bare
26
- // concatenation — an object never learnt) could rank the true container
27
- // out of its top-k; the ascent cannot.
28
- //
29
- // 2. EDGE JUNCTIONS. A continuation edge IS junction information: when a
30
- // learnt continuation of L contains R, the prefix before R is the learnt
31
- // glue ("what comes after L on the way to R"); symmetrically, a learnt
32
- // context of R that contains L yields its suffix after L. The legacy
33
- // bridge ignored edges entirely.
34
- //
35
- // 3. RESONANCE (the legacy path), kept as the last resort: containment
36
- // links absent or saturated, the ANN may still surface a container.
37
- //
38
- // Selection among several junctions: the response guide (ctx._edgeGuide — the
39
- // same disambiguator every projection uses) picks by gist resonance through
40
- // the session gist cache; ties prefer the SHORTEST interior (a junction
41
- // should not insert unnecessary glue), then the lowest node id
42
- // (deterministic, a property of the corpus, not the seed). An EMPTY interior
43
- // found by evidence is a confirmed adjacency — returned as such, never
44
- // confused with a miss (null).
45
- /** Rank junction candidates and return the best interior (see the module
46
- * note above for the order), or null when there are none. */
47
- function pickJunction(ctx, cands) {
48
- if (cands.length === 0)
49
- return null;
50
- if (cands.length === 1)
51
- return cands[0];
52
- const guide = ctx._edgeGuide;
53
- const scored = cands.map((c) => {
54
- const g = guide !== null ? candidateGist(ctx, c.id) : null;
55
- return { ...c, score: g !== null && guide !== null ? cosine(guide, g) : 0 };
56
- });
57
- scored.sort((a, b) => b.score - a.score ||
58
- a.interior.length - b.interior.length ||
59
- a.id - b.id);
60
- return scored[0];
61
- }
62
- /** Tier 2: junctions learnt as EDGES. A continuation of left that contains
63
- * right carries the glue as its prefix; a context of right that contains
64
- * left carries it as its suffix. Fan-outs read through the store's LIMITed
65
- * edge reads at the hub bound, like every edge walk. */
66
- function junctionEdges(ctx, left, right, maxContainer) {
67
- const bound = hubBound(ctx);
68
- const out = [];
69
- const lId = resolve(ctx, left);
70
- if (lId !== null) {
71
- // A FULL √N page of continuations means the side is an edge hub: its
72
- // fan-out is non-discriminative for a junction (the same common-content
73
- // abstention as tier 1's containment gate), and reading √N capped
74
- // continuations per pair is exactly the cost a miss must not pay.
75
- // Below the page the list IS the full fan — read exactly.
76
- const nexts = ctx.store.nextFirst(lId, bound);
77
- if (nexts.length < bound) {
78
- const cache = walkCache(ctx);
79
- for (const n of nexts) {
80
- // Prefix-capped read (same phrase-scale discipline as tier 1): a
81
- // continuation longer than any admissible container cannot carry a
82
- // junction-sized glue — skipped without reconstructing it.
83
- const b = cachedRead(ctx, cache, n, maxContainer);
84
- if (b.length > maxContainer)
85
- continue;
86
- const ri = indexOf(b, right, 0);
87
- if (ri >= 0)
88
- out.push({ id: n, interior: b.subarray(0, ri) });
89
- }
90
- }
91
- }
92
- const rId = resolve(ctx, right);
93
- if (rId !== null) {
94
- const prevs = ctx.store.prevFirst(rId, bound);
95
- if (prevs.length < bound) {
96
- const cache = walkCache(ctx);
97
- for (const p of prevs) {
98
- const b = cachedRead(ctx, cache, p, maxContainer);
99
- if (b.length > maxContainer)
100
- continue;
101
- const li = indexOf(b, left, 0);
102
- if (li >= 0) {
103
- out.push({ id: p, interior: b.subarray(li + left.length) });
104
- }
105
- }
106
- }
107
- }
108
- return out;
109
- }
110
- /** A byte string as a string, ONE code unit per byte — injective, so it is
111
- * safe to build a cache key from. Chunked to keep the spread within the
112
- * engine's argument limit on long contexts. */
113
- function latin1(b) {
114
- let s = "";
115
- for (let i = 0; i < b.length; i += 4096) {
116
- s += String.fromCharCode(...b.subarray(i, i + 4096));
117
- }
118
- return s;
119
- }
120
- /** Per-response memo of bridge results, keyed by the response's lifecycle
121
- * object (ctx.climbMemo — created fresh by respond() and nulled after, so
122
- * entries can never outlive the read-only window they are valid in). The
123
- * cover's connector pre-resolution asks for the same byte pair through up
124
- * to eight (site, answer) combinations, and fusion/CAST re-ask pairs the
125
- * cover already resolved — each unique (left, right, allowance) is walked
126
- * once per response. Outside a response (climbMemo null) nothing is
127
- * memoised, preserving standalone behaviour. */
128
- const bridgeMemo = new WeakMap();
129
- /** The connector that belongs BETWEEN two adjacent results — the graded
130
- * junction ladder described in the module note above. Returns null when
131
- * the graph holds no evidence that the two ever ran together. */
132
- export async function bridge(ctx, left, right, interiorAllowance) {
133
- if (left.length === 0 || right.length === 0)
134
- return null;
135
- let memo;
136
- let memoKey;
137
- if (ctx.climbMemo !== null) {
138
- memo = bridgeMemo.get(ctx.climbMemo);
139
- if (memo === undefined)
140
- bridgeMemo.set(ctx.climbMemo, memo = new Map());
141
- // KEYED ON BYTES, NOT ON TEXT. This key used to be built with
142
- // `decodeText`, which decodes lossily AND strips NUL — so it is not
143
- // injective on raw bytes, and a cache key that is not injective returns
144
- // one input's answer for another's. `bridge` takes arbitrary byte
145
- // strings, and this system pads with NUL, so the collision is reachable:
146
- // [65,0,66] and [65,66,0] have the same length and both decode to "AB",
147
- // giving them the same key and the same cached bridge.
148
- //
149
- // `latin1` maps each byte to exactly one code unit and is therefore
150
- // injective; both lengths are included so the two sides cannot be
151
- // confused by a shared boundary, which is what the separator was for.
152
- memoKey = `${interiorAllowance ?? -1}:${left.length}:${right.length}:` +
153
- latin1(left) + latin1(right);
154
- const hit = memo.get(memoKey);
155
- if (hit !== undefined)
156
- return hit;
157
- }
158
- const result = await bridgeUncached(ctx, left, right, interiorAllowance);
159
- if (memo !== undefined && memoKey !== undefined)
160
- memo.set(memoKey, result);
161
- return result;
162
- }
163
- async function bridgeUncached(ctx, left, right, interiorAllowance) {
164
- const joined = concat2(left, right);
165
- // The PHRASE-SCALE contract: a junction container is a learnt whole the
166
- // pair nearly exhausts. By default the glue between the two sides may be
167
- // up to W (the perceptual quantum) times the content it joins; a caller
168
- // that KNOWS its interior legitimately carries more (the n-ary connector,
169
- // whose interior holds the intermediate answers themselves) passes its own
170
- // allowance. This is what lets the identity walks read every candidate
171
- // with a hard byte cap instead of reconstructing corpus-sized deposits.
172
- const maxInterior = interiorAllowance ??
173
- (left.length + right.length) * ctx.space.maxGroup;
174
- const maxContainer = joined.length + maxInterior;
175
- // Tier 1 — junction containers, by content-addressed identity.
176
- const container = pickJunction(ctx, junctionContainers(ctx, left, right, maxContainer));
177
- if (container !== null) {
178
- ctx.trace?.step("bridge", [rItem(left, "left"), rItem(right, "right")], [rItem(container.interior, "connector", container.id)], "junction container — a learnt whole runs the two together (content-addressed ascent)");
179
- return container.interior;
180
- }
181
- // Tier 2 — junctions learnt as edges.
182
- const edge = pickJunction(ctx, junctionEdges(ctx, left, right, maxContainer));
183
- if (edge !== null) {
184
- ctx.trace?.step("bridge", [rItem(left, "left"), rItem(right, "right")], [rItem(edge.interior, "connector", edge.id)], "edge junction — a learnt continuation/context carries the glue between the two");
185
- return edge.interior;
186
- }
187
- // Tier 2.5 — synonym junctions: the content-addressed container search
188
- // applied to halo siblings of left/right. Container evidence is exact
189
- // (same DAG ascent as tier 1, with window-id-enhanced seeds); the
190
- // relaxation is only in which form occupies one side.
191
- const synonym = pickJunction(ctx, await junctionSynonyms(ctx, left, right, maxInterior));
192
- if (synonym !== null) {
193
- ctx.trace?.step("bridge", [rItem(left, "left"), rItem(right, "right")], [rItem(synonym.interior, "connector", synonym.id)], "synonym junction — a halo sibling of one answer runs together with the other in a learnt whole");
194
- return synonym.interior;
195
- }
196
- // Tier 3 — the legacy resonance path (approximate, last resort).
197
- const hits = await ctx.store.resonate(gistOf(ctx, joined), ctx.cfg.recallQueryK * 2);
198
- // `hits` arrive nearest-first, so the first containment-passing hit is also
199
- // the best-scoring container — no further evidence comparison is needed.
200
- for (const h of hits) {
201
- // Same phrase-scale cap as the identity tiers: a hit longer than any
202
- // admissible container is skipped without reconstructing it.
203
- const f = read(ctx, h.id, maxContainer + 1);
204
- if (f.length > maxContainer)
205
- continue;
206
- if (f.length <= joined.length)
207
- continue; // no room for a connector
208
- const li = indexOf(f, left, 0);
209
- if (li < 0)
210
- continue;
211
- const ri = indexOf(f, right, li + left.length);
212
- if (ri < 0)
213
- continue;
214
- ctx.trace?.step("bridge", [rItem(left, "left"), rItem(right, "right")], [rItem(f.subarray(li + left.length, ri), "connector", h.id)], "resonant container — found by whole-gist resonance (approximate fallback)");
215
- return f.subarray(li + left.length, ri);
216
- }
217
- return null;
218
- }
219
- /** Join two spans with the learnt connector between them, when one exists —
220
- * the composition step every out-of-search assembly (multi-topic fusion,
221
- * CAST's substitution and comparison) shares. A miss joins the pieces BARE
222
- * and is never silent: it emits the same `bridgeMiss` trace step everywhere,
223
- * so a degraded join is visible in the rationale regardless of which
224
- * mechanism paid it. (The in-search connector splice in graph-search.ts is
225
- * the same concept inside the deduction, where the join is a costed rule.) */
226
- export async function joinWithBridge(ctx, left, right) {
227
- const link = await bridge(ctx, left, right);
228
- if (link === null) {
229
- ctx.trace?.step("bridgeMiss", [rItem(left, "left"), rItem(right, "right")], [], "no learnt connector resonated between these pieces — concatenated bare");
230
- return concat2(left, right);
231
- }
232
- return concatBytes([left, link, right]);
233
- }
234
- /** The pivot a produced answer bridges through: the longest UNCONSUMED learnt
235
- * CONTEXT (a node bearing a continuation edge) whose bytes `answer` literally
236
- * contains. Candidates are gathered by resonating the answer's sub-regions
237
- * (breadth-first, leaves skipped, probes capped by branch count), then
238
- * confirmed by exact byte containment — a near-resonance alone never hops.
239
- *
240
- * `voiced` carries the BYTES of the anchors the grounding mechanism declared
241
- * it spoke for, and no candidate CONTAINED IN one of them may be pivoted
242
- * through. Node identity alone is too coarse a reading of "already spoken
243
- * for": the same content is interned at several scales, so a strict fragment
244
- * of a voiced anchor is a different id carrying no evidence the anchor did
245
- * not already carry. Measured on test/29 C2 — CAST voiced "William
246
- * Shakespeare" (id 676) and the pivot hopped through "speare" (id 606, not
247
- * in `consumed`) straight into that analog's own biography, which is exactly
248
- * what the comparison had refused to voice. The rule is CONTAINMENT, not
249
- * overlap, so C3's genuine further hop — "Mona Lisa", a term inside the seat
250
- * sentence but part of NEITHER analog — still fires. */
251
- export async function pivotInto(ctx, answer, consumed, voiced = []) {
252
- const k = ctx.cfg.recallQueryK;
253
- // ONE perception of the answer, shared by the probe budget and the walk —
254
- // this used to fold the same bytes twice, back to back, on every hop.
255
- const tree = perceive(ctx, answer);
256
- // Probe budget: one per branch node, CAPPED at k. The sweep is a
257
- // resonance-shortlist question ("which learnt contexts does this answer
258
- // contain?"), so it carries the same k budget every resonance read does —
259
- // an answer's branch count grows with its length, and probing every
260
- // branch of a long answer made the pivot sweep the dominant ANN cost of
261
- // multi-hop reasoning at corpus scale (profiled: ~150 ANN queries per
262
- // response on conversation-length answers). Breadth-first order means
263
- // the k probes spent are the LARGEST regions — the ones that name learnt
264
- // contexts; and recognition below still contributes every exact,
265
- // content-addressed containment candidate regardless of the probe budget,
266
- // so short answers (branchCount ≤ k) keep the identical exhaustive sweep.
267
- let branchCount = 0;
268
- walkTree(tree, 0, (n) => {
269
- if (n.kids !== null)
270
- branchCount++;
271
- });
272
- const probeCap = Math.min(branchCount, k);
273
- const scored = new Map();
274
- const queue = [tree];
275
- let probes = 0;
276
- while (queue.length > 0 && probes < probeCap) {
277
- const n = queue.shift();
278
- if (n.kids === null)
279
- continue; // a leaf never names a learnt context
280
- probes++;
281
- for (const hit of await ctx.store.resonate(n.v, k)) {
282
- if (!consumed.has(hit.id) && ctx.store.hasNext(hit.id)) {
283
- const prev = scored.get(hit.id) ?? 0;
284
- if (hit.score > prev)
285
- scored.set(hit.id, hit.score);
286
- }
287
- }
288
- for (const c of n.kids)
289
- queue.push(c); // breadth-first: larger regions first
290
- }
291
- const rec = recognise(ctx, answer);
292
- for (const s of rec.sites) {
293
- if (!consumed.has(s.payload) && ctx.store.hasNext(s.payload)) {
294
- scored.set(s.payload, Math.max(scored.get(s.payload) ?? 0, 1));
295
- }
296
- }
297
- // Byte containment, longest wins — the answer literally contains the
298
- // pivot's bytes, and the biggest well-evidenced span is the real pivot.
299
- const found = argmaxBy(scored.keys(), (id) => {
300
- // A PIVOT MUST BE A THING THE CORPUS DEPOSITED, NOT A PIECE OF ONE.
301
- // "Longest wins" ranks candidates but never asks whether the winner is
302
- // an entity at all, and by the time a chain reaches here `consumeAll`
303
- // has taken the answer's real contexts — so on a corpus of
304
- // near-identical records the field is left to whatever interned
305
- // fragments remain. Measured on a 200-line templated log corpus, query
306
- // "what happened to request_id=1042 and request_id=1077?": CAST
307
- // produced the correct comparison and one `pivotStep` replaced it
308
- // wholesale, pivoting through `s=70` — a four-byte tail of
309
- // `latency_ms=70` — onto an unrelated record (`handled 1130`).
310
- //
311
- // The separator is NOT length. Measured against the multi-hop tests'
312
- // own pivots: `Paris` (5 bytes), `Jupiter` (7), `lithium` (7), `Mona
313
- // Lisa` (9) against junk `s=70` (4) — a two-quantum floor, which
314
- // confluence.ts applies to a meet for the same "one window is not an
315
- // entity" reason, discards three of the four legitimate pivots.
316
- // Entities are simply short.
317
- //
318
- // What separates them is STRUCTURAL, and the store already holds it:
319
- //
320
- // s=70 parents 2 containers 1 prevCount 0 halo no
321
- // Paris parents 0 containers 0 prevCount 1 halo yes
322
- // Jupiter parents 0 containers 0 prevCount 1 halo yes
323
- // lithium parents 0 containers 0 prevCount 1 halo yes
324
- // Mona Lisa parents 0 containers 0 prevCount 1 halo yes
325
- //
326
- // A deposited whole — a context or an answer — is interned in its own
327
- // right and has neither structural parents nor containment links. A
328
- // fragment is addressable ONLY because window interning made its span
329
- // addressable inside something bigger, and that containment is exactly
330
- // what `parents`/`containers` record. Reasoning steps THROUGH a fact;
331
- // a span that was never a fact on its own is not one to step through.
332
- // No constant enters — it is a structural predicate, not a threshold.
333
- if (ctx.store.hasParents(id) || ctx.store.hasContainers(id)) {
334
- return -Infinity;
335
- }
336
- const bytes = read(ctx, id);
337
- if (indexOf(answer, bytes, 0) < 0)
338
- return -Infinity;
339
- for (const v of voiced)
340
- if (indexOf(v, bytes, 0) >= 0)
341
- return -Infinity;
342
- return bytes.length;
343
- }, 0, true);
344
- return found?.item ?? null;
345
- }
346
- /** Which of the given labelled forms a span MEANS — generic resonance over
347
- * perceived gists. Each anchor form's gist is memoised; the span's gist
348
- * is matched against them. Returns null when nothing resonates closely
349
- * enough — the caller declines rather than guessing. */
350
- const anchorGists = new WeakMap();
351
- export async function meaningOf(ctx, bytes, anchors) {
352
- if (bytes.length === 0 || anchors.length === 0)
353
- return null;
354
- let gists = anchorGists.get(anchors);
355
- if (!gists) {
356
- gists = anchors.map((a) => ({
357
- name: a.name,
358
- v: gistOf(ctx, a.form),
359
- }));
360
- anchorGists.set(anchors, gists);
361
- }
362
- const qv = gistOf(ctx, bytes);
363
- const found = argmaxCosine(qv, gists, (g) => g.v, mergeThreshold(ctx.store.D));
364
- return found?.item.name ?? null;
365
- }
@@ -1,15 +0,0 @@
1
- import type { MindContext } from "./types.js";
2
- import type { DerivationStep } from "./graph-search.js";
3
- import type { RationaleItem } from "./rationale.js";
4
- export declare function rItem(bytes: Uint8Array, role?: string, node?: number, span?: [number, number]): RationaleItem;
5
- export declare function rNode(ctx: MindContext, id: number, role?: string, score?: number): RationaleItem;
6
- export declare function rDeriv(ctx: MindContext, it: DerivationStep["conclusion"], role?: string): RationaleItem;
7
- /** The standard FALL-THROUGH closer every self-gating mechanism ends with:
8
- * close the open scope with no outputs and the reason, and return null so
9
- * the caller can `return fail("…")` in one expression. `t` is the scope an
10
- * enclosing `ctx.trace?.enter(...)` returned (undefined when not tracing). */
11
- export declare function traceFail(t: {
12
- done(outputs: RationaleItem[], note?: string): void;
13
- } | undefined): (note: string) => null;
14
- export declare const MOVE_NOTE: Record<string, string>;
15
- export declare function traceDerivation(ctx: MindContext, steps: ReadonlyArray<DerivationStep>): void;
@@ -1,73 +0,0 @@
1
- // trace.ts — trace instrumentation + persistence (Section 9 of the mind).
2
- //
3
- // rItem, rNode, rDeriv — build RationaleItems from bytes/nodes/derivations
4
- // traceDerivation — trace a full derivation proof tree
5
- // MOVE_NOTE — human-readable names for each derivation move
6
- import { read } from "./primitives.js";
7
- import { decodeText } from "./rationale.js";
8
- export function rItem(bytes, role, node, span) {
9
- return {
10
- text: decodeText(bytes),
11
- role,
12
- node: node ?? undefined,
13
- span,
14
- };
15
- }
16
- export function rNode(ctx, id, role, score) {
17
- return {
18
- text: decodeText(read(ctx, id)),
19
- node: id,
20
- role,
21
- score,
22
- };
23
- }
24
- export function rDeriv(ctx, it, role) {
25
- const text = it.bytes
26
- ? decodeText(it.bytes)
27
- : it.node !== undefined
28
- ? decodeText(read(ctx, it.node))
29
- : it.kind === "cover"
30
- ? `cover@${it.span[0]}`
31
- : `[${it.span[0]},${it.span[1]})`;
32
- return { text, role: role ?? it.kind, node: it.node, span: it.span };
33
- }
34
- /** The standard FALL-THROUGH closer every self-gating mechanism ends with:
35
- * close the open scope with no outputs and the reason, and return null so
36
- * the caller can `return fail("…")` in one expression. `t` is the scope an
37
- * enclosing `ctx.trace?.enter(...)` returned (undefined when not tracing). */
38
- export function traceFail(t) {
39
- return (note) => {
40
- t?.done([], note);
41
- return null;
42
- };
43
- }
44
- export const MOVE_NOTE = {
45
- "follow-edge": "follow a learned continuation edge — 'what follows what'",
46
- "concept-hop": "jump a concept (halo) link — a synonym's edge",
47
- "voice": "emit the asker's own wording for this form (articulation)",
48
- "ground": "a chain reached its terminal answer",
49
- "splice-connector": "splice a learnt connector between two rewrites",
50
- "split": "cut a span at a sub-leaf form boundary so a form can be reached",
51
- "fuse": "fuse adjacent fragments toward a deeper learned form",
52
- "recompose": "recompose fused parts into a learned whole that leads on",
53
- "bridge": "advance the cover frontier across this span",
54
- "pool-vote": "pool independent regions' evidence for a shared anchor (sum, not shortest path)",
55
- "axiom": "a seed: a perceived leaf, recognised form, or computed result",
56
- "step": "a derivation step",
57
- };
58
- export function traceDerivation(ctx, steps) {
59
- const t = ctx.trace;
60
- if (!t)
61
- return;
62
- const indexOfOrder = new Map();
63
- for (const s of steps) {
64
- const note = MOVE_NOTE[s.move] ?? s.move;
65
- const deps = s.producers
66
- .map((o) => indexOfOrder.get(o))
67
- .filter((x) => x !== undefined);
68
- const premises = s.premises.map((p) => rDeriv(ctx, p));
69
- const conclusion = [rDeriv(ctx, s.conclusion)];
70
- const index = t.step(s.move, premises, conclusion, s.cost > 0 ? `${note} (cost ${s.cost})` : note, deps.length > 0 ? deps : undefined);
71
- indexOfOrder.set(s.order, index);
72
- }
73
- }