@hviana/sema 0.1.5 → 0.1.6

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 (160) hide show
  1. package/AGENTS.md +6 -5
  2. package/CITATION.cff +49 -0
  3. package/HOW_IT_WORKS.md +11 -12
  4. package/README.md +7 -5
  5. package/dist/example/demo.js +25 -25
  6. package/dist/example/train_base.d.ts +19 -21
  7. package/dist/example/train_base.js +1687 -1952
  8. package/dist/src/alphabet.d.ts +3 -3
  9. package/dist/src/alphabet.js +24 -27
  10. package/dist/src/alu/src/alu.d.ts +169 -194
  11. package/dist/src/alu/src/alu.js +374 -414
  12. package/dist/src/alu/src/expr.d.ts +36 -43
  13. package/dist/src/alu/src/expr.js +252 -278
  14. package/dist/src/alu/src/index.d.ts +9 -98
  15. package/dist/src/alu/src/index.js +10 -64
  16. package/dist/src/alu/src/kernel-arith.d.ts +1 -5
  17. package/dist/src/alu/src/kernel-arith.js +195 -285
  18. package/dist/src/alu/src/kernel-bits.d.ts +1 -5
  19. package/dist/src/alu/src/kernel-bits.js +81 -115
  20. package/dist/src/alu/src/kernel-logic.js +33 -63
  21. package/dist/src/alu/src/kernel-nd.js +155 -195
  22. package/dist/src/alu/src/kernel-numeric.d.ts +16 -80
  23. package/dist/src/alu/src/kernel-numeric.js +259 -331
  24. package/dist/src/alu/src/operation.d.ts +112 -132
  25. package/dist/src/alu/src/operation.js +149 -163
  26. package/dist/src/alu/src/parser.d.ts +168 -175
  27. package/dist/src/alu/src/parser.js +382 -421
  28. package/dist/src/alu/src/resonance.d.ts +16 -25
  29. package/dist/src/alu/src/resonance.js +49 -56
  30. package/dist/src/alu/src/text.d.ts +3 -7
  31. package/dist/src/alu/src/text.js +31 -37
  32. package/dist/src/alu/src/value.d.ts +14 -14
  33. package/dist/src/alu/src/value.js +150 -160
  34. package/dist/src/alu/test/alu.test.js +543 -656
  35. package/dist/src/bytes.d.ts +1 -5
  36. package/dist/src/bytes.js +33 -40
  37. package/dist/src/config.d.ts +99 -102
  38. package/dist/src/config.js +78 -83
  39. package/dist/src/derive/src/deduction.d.ts +60 -62
  40. package/dist/src/derive/src/deduction.js +103 -109
  41. package/dist/src/derive/src/index.d.ts +1 -7
  42. package/dist/src/derive/src/priority-queue.d.ts +8 -8
  43. package/dist/src/derive/src/priority-queue.js +57 -61
  44. package/dist/src/derive/src/rewrite.d.ts +15 -18
  45. package/dist/src/derive/src/rewrite.js +59 -67
  46. package/dist/src/derive/src/trie.d.ts +56 -56
  47. package/dist/src/derive/src/trie.js +175 -179
  48. package/dist/src/derive/test/derive.test.js +96 -100
  49. package/dist/src/extension.d.ts +13 -16
  50. package/dist/src/geometry.d.ts +17 -42
  51. package/dist/src/geometry.js +235 -266
  52. package/dist/src/index.d.ts +2 -17
  53. package/dist/src/index.js +2 -12
  54. package/dist/src/ingest-cache.d.ts +25 -30
  55. package/dist/src/ingest-cache.js +108 -127
  56. package/dist/src/mind/articulation.d.ts +1 -5
  57. package/dist/src/mind/articulation.js +77 -112
  58. package/dist/src/mind/attention.d.ts +40 -108
  59. package/dist/src/mind/attention.js +749 -871
  60. package/dist/src/mind/canonical.d.ts +4 -19
  61. package/dist/src/mind/canonical.js +27 -31
  62. package/dist/src/mind/graph-search.d.ts +201 -225
  63. package/dist/src/mind/graph-search.js +742 -821
  64. package/dist/src/mind/index.d.ts +2 -10
  65. package/dist/src/mind/junction.d.ts +31 -58
  66. package/dist/src/mind/junction.js +172 -237
  67. package/dist/src/mind/learning.d.ts +16 -52
  68. package/dist/src/mind/learning.js +143 -165
  69. package/dist/src/mind/match.d.ts +20 -69
  70. package/dist/src/mind/match.js +259 -318
  71. package/dist/src/mind/mechanisms/alu.js +16 -16
  72. package/dist/src/mind/mechanisms/cast.d.ts +9 -13
  73. package/dist/src/mind/mechanisms/cast.js +363 -456
  74. package/dist/src/mind/mechanisms/confluence.d.ts +8 -12
  75. package/dist/src/mind/mechanisms/confluence.js +152 -183
  76. package/dist/src/mind/mechanisms/cover.d.ts +2 -8
  77. package/dist/src/mind/mechanisms/cover.js +148 -210
  78. package/dist/src/mind/mechanisms/extraction.d.ts +8 -34
  79. package/dist/src/mind/mechanisms/extraction.js +234 -288
  80. package/dist/src/mind/mechanisms/recall.d.ts +6 -10
  81. package/dist/src/mind/mechanisms/recall.js +126 -185
  82. package/dist/src/mind/mind.d.ts +129 -154
  83. package/dist/src/mind/mind.js +258 -288
  84. package/dist/src/mind/pipeline-mechanism.d.ts +112 -124
  85. package/dist/src/mind/pipeline-mechanism.js +161 -172
  86. package/dist/src/mind/pipeline.d.ts +4 -14
  87. package/dist/src/mind/pipeline.js +125 -189
  88. package/dist/src/mind/primitives.d.ts +8 -32
  89. package/dist/src/mind/primitives.js +99 -117
  90. package/dist/src/mind/rationale.d.ts +86 -98
  91. package/dist/src/mind/rationale.js +113 -121
  92. package/dist/src/mind/reasoning.d.ts +2 -13
  93. package/dist/src/mind/reasoning.js +129 -166
  94. package/dist/src/mind/recognition.d.ts +1 -4
  95. package/dist/src/mind/recognition.js +183 -208
  96. package/dist/src/mind/resonance.d.ts +5 -22
  97. package/dist/src/mind/resonance.js +0 -0
  98. package/dist/src/mind/trace.d.ts +6 -25
  99. package/dist/src/mind/trace.js +50 -58
  100. package/dist/src/mind/traverse.d.ts +16 -58
  101. package/dist/src/mind/traverse.js +304 -357
  102. package/dist/src/mind/types.d.ts +120 -127
  103. package/dist/src/mind/types.js +60 -69
  104. package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
  105. package/dist/src/rabitq-ivf/src/database.js +201 -0
  106. package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
  107. package/dist/src/{rabitq-hnsw → rabitq-ivf}/src/index.js +1 -3
  108. package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
  109. package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
  110. package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
  111. package/dist/src/rabitq-ivf/src/prng.js +36 -0
  112. package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
  113. package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
  114. package/dist/src/sema.d.ts +9 -13
  115. package/dist/src/sema.js +26 -40
  116. package/dist/src/store-sqlite.d.ts +169 -166
  117. package/dist/src/store-sqlite.js +762 -662
  118. package/dist/src/store.d.ts +586 -630
  119. package/dist/src/store.js +1423 -1581
  120. package/dist/src/vec.d.ts +5 -9
  121. package/dist/src/vec.js +61 -73
  122. package/example/train_base.ts +13 -10
  123. package/package.json +1 -1
  124. package/src/alu/README.md +1 -1
  125. package/src/alu/src/index.ts +1 -1
  126. package/src/config.ts +19 -27
  127. package/src/index.ts +6 -11
  128. package/src/rabitq-ivf/README.md +56 -0
  129. package/src/rabitq-ivf/src/database.ts +276 -0
  130. package/src/{rabitq-hnsw → rabitq-ivf}/src/index.ts +2 -5
  131. package/src/rabitq-ivf/src/ivf.ts +1330 -0
  132. package/src/{rabitq-hnsw → rabitq-ivf}/src/prng.ts +1 -1
  133. package/src/store-sqlite.ts +196 -9
  134. package/src/store.ts +8 -32
  135. package/test/08-storage.test.mjs +3 -3
  136. package/test/14-scaling.test.mjs +2 -2
  137. package/test/35-ivf.test.mjs +263 -0
  138. package/test/36-bloom.test.mjs +123 -0
  139. package/dist/src/rabitq-hnsw/src/database.d.ts +0 -202
  140. package/dist/src/rabitq-hnsw/src/database.js +0 -405
  141. package/dist/src/rabitq-hnsw/src/heap.d.ts +0 -22
  142. package/dist/src/rabitq-hnsw/src/heap.js +0 -94
  143. package/dist/src/rabitq-hnsw/src/hnsw.d.ts +0 -125
  144. package/dist/src/rabitq-hnsw/src/hnsw.js +0 -500
  145. package/dist/src/rabitq-hnsw/src/index.d.ts +0 -15
  146. package/dist/src/rabitq-hnsw/src/prng.d.ts +0 -19
  147. package/dist/src/rabitq-hnsw/src/prng.js +0 -38
  148. package/dist/src/rabitq-hnsw/src/rabitq.d.ts +0 -95
  149. package/dist/src/rabitq-hnsw/src/rabitq.js +0 -299
  150. package/dist/src/rabitq-hnsw/src/store.d.ts +0 -162
  151. package/dist/src/rabitq-hnsw/src/store.js +0 -916
  152. package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +0 -1
  153. package/dist/src/rabitq-hnsw/test/hnsw.test.js +0 -1197
  154. package/src/rabitq-hnsw/README.md +0 -303
  155. package/src/rabitq-hnsw/src/database.ts +0 -492
  156. package/src/rabitq-hnsw/src/heap.ts +0 -90
  157. package/src/rabitq-hnsw/src/hnsw.ts +0 -514
  158. package/src/rabitq-hnsw/src/store.ts +0 -994
  159. package/src/rabitq-hnsw/test/hnsw.test.ts +0 -1213
  160. /package/src/{rabitq-hnsw → rabitq-ivf}/src/rabitq.ts +0 -0
@@ -6,13 +6,13 @@ import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
6
6
  * matches and one meet, STEP each). `used` carries the pair's exemplar
7
7
  * anchors so the reasoning stage does not re-speak them. */
8
8
  export interface JoinResult {
9
- bytes: Uint8Array;
10
- used: ReadonlySet<number>;
11
- accounted: Array<[number, number]>;
12
- moves: number;
13
- /** A human-readable label for the query bytes the meet left unexplained —
14
- * purely diagnostic, never priced. */
15
- unexplained: string;
9
+ bytes: Uint8Array;
10
+ used: ReadonlySet<number>;
11
+ accounted: Array<[number, number]>;
12
+ moves: number;
13
+ /** A human-readable label for the query bytes the meet left unexplained —
14
+ * purely diagnostic, never priced. */
15
+ unexplained: string;
16
16
  }
17
17
  /** The main confluence entry point. Given a query, detect whether it weaves
18
18
  * two or more INDEPENDENT constraints (ranked anchors supported by disjoint
@@ -20,9 +20,5 @@ export interface JoinResult {
20
20
  * identity, and return the discriminative content the streams share — the
21
21
  * entity that satisfies all constraints at once. Null when the query is
22
22
  * not conjunctive or nothing lies in the intersection. */
23
- export declare function confluenceJoin(
24
- ctx: MindContext,
25
- query: Uint8Array,
26
- pre: Precomputed,
27
- ): Promise<JoinResult | null>;
23
+ export declare function confluenceJoin(ctx: MindContext, query: Uint8Array, pre: Precomputed): Promise<JoinResult | null>;
28
24
  export declare const confluenceMechanism: PipelineMechanism;
@@ -51,194 +51,163 @@ import { rItem, rNode } from "../trace.js";
51
51
  * entity that satisfies all constraints at once. Null when the query is
52
52
  * not conjunctive or nothing lies in the intersection. */
53
53
  export async function confluenceJoin(ctx, query, pre) {
54
- const W = ctx.space.maxGroup;
55
- if (query.length < 2 * W || ctx.store.edgeSourceCount() === 0) {
56
- return null;
57
- }
58
- const { ranked } = await pre.attention();
59
- if (ranked.length < 2) {
60
- return null;
61
- }
62
- const N = corpusN(ctx);
63
- // Response-scoped shared memos: the anchor-window identities and the
64
- // structural-IDF reach live on Precomputed, so any other identity-based
65
- // mechanism in the same response reuses them.
66
- const reachMemo = pre.reachMemo;
67
- const windowsOfAnchor = (anchor) => pre.windowsOf(anchor);
68
- // The query's own window identities, offset id (the canonical
69
- // content-addressed read, canonical.windowIds): whatever the meet shares
70
- // with the query is the CONSTRAINT being re-named (or its scaffolding),
71
- // never the open seat the question asks for — subtracted by identity,
72
- // below.
73
- const queryWin = pre.queryWindows;
74
- const queryIds = new Set(queryWin.values());
75
- const streams = [];
76
- const rankedCapped = ranked.length > pre.k ? ranked.slice(0, pre.k) : ranked;
77
- for (const cand of rankedCapped) {
78
- if (streams.some((s) => s.anchor === cand.anchor)) {
79
- continue;
80
- }
81
- const ids = new Set(windowsOfAnchor(cand.anchor).values());
82
- if (ids.size === 0) {
83
- continue;
84
- }
85
- const cover = [];
86
- const held = [];
87
- let curC = null;
88
- let curH = null;
89
- for (const [off, wid] of queryWin) {
90
- if (!ids.has(wid)) {
91
- continue;
92
- }
93
- if (curH !== null && off <= curH[1]) {
94
- curH[1] = off + W;
95
- } else {
96
- held.push(curH = [off, off + W]);
97
- }
98
- if (dominates(reachOf(ctx, wid, N, reachMemo), N)) {
99
- continue; // scaffolding never binds
100
- }
101
- if (curC !== null && off <= curC[1]) {
102
- curC[1] = off + W;
103
- } else {
104
- cover.push(curC = [off, off + W]);
105
- }
106
- }
107
- if (cover.length > 0) {
108
- streams.push({ anchor: cand.anchor, vote: cand.vote, ids, cover, held });
109
- }
110
- }
111
- if (streams.length < 2) {
112
- return null;
113
- }
114
- // Two streams are INDEPENDENT constraints when the query content they
115
- // hold is disjoint — each answers a different part of what was asked.
116
- const disjoint = (a, b) =>
117
- a.cover.every(([as, ae]) =>
118
- b.cover.every(([bs, be]) => be <= as || bs >= ae)
119
- );
120
- let met = null;
121
- for (let i = 0; i < streams.length; i++) {
122
- for (let j = i + 1; j < streams.length; j++) {
123
- const a = streams[i];
124
- const b = streams[j];
125
- if (!disjoint(a, b)) {
126
- continue;
127
- }
128
- const wa = windowsOfAnchor(a.anchor);
129
- const wb = b.ids;
130
- // ── The MEET: in both anchors, not in the query ────────────────────
131
- // Offsets of A whose window id is shared with B and absent from the
132
- // query — merged into maximal contiguous spans (windows overlap, so
133
- // consecutive shared offsets weave one span).
134
- const spans = [];
135
- let cur = null;
136
- for (const [off, wid] of wa) {
137
- const inMeet = wb.has(wid) && !queryIds.has(wid);
138
- if (inMeet) {
139
- if (cur !== null && off <= cur[1]) {
140
- cur[1] = off + W;
141
- } else {
142
- spans.push(cur = [off, off + W]);
143
- }
144
- }
145
- }
146
- if (spans.length === 0) {
147
- continue;
148
- }
149
- const aBytes = read(ctx, a.anchor);
150
- for (const [s, e] of spans) {
151
- // Scaffolding gate: the span's MOST discriminative window decides.
152
- // Content reaching a corpus MAJORITY of contexts discriminates
153
- // nothing (the same half-dominance convention every wrapper test
154
- // uses); the query-subtraction above already removed everything the
155
- // question names, so what survives here is a genuine open-seat
156
- // entity.
157
- let reach = Infinity;
158
- for (let off = s; off + W <= e; off++) {
159
- const wid = wa.get(off);
160
- if (wid !== undefined && wb.has(wid) && !queryIds.has(wid)) {
161
- reach = Math.min(reach, reachOf(ctx, wid, N, reachMemo));
162
- }
54
+ const W = ctx.space.maxGroup;
55
+ if (query.length < 2 * W || ctx.store.edgeSourceCount() === 0)
56
+ return null;
57
+ const { ranked } = await pre.attention();
58
+ if (ranked.length < 2)
59
+ return null;
60
+ const N = corpusN(ctx);
61
+ // Response-scoped shared memos: the anchor-window identities and the
62
+ // structural-IDF reach live on Precomputed, so any other identity-based
63
+ // mechanism in the same response reuses them.
64
+ const reachMemo = pre.reachMemo;
65
+ const windowsOfAnchor = (anchor) => pre.windowsOf(anchor);
66
+ // The query's own window identities, offset → id (the canonical
67
+ // content-addressed read, canonical.windowIds): whatever the meet shares
68
+ // with the query is the CONSTRAINT being re-named (or its scaffolding),
69
+ // never the open seat the question asks for — subtracted by identity,
70
+ // below.
71
+ const queryWin = pre.queryWindows;
72
+ const queryIds = new Set(queryWin.values());
73
+ const streams = [];
74
+ const rankedCapped = ranked.length > pre.k ? ranked.slice(0, pre.k) : ranked;
75
+ for (const cand of rankedCapped) {
76
+ if (streams.some((s) => s.anchor === cand.anchor))
77
+ continue;
78
+ const ids = new Set(windowsOfAnchor(cand.anchor).values());
79
+ if (ids.size === 0)
80
+ continue;
81
+ const cover = [];
82
+ const held = [];
83
+ let curC = null;
84
+ let curH = null;
85
+ for (const [off, wid] of queryWin) {
86
+ if (!ids.has(wid))
87
+ continue;
88
+ if (curH !== null && off <= curH[1])
89
+ curH[1] = off + W;
90
+ else
91
+ held.push(curH = [off, off + W]);
92
+ if (dominates(reachOf(ctx, wid, N, reachMemo), N))
93
+ continue; // scaffolding never binds
94
+ if (curC !== null && off <= curC[1])
95
+ curC[1] = off + W;
96
+ else
97
+ cover.push(curC = [off, off + W]);
163
98
  }
164
- if (!isFinite(reach) || dominates(reach, N)) {
165
- continue;
99
+ if (cover.length > 0) {
100
+ streams.push({ anchor: cand.anchor, vote: cand.vote, ids, cover, held });
166
101
  }
167
- const len = e - s;
168
- if (
169
- met === null || reach < met.reach ||
170
- (reach === met.reach && len > met.len)
171
- ) {
172
- met = { bytes: aBytes.subarray(s, e), reach, len, a, b };
102
+ }
103
+ if (streams.length < 2)
104
+ return null;
105
+ // Two streams are INDEPENDENT constraints when the query content they
106
+ // hold is disjoint — each answers a different part of what was asked.
107
+ const disjoint = (a, b) => a.cover.every(([as, ae]) => b.cover.every(([bs, be]) => be <= as || bs >= ae));
108
+ let met = null;
109
+ for (let i = 0; i < streams.length; i++) {
110
+ for (let j = i + 1; j < streams.length; j++) {
111
+ const a = streams[i];
112
+ const b = streams[j];
113
+ if (!disjoint(a, b))
114
+ continue;
115
+ const wa = windowsOfAnchor(a.anchor);
116
+ const wb = b.ids;
117
+ // ── The MEET: in both anchors, not in the query ────────────────────
118
+ // Offsets of A whose window id is shared with B and absent from the
119
+ // query — merged into maximal contiguous spans (windows overlap, so
120
+ // consecutive shared offsets weave one span).
121
+ const spans = [];
122
+ let cur = null;
123
+ for (const [off, wid] of wa) {
124
+ const inMeet = wb.has(wid) && !queryIds.has(wid);
125
+ if (inMeet) {
126
+ if (cur !== null && off <= cur[1])
127
+ cur[1] = off + W;
128
+ else
129
+ spans.push(cur = [off, off + W]);
130
+ }
131
+ }
132
+ if (spans.length === 0)
133
+ continue;
134
+ const aBytes = read(ctx, a.anchor);
135
+ for (const [s, e] of spans) {
136
+ // Scaffolding gate: the span's MOST discriminative window decides.
137
+ // Content reaching a corpus MAJORITY of contexts discriminates
138
+ // nothing (the same half-dominance convention every wrapper test
139
+ // uses); the query-subtraction above already removed everything the
140
+ // question names, so what survives here is a genuine open-seat
141
+ // entity.
142
+ let reach = Infinity;
143
+ for (let off = s; off + W <= e; off++) {
144
+ const wid = wa.get(off);
145
+ if (wid !== undefined && wb.has(wid) && !queryIds.has(wid)) {
146
+ reach = Math.min(reach, reachOf(ctx, wid, N, reachMemo));
147
+ }
148
+ }
149
+ if (!isFinite(reach) || dominates(reach, N))
150
+ continue;
151
+ const len = e - s;
152
+ if (met === null || reach < met.reach ||
153
+ (reach === met.reach && len > met.len)) {
154
+ met = { bytes: aBytes.subarray(s, e), reach, len, a, b };
155
+ }
156
+ }
173
157
  }
174
- }
175
158
  }
176
- }
177
- if (met === null) {
178
- return null;
179
- }
180
- const t = ctx.trace?.enter("confluence", [rItem(query, "query")]);
181
- ctx.trace?.step(
182
- "intersectEvidence",
183
- [
184
- rNode(ctx, met.a.anchor, "constraint", met.a.vote),
185
- rNode(ctx, met.b.anchor, "constraint", met.b.vote),
186
- ],
187
- [rItem(met.bytes, "meet")],
188
- `the discriminative content BOTH constraints' evidence shares, by content-addressed identity (reach ${met.reach} of ${N} contexts)`,
189
- );
190
- t?.done(
191
- [rItem(met.bytes, "answer")],
192
- "conjunctive join — the entity where the independent evidence streams meet",
193
- );
194
- // Evidence: the query spans whose content the two streams hold by
195
- // identity (scaffolding included — held, not just the binding cover);
196
- // the acts were two constraint matches and one meet.
197
- const accounted = [
198
- ...met.a.held,
199
- ...met.b.held,
200
- ];
201
- return {
202
- bytes: met.bytes,
203
- used: new Set([met.a.anchor, met.b.anchor]),
204
- accounted,
205
- moves: 3 * STEP,
206
- unexplained: unexplainedLabel(query, accounted),
207
- };
159
+ if (met === null)
160
+ return null;
161
+ const t = ctx.trace?.enter("confluence", [rItem(query, "query")]);
162
+ ctx.trace?.step("intersectEvidence", [
163
+ rNode(ctx, met.a.anchor, "constraint", met.a.vote),
164
+ rNode(ctx, met.b.anchor, "constraint", met.b.vote),
165
+ ], [rItem(met.bytes, "meet")], `the discriminative content BOTH constraints' evidence shares, by content-addressed identity (reach ${met.reach} of ${N} contexts)`);
166
+ t?.done([rItem(met.bytes, "answer")], "conjunctive join — the entity where the independent evidence streams meet");
167
+ // Evidence: the query spans whose content the two streams hold by
168
+ // identity (scaffolding included — held, not just the binding cover);
169
+ // the acts were two constraint matches and one meet.
170
+ const accounted = [
171
+ ...met.a.held,
172
+ ...met.b.held,
173
+ ];
174
+ return {
175
+ bytes: met.bytes,
176
+ used: new Set([met.a.anchor, met.b.anchor]),
177
+ accounted,
178
+ moves: 3 * STEP,
179
+ unexplained: unexplainedLabel(query, accounted),
180
+ };
208
181
  }
209
182
  // ── Pipeline mechanism ──────────────────────────────────────────────────────
210
183
  export const confluenceMechanism = {
211
- name: "confluence",
212
- provenance: "join",
213
- async floor(_ctx, query, pre, worthRunning) {
214
- const W = _ctx.space.maxGroup;
215
- if (query.length < 2 * W || _ctx.store.edgeSourceCount() === 0) {
216
- return null;
217
- }
218
- // Confluence's floor is always exactly 3*STEP when it exists — same
219
- // investment discipline as CAST's (see cast.ts): when the bound already
220
- // cannot beat the incumbent, return it UNINVESTED (never first-touch the
221
- // climb just to be pruned) and let the pipeline record the truthful
222
- // "cannot beat incumbent" note.
223
- if (!worthRunning(3 * STEP)) {
224
- return 3 * STEP;
225
- }
226
- if ((await pre.attention()).ranked.length < 2) {
227
- return null;
228
- }
229
- return 3 * STEP;
230
- },
231
- async run(ctx, query, pre) {
232
- const met = await confluenceJoin(ctx, query, pre);
233
- if (!met) {
234
- return [];
235
- }
236
- return [{
237
- bytes: met.bytes,
238
- accounted: met.accounted,
239
- moves: met.moves,
240
- used: met.used,
241
- unexplained: met.unexplained,
242
- }];
243
- },
184
+ name: "confluence",
185
+ provenance: "join",
186
+ async floor(_ctx, query, pre, worthRunning) {
187
+ const W = _ctx.space.maxGroup;
188
+ if (query.length < 2 * W || _ctx.store.edgeSourceCount() === 0)
189
+ return null;
190
+ // Confluence's floor is always exactly 3*STEP when it exists — same
191
+ // investment discipline as CAST's (see cast.ts): when the bound already
192
+ // cannot beat the incumbent, return it UNINVESTED (never first-touch the
193
+ // climb just to be pruned) and let the pipeline record the truthful
194
+ // "cannot beat incumbent" note.
195
+ if (!worthRunning(3 * STEP))
196
+ return 3 * STEP;
197
+ if ((await pre.attention()).ranked.length < 2)
198
+ return null;
199
+ return 3 * STEP;
200
+ },
201
+ async run(ctx, query, pre) {
202
+ const met = await confluenceJoin(ctx, query, pre);
203
+ if (!met)
204
+ return [];
205
+ return [{
206
+ bytes: met.bytes,
207
+ accounted: met.accounted,
208
+ moves: met.moves,
209
+ used: met.used,
210
+ unexplained: met.unexplained,
211
+ }];
212
+ },
244
213
  };
@@ -1,12 +1,6 @@
1
1
  import type { MindContext } from "../types.js";
2
2
  import type { Site } from "../graph-search.js";
3
3
  import type { PipelineMechanism } from "../pipeline-mechanism.js";
4
- export declare function resolveConcepts(
5
- ctx: MindContext,
6
- sites: Site[],
7
- ): Promise<Map<number, number>>;
8
- export declare function resolveConnectors(
9
- ctx: MindContext,
10
- sites: ReadonlyArray<Site>,
11
- ): Promise<Map<string, Uint8Array>>;
4
+ export declare function resolveConcepts(ctx: MindContext, sites: Site[]): Promise<Map<number, number>>;
5
+ export declare function resolveConnectors(ctx: MindContext, sites: ReadonlyArray<Site>): Promise<Map<string, Uint8Array>>;
12
6
  export declare const coverMechanism: PipelineMechanism;