@hviana/sema 0.1.8 → 0.1.9
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.
- package/package.json +1 -1
- package/src/geometry.ts +14 -30
- package/src/mind/mechanisms/cast.ts +12 -7
- package/dist/example/demo.d.ts +0 -1
- package/dist/example/demo.js +0 -39
- package/dist/example/train_base.d.ts +0 -87
- package/dist/example/train_base.js +0 -2252
- package/dist/src/alphabet.d.ts +0 -7
- package/dist/src/alphabet.js +0 -33
- package/dist/src/alu/src/alu.d.ts +0 -185
- package/dist/src/alu/src/alu.js +0 -440
- package/dist/src/alu/src/expr.d.ts +0 -61
- package/dist/src/alu/src/expr.js +0 -318
- package/dist/src/alu/src/index.d.ts +0 -11
- package/dist/src/alu/src/index.js +0 -19
- package/dist/src/alu/src/kernel-arith.d.ts +0 -16
- package/dist/src/alu/src/kernel-arith.js +0 -264
- package/dist/src/alu/src/kernel-bits.d.ts +0 -19
- package/dist/src/alu/src/kernel-bits.js +0 -152
- package/dist/src/alu/src/kernel-logic.d.ts +0 -4
- package/dist/src/alu/src/kernel-logic.js +0 -60
- package/dist/src/alu/src/kernel-nd.d.ts +0 -3
- package/dist/src/alu/src/kernel-nd.js +0 -208
- package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
- package/dist/src/alu/src/kernel-numeric.js +0 -366
- package/dist/src/alu/src/operation.d.ts +0 -168
- package/dist/src/alu/src/operation.js +0 -189
- package/dist/src/alu/src/parser.d.ts +0 -221
- package/dist/src/alu/src/parser.js +0 -577
- package/dist/src/alu/src/resonance.d.ts +0 -55
- package/dist/src/alu/src/resonance.js +0 -126
- package/dist/src/alu/src/text.d.ts +0 -31
- package/dist/src/alu/src/text.js +0 -73
- package/dist/src/alu/src/value.d.ts +0 -109
- package/dist/src/alu/src/value.js +0 -300
- package/dist/src/alu/test/alu.test.d.ts +0 -1
- package/dist/src/alu/test/alu.test.js +0 -764
- package/dist/src/bytes.d.ts +0 -14
- package/dist/src/bytes.js +0 -59
- package/dist/src/canon.d.ts +0 -26
- package/dist/src/canon.js +0 -57
- package/dist/src/config.d.ts +0 -111
- package/dist/src/config.js +0 -91
- package/dist/src/derive/src/deduction.d.ts +0 -125
- package/dist/src/derive/src/deduction.js +0 -155
- package/dist/src/derive/src/index.d.ts +0 -7
- package/dist/src/derive/src/index.js +0 -11
- package/dist/src/derive/src/priority-queue.d.ts +0 -20
- package/dist/src/derive/src/priority-queue.js +0 -73
- package/dist/src/derive/src/rewrite.d.ts +0 -56
- package/dist/src/derive/src/rewrite.js +0 -100
- package/dist/src/derive/src/trie.d.ts +0 -90
- package/dist/src/derive/src/trie.js +0 -217
- package/dist/src/derive/test/derive.test.d.ts +0 -1
- package/dist/src/derive/test/derive.test.js +0 -122
- package/dist/src/extension.d.ts +0 -37
- package/dist/src/extension.js +0 -7
- package/dist/src/geometry.d.ts +0 -148
- package/dist/src/geometry.js +0 -529
- package/dist/src/index.d.ts +0 -16
- package/dist/src/index.js +0 -18
- package/dist/src/ingest-cache.d.ts +0 -41
- package/dist/src/ingest-cache.js +0 -161
- package/dist/src/mind/articulation.d.ts +0 -6
- package/dist/src/mind/articulation.js +0 -99
- package/dist/src/mind/attention.d.ts +0 -72
- package/dist/src/mind/attention.js +0 -898
- package/dist/src/mind/canonical.d.ts +0 -29
- package/dist/src/mind/canonical.js +0 -88
- package/dist/src/mind/graph-search.d.ts +0 -270
- package/dist/src/mind/graph-search.js +0 -847
- package/dist/src/mind/index.d.ts +0 -5
- package/dist/src/mind/index.js +0 -5
- package/dist/src/mind/junction.d.ts +0 -95
- package/dist/src/mind/junction.js +0 -262
- package/dist/src/mind/learning.d.ts +0 -47
- package/dist/src/mind/learning.js +0 -233
- package/dist/src/mind/match.d.ts +0 -113
- package/dist/src/mind/match.js +0 -446
- package/dist/src/mind/mechanisms/alu.d.ts +0 -4
- package/dist/src/mind/mechanisms/alu.js +0 -29
- package/dist/src/mind/mechanisms/cast.d.ts +0 -35
- package/dist/src/mind/mechanisms/cast.js +0 -461
- package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
- package/dist/src/mind/mechanisms/confluence.js +0 -225
- package/dist/src/mind/mechanisms/cover.d.ts +0 -6
- package/dist/src/mind/mechanisms/cover.js +0 -179
- package/dist/src/mind/mechanisms/extraction.d.ts +0 -67
- package/dist/src/mind/mechanisms/extraction.js +0 -342
- package/dist/src/mind/mechanisms/recall.d.ts +0 -13
- package/dist/src/mind/mechanisms/recall.js +0 -235
- package/dist/src/mind/mind.d.ts +0 -273
- package/dist/src/mind/mind.js +0 -562
- package/dist/src/mind/pipeline-mechanism.d.ts +0 -142
- package/dist/src/mind/pipeline-mechanism.js +0 -213
- package/dist/src/mind/pipeline.d.ts +0 -20
- package/dist/src/mind/pipeline.js +0 -185
- package/dist/src/mind/primitives.d.ts +0 -63
- package/dist/src/mind/primitives.js +0 -251
- package/dist/src/mind/rationale.d.ts +0 -134
- package/dist/src/mind/rationale.js +0 -162
- package/dist/src/mind/reasoning.d.ts +0 -15
- package/dist/src/mind/reasoning.js +0 -162
- package/dist/src/mind/recognition.d.ts +0 -20
- package/dist/src/mind/recognition.js +0 -246
- package/dist/src/mind/resonance.d.ts +0 -23
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +0 -15
- package/dist/src/mind/trace.js +0 -73
- package/dist/src/mind/traverse.d.ts +0 -113
- package/dist/src/mind/traverse.js +0 -488
- package/dist/src/mind/types.d.ts +0 -186
- package/dist/src/mind/types.js +0 -84
- package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
- package/dist/src/rabitq-ivf/src/database.js +0 -201
- package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
- package/dist/src/rabitq-ivf/src/index.js +0 -4
- package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
- package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
- package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
- package/dist/src/rabitq-ivf/src/prng.js +0 -36
- package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
- package/dist/src/rabitq-ivf/src/rabitq.js +0 -283
- package/dist/src/sema.d.ts +0 -31
- package/dist/src/sema.js +0 -63
- package/dist/src/store-sqlite.d.ts +0 -184
- package/dist/src/store-sqlite.js +0 -942
- package/dist/src/store.d.ts +0 -654
- package/dist/src/store.js +0 -1612
- package/dist/src/vec.d.ts +0 -31
- package/dist/src/vec.js +0 -109
|
@@ -1,488 +0,0 @@
|
|
|
1
|
-
// traverse.ts — Traverse primitives + disambiguation (Sections 1 & 6 of the mind).
|
|
2
|
-
//
|
|
3
|
-
// Traverse — node → nodes (edgeAncestors, nextOf, prevOf, contains,
|
|
4
|
-
// guidedNext, chooseNext, chooseAmong, hubCap)
|
|
5
|
-
//
|
|
6
|
-
// The PROJECTIONS built on these walks (follow, conceptHop, reverseContext,
|
|
7
|
-
// project) live in match.ts — the elementary match-and-project operation.
|
|
8
|
-
import { cosine } from "../vec.js";
|
|
9
|
-
import { gistOf, read } from "./primitives.js";
|
|
10
|
-
const structCaches = new WeakMap();
|
|
11
|
-
function getStructCache(ctx) {
|
|
12
|
-
if (ctx.climbMemo === null)
|
|
13
|
-
return null;
|
|
14
|
-
let c = structCaches.get(ctx.climbMemo);
|
|
15
|
-
if (c === undefined) {
|
|
16
|
-
structCaches.set(ctx.climbMemo, c = {
|
|
17
|
-
hasNext: new Map(),
|
|
18
|
-
prevCount: new Map(),
|
|
19
|
-
hasParents: new Map(),
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
return c;
|
|
23
|
-
}
|
|
24
|
-
/** Cached {@link Store.hasNext} — pure during one respond(). */
|
|
25
|
-
function cachedHasNext(ctx, id, cache) {
|
|
26
|
-
if (cache === null)
|
|
27
|
-
return ctx.store.hasNext(id);
|
|
28
|
-
let v = cache.hasNext.get(id);
|
|
29
|
-
if (v === undefined) {
|
|
30
|
-
v = ctx.store.hasNext(id);
|
|
31
|
-
cache.hasNext.set(id, v);
|
|
32
|
-
}
|
|
33
|
-
return v;
|
|
34
|
-
}
|
|
35
|
-
/** Cached {@link Store.prevCount} — pure during one respond(). */
|
|
36
|
-
function cachedPrevCount(ctx, id, cache) {
|
|
37
|
-
if (cache === null)
|
|
38
|
-
return ctx.store.prevCount(id);
|
|
39
|
-
let v = cache.prevCount.get(id);
|
|
40
|
-
if (v === undefined) {
|
|
41
|
-
v = ctx.store.prevCount(id);
|
|
42
|
-
cache.prevCount.set(id, v);
|
|
43
|
-
}
|
|
44
|
-
return v;
|
|
45
|
-
}
|
|
46
|
-
/** Cached {@link Store.hasParents} — pure during one respond(). */
|
|
47
|
-
function cachedHasParents(ctx, id, cache) {
|
|
48
|
-
if (cache === null)
|
|
49
|
-
return ctx.store.hasParents(id);
|
|
50
|
-
let v = cache.hasParents.get(id);
|
|
51
|
-
if (v === undefined) {
|
|
52
|
-
v = ctx.store.hasParents(id);
|
|
53
|
-
cache.hasParents.set(id, v);
|
|
54
|
-
}
|
|
55
|
-
return v;
|
|
56
|
-
}
|
|
57
|
-
// ── Graph climbing ───────────────────────────────────────────────────────
|
|
58
|
-
/** Climb the structural DAG from a node to its edge-bearing ancestor contexts.
|
|
59
|
-
* Ascent stops at hub nodes (parents > √N) — their reach is non-discriminative.
|
|
60
|
-
* When the start node has no structural parents, climbs from containment parents
|
|
61
|
-
* (sub-span flat branches inheriting their chunks' context).
|
|
62
|
-
*
|
|
63
|
-
* `memo`, when given, caches whole climbs by start id for the duration of ONE
|
|
64
|
-
* query (the store is read-only while a query is in flight, so a climb is a
|
|
65
|
-
* pure function of the id). The consensus pipeline climbs the SAME anchors
|
|
66
|
-
* repeatedly — regions sharing a chunk, and canonicalChunkId probing each
|
|
67
|
-
* chunk's prefixes — so without the memo every repeat re-pays the full
|
|
68
|
-
* fan-out reads. */
|
|
69
|
-
export function edgeAncestors(ctx, id, contextCount, memo) {
|
|
70
|
-
const hit = memo?.get(id);
|
|
71
|
-
if (hit !== undefined)
|
|
72
|
-
return hit;
|
|
73
|
-
// BYTE-ATOM COMMONALITY. A single-byte leaf (implicit negative id) has no
|
|
74
|
-
// structural parents BY CONSTRUCTION — atoms are never linked into the kid
|
|
75
|
-
// or contain tables — so this climb cannot observe its containment at all.
|
|
76
|
-
// The walk below would see only the atom's own direct edges and report
|
|
77
|
-
// contextsReached ≈ 1, turning the MOST common content in the store into
|
|
78
|
-
// the MOST discriminative voter (observed on a 325K-context store: every
|
|
79
|
-
// recognised single-letter site voted full ln N for the one fact whose
|
|
80
|
-
// continuation is that letter, and their pooled sum out-voted every
|
|
81
|
-
// genuine anchor). An unmeasurable containment must not default to
|
|
82
|
-
// "maximally rare": it is bounded below by the uniform expectation over
|
|
83
|
-
// the byte alphabet — N contexts, each at least one chunk of up to W of
|
|
84
|
-
// the 256 possible atoms, reach ≥ N·W/256 contexts per atom on average
|
|
85
|
-
// (see {@link atomReach}). When that floor itself exceeds the hub bound
|
|
86
|
-
// √N the atom is a hub at this corpus scale and the climb abstains
|
|
87
|
-
// (saturated) — the atom's own edges remain fully traversable (tier-0
|
|
88
|
-
// exact recall, chooseNext, project); only its say as a consensus voter
|
|
89
|
-
// is withdrawn. On a small store the floor stays ≤ √N and the atom
|
|
90
|
-
// climbs exactly as before, so single-letter facts keep working.
|
|
91
|
-
if (id < 0 && atomIsHub(ctx, contextCount)) {
|
|
92
|
-
const reach = { roots: [], contextsReached: 0, saturated: true };
|
|
93
|
-
memo?.set(id, reach);
|
|
94
|
-
return reach;
|
|
95
|
-
}
|
|
96
|
-
const bound = Math.ceil(Math.sqrt(contextCount));
|
|
97
|
-
const roots = [];
|
|
98
|
-
const seen = new Set([id]);
|
|
99
|
-
const ctxSeen = new Set();
|
|
100
|
-
let saturated = false;
|
|
101
|
-
// EXPAND-UNTIL-DECIDED: a reach is consumed either as a VOTE (which needs
|
|
102
|
-
// contextsReached exactly, and only while ≤ √N — beyond that the region is
|
|
103
|
-
// non-discriminative) or as an ABSTENTION (saturated — whose roots and
|
|
104
|
-
// counts no consumer reads). So the climb may STOP the moment the answer
|
|
105
|
-
// is decided:
|
|
106
|
-
// • a node whose prev fan-in alone exceeds √N decides it (its
|
|
107
|
-
// predecessors are √N+ distinct contexts) — no read needed, prevCount
|
|
108
|
-
// is an indexed O(1);
|
|
109
|
-
// • distinct contexts crossing √N decides it;
|
|
110
|
-
// • a node with more than √N parents decides its own expansion (the
|
|
111
|
-
// classic hub guard; the walk aborts rather than continue, which no
|
|
112
|
-
// consumer can distinguish — saturated reaches are never voted).
|
|
113
|
-
// Below every decision threshold the walk is EXACT — identical roots and
|
|
114
|
-
// contexts to the unbounded climb — because prevFirst(√N) IS the full prev
|
|
115
|
-
// list and parentsFirst(√N+1) IS the full parent list whenever they do not
|
|
116
|
-
// decide. Work is bounded by √N contexts × the climb's local structure,
|
|
117
|
-
// never by the corpus.
|
|
118
|
-
const structCache = getStructCache(ctx);
|
|
119
|
-
// LATERAL-BRANCH ACCOUNT — the cumulative dual of the per-node hub guard.
|
|
120
|
-
// Within one deposit the ascent is a CHAIN (each node's first parent);
|
|
121
|
-
// every parent BEYOND a node's first is an entry into another containing
|
|
122
|
-
// structure (hash-consing: a shared subtree's extra parents are other
|
|
123
|
-
// deposits' chunks). The per-node guard already declares a node with more
|
|
124
|
-
// than √N parents non-discriminative; a climb whose ACCUMULATED lateral
|
|
125
|
-
// entries exceed √N has spread across just as many distinct containing
|
|
126
|
-
// structures — the same commonness, distributed along the cone instead of
|
|
127
|
-
// concentrated at one node — and is decided: saturated. A deep chain in
|
|
128
|
-
// ONE structure accrues no laterals, so legitimate deep scaffolding (a
|
|
129
|
-
// fragment far down a long cumulative context) still climbs to its root
|
|
130
|
-
// at any depth; what dies is the cross-structure drift that visited tens
|
|
131
|
-
// of thousands of edge-free interiors (profiled on a 17.7M-node store:
|
|
132
|
-
// ~20K distinct nodes per climb family, >95% unique — not memoisable)
|
|
133
|
-
// while the context account never decided.
|
|
134
|
-
let lateral = 0;
|
|
135
|
-
const visit = (x) => {
|
|
136
|
-
const hasNx = cachedHasNext(ctx, x, structCache);
|
|
137
|
-
const pc = cachedPrevCount(ctx, x, structCache);
|
|
138
|
-
if (hasNx || pc > 0) {
|
|
139
|
-
roots.push(x);
|
|
140
|
-
if (hasNx)
|
|
141
|
-
ctxSeen.add(x);
|
|
142
|
-
if (pc > bound)
|
|
143
|
-
return false; // decided: ≥ pc > √N distinct contexts
|
|
144
|
-
for (const p of ctx.store.prevFirst(x, bound))
|
|
145
|
-
ctxSeen.add(p);
|
|
146
|
-
if (ctxSeen.size > bound)
|
|
147
|
-
return false; // decided
|
|
148
|
-
}
|
|
149
|
-
const parents = ctx.store.parentsFirst(x, bound + 1);
|
|
150
|
-
if (parents.length > bound)
|
|
151
|
-
return false; // decided: hub
|
|
152
|
-
let fresh = 0;
|
|
153
|
-
for (const p of parents) {
|
|
154
|
-
if (!seen.has(p)) {
|
|
155
|
-
seen.add(p);
|
|
156
|
-
stack.push(p);
|
|
157
|
-
fresh++;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (fresh > 1) {
|
|
161
|
-
lateral += fresh - 1;
|
|
162
|
-
if (lateral > bound)
|
|
163
|
-
return false; // decided: cone-wide hub
|
|
164
|
-
}
|
|
165
|
-
return true;
|
|
166
|
-
};
|
|
167
|
-
const stack = [];
|
|
168
|
-
const containment = !cachedHasParents(ctx, id, structCache);
|
|
169
|
-
if (!containment)
|
|
170
|
-
stack.push(id);
|
|
171
|
-
// The containment seed is STREAMED in pages of √N: a distinctive window's
|
|
172
|
-
// containers (which converge on one or two contexts, however many chunks
|
|
173
|
-
// of one deposit repeat it) are walked IN FULL — exact — while a common
|
|
174
|
-
// window's corpus-sized container list is abandoned at the first decision
|
|
175
|
-
// above, after O(√N) pages at most (each page adds containers whose climbs
|
|
176
|
-
// add contexts; √N distinct contexts decide).
|
|
177
|
-
let containerOff = 0;
|
|
178
|
-
let containersExhausted = !containment;
|
|
179
|
-
climb: for (;;) {
|
|
180
|
-
if (stack.length === 0) {
|
|
181
|
-
if (containersExhausted)
|
|
182
|
-
break;
|
|
183
|
-
const page = ctx.store.containersSlice(id, containerOff, bound);
|
|
184
|
-
containerOff += page.length;
|
|
185
|
-
if (page.length < bound)
|
|
186
|
-
containersExhausted = true;
|
|
187
|
-
for (const c of page) {
|
|
188
|
-
if (!seen.has(c)) {
|
|
189
|
-
seen.add(c);
|
|
190
|
-
stack.push(c);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (stack.length === 0) {
|
|
194
|
-
if (containerOff === 0)
|
|
195
|
-
stack.push(id); // no containers at all
|
|
196
|
-
else
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
while (stack.length > 0) {
|
|
201
|
-
let x = stack.pop();
|
|
202
|
-
// TRANSPARENT-CHAIN HOP: a node with no edges in or out and exactly one
|
|
203
|
-
// parent contributes nothing here — no root, no context, no lateral
|
|
204
|
-
// entry — so the run to its first non-transparent ancestor is skipped
|
|
205
|
-
// in ONE store read (Store.chainRun) instead of three probes per node.
|
|
206
|
-
// The interior nodes still enter `seen`, exactly as a node-at-a-time
|
|
207
|
-
// ascent would have recorded them at push time, so sibling entries into
|
|
208
|
-
// the same chain keep identical fresh/lateral accounting; and if the
|
|
209
|
-
// terminal was already seen (another chain merged into this one first),
|
|
210
|
-
// it is not visited twice — the same dedup the push-time seen-check
|
|
211
|
-
// used to provide.
|
|
212
|
-
const run = ctx.store.chainRun(x);
|
|
213
|
-
if (run.length > 1) {
|
|
214
|
-
const top = run[run.length - 1];
|
|
215
|
-
const dup = seen.has(top);
|
|
216
|
-
for (let i = 1; i < run.length; i++)
|
|
217
|
-
seen.add(run[i]);
|
|
218
|
-
if (dup)
|
|
219
|
-
continue;
|
|
220
|
-
x = top;
|
|
221
|
-
}
|
|
222
|
-
if (!visit(x)) {
|
|
223
|
-
saturated = true;
|
|
224
|
-
break climb;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const reach = { roots, contextsReached: ctxSeen.size, saturated };
|
|
229
|
-
memo?.set(id, reach);
|
|
230
|
-
return reach;
|
|
231
|
-
}
|
|
232
|
-
/** Convenience: forward edges of a node. */
|
|
233
|
-
export function nextOf(ctx, id) {
|
|
234
|
-
return ctx.store.next(id);
|
|
235
|
-
}
|
|
236
|
-
/** Convenience: reverse edges of a node. */
|
|
237
|
-
export function prevOf(ctx, id) {
|
|
238
|
-
return ctx.store.prev(id);
|
|
239
|
-
}
|
|
240
|
-
/** The uniform-expectation floor on a byte atom's corpus commonality: N
|
|
241
|
-
* learnt contexts, each at least one perception chunk of up to W of the 256
|
|
242
|
-
* possible byte values, contain a given atom in ≥ N·W/256 contexts on
|
|
243
|
-
* average. An atom's TRUE containment is unmeasurable (atoms carry no
|
|
244
|
-
* kid/contain links by construction), so this floor is the honest stand-in:
|
|
245
|
-
* derived entirely from the corpus scale N, the perception window W, and
|
|
246
|
-
* the alphabet size — never tuned. */
|
|
247
|
-
export function atomReach(ctx, contextCount) {
|
|
248
|
-
return Math.max(1, Math.ceil((contextCount * ctx.space.maxGroup) / 256));
|
|
249
|
-
}
|
|
250
|
-
/** Whether a byte atom is a hub at this corpus scale — its commonality floor
|
|
251
|
-
* {@link atomReach} exceeds the hub bound √N. Below it (small stores) an
|
|
252
|
-
* atom votes and is recognised exactly as any stored form; above it the
|
|
253
|
-
* alphabet is scaffolding everywhere and abstains. */
|
|
254
|
-
export function atomIsHub(ctx, contextCount) {
|
|
255
|
-
return atomReach(ctx, contextCount) >
|
|
256
|
-
Math.ceil(Math.sqrt(Math.max(2, contextCount)));
|
|
257
|
-
}
|
|
258
|
-
/** Whether a node LEADS SOMEWHERE — it bears a continuation edge or a halo.
|
|
259
|
-
* The admission predicate recognition filters sites with (HOW_IT_WORKS
|
|
260
|
-
* §15.3): a form that leads nowhere contributes nothing to any derivation.
|
|
261
|
-
* Runs once per candidate span on the recognition hot path — `hasNext` is
|
|
262
|
-
* cached per response (the same flat-branch ids are probed across prefix
|
|
263
|
-
* variants by canonicalChunkId). `hasHalo` is not cached: it's a single
|
|
264
|
-
* indexed point probe per candidate, and the candidates that reach this
|
|
265
|
-
* check have already been filtered by hasNext above in edgeAncestors. */
|
|
266
|
-
export function leadsSomewhere(ctx, id) {
|
|
267
|
-
const memo = getStructCache(ctx);
|
|
268
|
-
if (cachedHasNext(ctx, id, memo))
|
|
269
|
-
return true;
|
|
270
|
-
return ctx.store.hasHalo(id);
|
|
271
|
-
}
|
|
272
|
-
/** The structural IDF read of ONE node: how many distinct learnt contexts
|
|
273
|
-
* its containment/edge climb reaches, or Infinity when it reaches none or
|
|
274
|
-
* saturates (no usable identity evidence). The number every
|
|
275
|
-
* discriminative-vs-scaffolding decision derives from — paired with the
|
|
276
|
-
* half-dominance convention (geometry.dominates(reach, N)): content
|
|
277
|
-
* reaching a corpus MINORITY of contexts discriminates (an entity, a
|
|
278
|
-
* filler); content reaching a majority is frame scaffolding. */
|
|
279
|
-
export function reachOf(ctx, id, contextCount, memo) {
|
|
280
|
-
const r = edgeAncestors(ctx, id, contextCount, memo);
|
|
281
|
-
if (r.saturated || r.roots.length === 0)
|
|
282
|
-
return Infinity;
|
|
283
|
-
return Math.max(1, r.contextsReached);
|
|
284
|
-
}
|
|
285
|
-
/** The corpus scale N — the count of DISTINCT learnt contexts, floored at 2
|
|
286
|
-
* so its derived readings (ln N in the consensus floor, √N in the hub bound)
|
|
287
|
-
* stay meaningful on a near-empty store. The one definition every consumer
|
|
288
|
-
* of "how big is this corpus?" reads. */
|
|
289
|
-
export function corpusN(ctx) {
|
|
290
|
-
return Math.max(2, ctx.store.edgeSourceCount());
|
|
291
|
-
}
|
|
292
|
-
/** The hub bound √N itself (≥ 2 always, since N is floored at 2) — for
|
|
293
|
-
* consumers that pass it to the store's LIMITed reads instead of capping a
|
|
294
|
-
* materialised list. {@link hubCap} is the list-side reading of the same
|
|
295
|
-
* convention. */
|
|
296
|
-
export function hubBound(ctx) {
|
|
297
|
-
return Math.ceil(Math.sqrt(corpusN(ctx)));
|
|
298
|
-
}
|
|
299
|
-
/** Cap a candidate list at the hub bound √N (insertion order) — the ONE
|
|
300
|
-
* fan-out convention every walk and disambiguation uses (see HOW_IT_WORKS
|
|
301
|
-
* §8.6). A node connected to more than √N others is a hub whose individual
|
|
302
|
-
* connections carry ~no discriminative information; materialising or scoring
|
|
303
|
-
* them all would make single decisions scale with the corpus. */
|
|
304
|
-
export function hubCap(ctx, ids) {
|
|
305
|
-
const bound = hubBound(ctx);
|
|
306
|
-
return ids.length > bound ? ids.slice(0, bound) : ids;
|
|
307
|
-
}
|
|
308
|
-
/** Whether `descendant` lies within `ancestor`'s subtree — a structural DAG
|
|
309
|
-
* relation read off the hash-consed `kids` lists, by a bounded explicit-stack
|
|
310
|
-
* descent. Used by articulation to keep a voice from revoicing a fragment
|
|
311
|
-
* OF that voice. */
|
|
312
|
-
export function contains(ctx, ancestor, descendant) {
|
|
313
|
-
if (ancestor === descendant)
|
|
314
|
-
return true;
|
|
315
|
-
const seen = new Set([ancestor]);
|
|
316
|
-
const stack = [ancestor];
|
|
317
|
-
while (stack.length > 0) {
|
|
318
|
-
const rec = ctx.store.get(stack.pop());
|
|
319
|
-
if (!rec?.kids)
|
|
320
|
-
continue;
|
|
321
|
-
for (const k of rec.kids) {
|
|
322
|
-
if (k === descendant)
|
|
323
|
-
return true;
|
|
324
|
-
if (!seen.has(k)) {
|
|
325
|
-
seen.add(k);
|
|
326
|
-
stack.push(k);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
// ── Edge disambiguation (Section 6) ──────────────────────────────────────
|
|
333
|
-
/** The best-scoring item by cosine against `query`, among items scoring at
|
|
334
|
-
* or above `threshold` — the shared arg-max every Pattern-A "which of these
|
|
335
|
-
* resonates best" decision reduces to. `strict` picks the tie-break a
|
|
336
|
-
* caller needs: `true` keeps the first-seen leader on a tie (`>`), the
|
|
337
|
-
* default lets a later equal score take it (`>=`). */
|
|
338
|
-
export function argmaxBy(items, scoreOf, threshold, strict = false) {
|
|
339
|
-
let best = null;
|
|
340
|
-
for (const item of items) {
|
|
341
|
-
const score = scoreOf(item);
|
|
342
|
-
const bar = best?.score ?? threshold;
|
|
343
|
-
if (strict ? score > bar : score >= bar)
|
|
344
|
-
best = { item, score };
|
|
345
|
-
}
|
|
346
|
-
return best;
|
|
347
|
-
}
|
|
348
|
-
export function argmaxCosine(query, items, vecOf, threshold, strict = false) {
|
|
349
|
-
return argmaxBy(items, (item) => {
|
|
350
|
-
const v = vecOf(item);
|
|
351
|
-
return v ? cosine(query, v) : -Infinity;
|
|
352
|
-
}, threshold, strict);
|
|
353
|
-
}
|
|
354
|
-
/** The guided-or-first continuation of a node, as answer-shaped bytes source:
|
|
355
|
-
* chooseNext under the response guide, falling back to the FIRST-inserted
|
|
356
|
-
* edge — the one no-guide convention chooseNext, project() and the search's
|
|
357
|
-
* formRules all share. undefined when the node has no continuation. */
|
|
358
|
-
export function guidedFirst(ctx, id) {
|
|
359
|
-
const pick = guidedNext(ctx, id);
|
|
360
|
-
if (pick !== undefined)
|
|
361
|
-
return pick;
|
|
362
|
-
// No guide in flight (or nothing chosen): the first-inserted edge, read
|
|
363
|
-
// with LIMIT 1 — never the full fan-out.
|
|
364
|
-
const nx = ctx.store.nextFirst(id, 1);
|
|
365
|
-
return nx.length > 0 ? nx[0] : undefined;
|
|
366
|
-
}
|
|
367
|
-
export function guidedNext(ctx, node) {
|
|
368
|
-
if (ctx._edgeGuide === null)
|
|
369
|
-
return undefined;
|
|
370
|
-
// The pick memo is BYPASSED while a rationale trace is attached — the same
|
|
371
|
-
// policy climbMemo and recogniseMemo follow (every mechanism must emit its
|
|
372
|
-
// own steps; a memo hit would swallow the repeat's `disambiguate` step).
|
|
373
|
-
// Consistency does not need the memo: chooseNext is a pure function of the
|
|
374
|
-
// (read-only) store and the guide, so recomputation yields the same pick.
|
|
375
|
-
if (!ctx.trace) {
|
|
376
|
-
const memo = ctx._edgeChoice.get(node);
|
|
377
|
-
if (memo !== undefined)
|
|
378
|
-
return memo === -1 ? undefined : memo;
|
|
379
|
-
}
|
|
380
|
-
const pick = chooseNext(ctx, node, ctx._edgeGuide);
|
|
381
|
-
if (!ctx.trace)
|
|
382
|
-
ctx._edgeChoice.set(node, pick ?? -1);
|
|
383
|
-
return pick;
|
|
384
|
-
}
|
|
385
|
-
/** Disambiguate among a node's learnt continuations by distributional
|
|
386
|
-
* support. NOTE the `guide` contract: its VALUE is deliberately unused —
|
|
387
|
-
* only its PRESENCE gates disambiguation (a null guide means no query is in
|
|
388
|
-
* flight, so structural walkers keep plain first-edge behaviour). The
|
|
389
|
-
* gist-cosine of short answer candidates against a query guide is dominated
|
|
390
|
-
* by accidental byte-pattern correlations, not semantic relatedness, so the
|
|
391
|
-
* evidence consulted is structural: each candidate's reverse-edge support
|
|
392
|
-
* count (see below). Contrast {@link chooseAmong}, the REVERSE-direction
|
|
393
|
-
* disambiguator, whose candidates are whole learnt contexts — long enough
|
|
394
|
-
* that their perceived gists ARE semantically meaningful — and which
|
|
395
|
-
* therefore scores by guide cosine. The two directions consult different
|
|
396
|
-
* halves of the evidence on purpose. */
|
|
397
|
-
export function chooseNext(ctx, id, guide) {
|
|
398
|
-
// CAPPED read: only the first √N continuations are ever candidates (the
|
|
399
|
-
// documented hub trade), so only they are read — a hub context's full
|
|
400
|
-
// fan-out is corpus-sized and must never be materialised. hubBound ≥ 2,
|
|
401
|
-
// so the single-continuation fast path below stays exact.
|
|
402
|
-
const nx = ctx.store.nextFirst(id, hubBound(ctx));
|
|
403
|
-
if (nx.length === 0)
|
|
404
|
-
return undefined;
|
|
405
|
-
if (nx.length === 1 || !guide)
|
|
406
|
-
return nx[0];
|
|
407
|
-
// Cap candidates at √N — the same bound the original chooseAmong used.
|
|
408
|
-
// A hub context can accumulate thousands of continuations; the best-fit
|
|
409
|
-
// one is among the first √N by insertion order (edges are never deleted,
|
|
410
|
-
// so the oldest are the most established). A strongly-supported edge
|
|
411
|
-
// inserted beyond the cap is invisible here — the deliberate trade
|
|
412
|
-
// against paying O(fan-out) count reads on every disambiguation.
|
|
413
|
-
const capped = nx; // already the hub-capped prefix, by the read above
|
|
414
|
-
// Distributional-evidence disambiguation, consulting BOTH read-outs of the
|
|
415
|
-
// evidence the training poured:
|
|
416
|
-
// 1. prevCount — how many DISTINCT contexts predict this candidate (one
|
|
417
|
-
// indexed COUNT; never a materialisation — a common continuation's
|
|
418
|
-
// reverse fan-in is corpus-sized). Diversity of independent evidence
|
|
419
|
-
// is the primary signal: three different formulations agreeing beat
|
|
420
|
-
// one formulation repeated.
|
|
421
|
-
// 2. haloMass — how many episode signatures were poured into the
|
|
422
|
-
// candidate's halo (repetition counts). The tie-break among equally
|
|
423
|
-
// diverse candidates: a fact reinforced across many episodes is more
|
|
424
|
-
// corroborated than one seen once, and this is the DIRECT measure of
|
|
425
|
-
// that — consulting only the structural count would leave poured
|
|
426
|
-
// evidence on the table.
|
|
427
|
-
// When both are equal, first-inserted wins (backward compatible).
|
|
428
|
-
let best = capped[0];
|
|
429
|
-
let bestSupport = ctx.store.prevCount(best);
|
|
430
|
-
let bestMass = ctx.store.haloMass(best);
|
|
431
|
-
for (let i = 1; i < capped.length; i++) {
|
|
432
|
-
const support = ctx.store.prevCount(capped[i]);
|
|
433
|
-
if (support < bestSupport)
|
|
434
|
-
continue;
|
|
435
|
-
const mass = ctx.store.haloMass(capped[i]);
|
|
436
|
-
if (support > bestSupport || mass > bestMass) {
|
|
437
|
-
best = capped[i];
|
|
438
|
-
bestSupport = support;
|
|
439
|
-
bestMass = mass;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
// Trace is built lazily — the filter + map below only execute when a
|
|
443
|
-
// trace listener is attached, so the common (no-trace) path pays only
|
|
444
|
-
// for the prevCount calls in the loop above, never for extra rItemShort
|
|
445
|
-
// byte-reads.
|
|
446
|
-
if (ctx.trace) {
|
|
447
|
-
const others = capped.filter((c) => c !== best);
|
|
448
|
-
ctx.trace.step("disambiguate", [rItemShort(ctx, best, "halo-evidence", bestSupport)], others.map((c) => rItemShort(ctx, c, "candidate", ctx.store.prevCount(c))), `${capped.length} continuations — distributional evidence selects ` +
|
|
449
|
-
`the most corroborated (distinct contexts ${bestSupport}, ` +
|
|
450
|
-
`poured mass ${bestMass})`);
|
|
451
|
-
}
|
|
452
|
-
return best;
|
|
453
|
-
}
|
|
454
|
-
/** The perceived gist of a candidate node, through the session gist cache.
|
|
455
|
-
* Re-gisting a candidate is a full river fold of its bytes — the measured
|
|
456
|
-
* recall bottleneck (a hub context offers up to √N continuations, EACH
|
|
457
|
-
* re-perceived per pick). A node's bytes are immutable and perception is
|
|
458
|
-
* pure, so the cached gist is valid for the store's lifetime. Exported for
|
|
459
|
-
* every "score node ids against a guide" decision (chooseAmong here, the
|
|
460
|
-
* bridge's junction pick) so they share ONE cache and one convention. */
|
|
461
|
-
export function candidateGist(ctx, c) {
|
|
462
|
-
const hit = ctx._gistCache.get(c);
|
|
463
|
-
if (hit !== undefined)
|
|
464
|
-
return hit;
|
|
465
|
-
const b = read(ctx, c);
|
|
466
|
-
if (b.length === 0)
|
|
467
|
-
return null;
|
|
468
|
-
const g = gistOf(ctx, b);
|
|
469
|
-
ctx._gistCache.set(c, g);
|
|
470
|
-
return g;
|
|
471
|
-
}
|
|
472
|
-
export function chooseAmong(ctx, candidates, guide) {
|
|
473
|
-
const capped = hubCap(ctx, candidates);
|
|
474
|
-
const found = argmaxCosine(guide, capped, (c) => candidateGist(ctx, c), -Infinity, true);
|
|
475
|
-
return found
|
|
476
|
-
? { id: found.item, score: found.score }
|
|
477
|
-
: { id: candidates[0], score: -Infinity };
|
|
478
|
-
}
|
|
479
|
-
// ── Trace shim (used by chooseNext before trace module is loaded) ────────
|
|
480
|
-
import { decodeText } from "./rationale.js";
|
|
481
|
-
function rItemShort(ctx, id, role, score) {
|
|
482
|
-
return {
|
|
483
|
-
text: decodeText(read(ctx, id)),
|
|
484
|
-
node: id,
|
|
485
|
-
role,
|
|
486
|
-
score,
|
|
487
|
-
};
|
|
488
|
-
}
|
package/dist/src/mind/types.d.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import type { Vec } from "../vec.js";
|
|
2
|
-
import type { Sema } from "../sema.js";
|
|
3
|
-
import type { BoundedMap, Store } from "../store.js";
|
|
4
|
-
import type { Space } from "../sema.js";
|
|
5
|
-
import type { Alphabet } from "../alphabet.js";
|
|
6
|
-
import type { MindConfig } from "../config.js";
|
|
7
|
-
import type { GraphSearch, Leaf, Seg, Site } from "./graph-search.js";
|
|
8
|
-
import type { Rationale } from "./rationale.js";
|
|
9
|
-
import type { FoldPyramid, Grid } from "../geometry.js";
|
|
10
|
-
export type Input = string | Uint8Array | Grid | Grid[];
|
|
11
|
-
/** The host capabilities GraphSearch consults during a cover. MindContext
|
|
12
|
-
* extends this so the Mind can pass itself as the host. */
|
|
13
|
-
export interface GraphSearchHost {
|
|
14
|
-
resolve(bytes: Uint8Array): number | null;
|
|
15
|
-
recogniseSpan?(bytes: Uint8Array): {
|
|
16
|
-
sites: ReadonlyArray<Site>;
|
|
17
|
-
leaves: ReadonlyArray<Leaf>;
|
|
18
|
-
splits: ReadonlySet<number>;
|
|
19
|
-
};
|
|
20
|
-
chooseNext?(node: number): number | undefined;
|
|
21
|
-
}
|
|
22
|
-
export interface Recognition {
|
|
23
|
-
/** Forms that can lead somewhere — they have an edge or a halo. */
|
|
24
|
-
sites: Site[];
|
|
25
|
-
/** The query's perceived leaves (the search's covering axioms). */
|
|
26
|
-
leaves: Leaf[];
|
|
27
|
-
/** Sub-leaf positions where a form boundary falls between leaf edges. */
|
|
28
|
-
splits: Set<number>;
|
|
29
|
-
}
|
|
30
|
-
/** How the consensus climb weights a region's Document-Frequency reach. */
|
|
31
|
-
export type DFMode = "inverse" | "direct" | "combined";
|
|
32
|
-
/** One POINT OF ATTENTION the consensus climb resolved. */
|
|
33
|
-
export interface Attention {
|
|
34
|
-
/** The learnt context this point resolves to. */
|
|
35
|
-
anchor: number;
|
|
36
|
-
/** IDF-weighted consensus vote — the strength that orders points. */
|
|
37
|
-
vote: number;
|
|
38
|
-
/** The union of the query byte-spans whose evidence supports this point. */
|
|
39
|
-
start: number;
|
|
40
|
-
end: number;
|
|
41
|
-
}
|
|
42
|
-
/** Both read-outs of one consensus climb. */
|
|
43
|
-
export interface AttentionRead {
|
|
44
|
-
roots: Attention[];
|
|
45
|
-
ranked: Attention[];
|
|
46
|
-
}
|
|
47
|
-
/** A positioned region of a byte stream paired with its gist. */
|
|
48
|
-
export interface Segment {
|
|
49
|
-
start: number;
|
|
50
|
-
end: number;
|
|
51
|
-
v: Vec;
|
|
52
|
-
}
|
|
53
|
-
/** A region of the query's perceived tree for the consensus climb. */
|
|
54
|
-
export interface Region {
|
|
55
|
-
v: Vec;
|
|
56
|
-
start: number;
|
|
57
|
-
end: number;
|
|
58
|
-
chunk: boolean;
|
|
59
|
-
/** Whether the region's bytes resolve to a KNOWN node (content-addressed,
|
|
60
|
-
* exact). Exact regions vote with full weight; approximate ones pay the
|
|
61
|
-
* contrastive margin (see voteRegions) — under the linear fold a raw
|
|
62
|
-
* resonance score is byte-overlap, evidence only in excess of its best
|
|
63
|
-
* rival conclusion. */
|
|
64
|
-
known: boolean;
|
|
65
|
-
}
|
|
66
|
-
/** Per-region vote data from the consensus climb's resonance pass. */
|
|
67
|
-
export interface RegionVote {
|
|
68
|
-
start: number;
|
|
69
|
-
end: number;
|
|
70
|
-
canonicalFailed: boolean;
|
|
71
|
-
roots: readonly number[];
|
|
72
|
-
w: number;
|
|
73
|
-
wFocus: number;
|
|
74
|
-
}
|
|
75
|
-
/** The edge-bearing contexts reached by climbing from a node, plus saturation info. */
|
|
76
|
-
export interface AncestorReach {
|
|
77
|
-
roots: number[];
|
|
78
|
-
contextsReached: number;
|
|
79
|
-
saturated: boolean;
|
|
80
|
-
}
|
|
81
|
-
/** Saturated-interval information for the noise-drop gate. */
|
|
82
|
-
export interface SaturationInfo {
|
|
83
|
-
leadingEnd: number;
|
|
84
|
-
hasLeading: boolean;
|
|
85
|
-
intervals: Array<{
|
|
86
|
-
start: number;
|
|
87
|
-
end: number;
|
|
88
|
-
}>;
|
|
89
|
-
}
|
|
90
|
-
/** The items of poolVotes' deduction system. */
|
|
91
|
-
export type AItem = {
|
|
92
|
-
kind: "region";
|
|
93
|
-
ri: number;
|
|
94
|
-
} | {
|
|
95
|
-
kind: "anchor";
|
|
96
|
-
id: number;
|
|
97
|
-
} | {
|
|
98
|
-
kind: "anchorFocus";
|
|
99
|
-
id: number;
|
|
100
|
-
};
|
|
101
|
-
export interface MindContext extends GraphSearchHost {
|
|
102
|
-
store: Store;
|
|
103
|
-
space: Space;
|
|
104
|
-
alphabet: Alphabet;
|
|
105
|
-
cfg: MindConfig;
|
|
106
|
-
search: GraphSearch;
|
|
107
|
-
trace: Rationale | null;
|
|
108
|
-
/** The content canonicalizer for THIS response, or null — injected by the
|
|
109
|
-
* modality entry point (respondText passes the text canonicalizer; a
|
|
110
|
-
* binary respond passes none). Resolution uses it as a fallback: when
|
|
111
|
-
* the exact content-addressed lookup misses, the span's canonical key is
|
|
112
|
-
* probed against the store's canon index (see src/canon.ts). The core
|
|
113
|
-
* never inspects what the equivalence IS. */
|
|
114
|
-
canon: ((bytes: Uint8Array) => Uint8Array) | null;
|
|
115
|
-
/** Per-response memo of canonical-fallback resolutions, keyed by the
|
|
116
|
-
* span's latin1 content key. Null outside respond(). */
|
|
117
|
-
canonMemo: Map<string, number | null> | null;
|
|
118
|
-
/** Memo of the consensus climb — content-keyed (latin1) so results
|
|
119
|
-
* persist across conversation turns where the same byte spans recur.
|
|
120
|
-
* Null outside respond(); during respondTurn() the conversation's
|
|
121
|
-
* persistent map is swapped in. */
|
|
122
|
-
climbMemo: Map<string, Map<string, AttentionRead>> | null;
|
|
123
|
-
/** Memo of {@link recognise} — content-keyed (latin1) so recognised
|
|
124
|
-
* forms carry forward across conversation turns. Bypassed while a
|
|
125
|
-
* trace is attached. Null outside respond(). */
|
|
126
|
-
recogniseMemo: Map<string, Recognition> | null;
|
|
127
|
-
/** Memo of {@link perceive} — content-keyed (latin1). The general
|
|
128
|
-
* cache the result-level memos each partially compensate for. NOT
|
|
129
|
-
* bypassed under trace — perception emits no rationale steps.
|
|
130
|
-
* Null outside respond(). */
|
|
131
|
-
perceiveMemo: Map<string, Sema> | null;
|
|
132
|
-
/** Subtree-resolution cache: Sema node → its store id and byte length.
|
|
133
|
-
* Populated by {@link foldTree} during inference; checked before
|
|
134
|
-
* walking children. When a conversation's pyramid reuses prefix
|
|
135
|
-
* subtrees, this cache lets {@link recognise} skip them entirely —
|
|
136
|
-
* O(suffix) instead of O(context). Mind-lifetime (WeakMap keys are
|
|
137
|
-
* the Sema objects the pyramid keeps alive). */
|
|
138
|
-
_resolvedSubtrees: WeakMap<Sema, {
|
|
139
|
-
id: number;
|
|
140
|
-
len: number;
|
|
141
|
-
}> | null;
|
|
142
|
-
_edgeGuide: Vec | null;
|
|
143
|
-
_edgeChoice: Map<number, number>;
|
|
144
|
-
_prevSeen: Set<number> | null;
|
|
145
|
-
/** Session cache of node-id → perceived gist, for candidate scoring
|
|
146
|
-
* ({@link chooseAmong} in the reverse projection's recall path re-gists up to
|
|
147
|
-
* √N contexts per pick — the measured bottleneck there). `chooseNext` does
|
|
148
|
-
* NOT use this cache; forward-edge disambiguation uses prevOf counts
|
|
149
|
-
* (distributional evidence) instead of gist comparison, because for short
|
|
150
|
-
* answer candidates the gist is dominated by accidental byte-pattern
|
|
151
|
-
* correlations. A node's bytes are immutable and perception is a pure
|
|
152
|
-
* function of bytes, so an entry stays valid for the store's lifetime —
|
|
153
|
-
* never invalidated. Bounded LRU (byte-sized); a miss only re-perceives,
|
|
154
|
-
* never a correctness risk. */
|
|
155
|
-
_gistCache: BoundedMap<number, Vec>;
|
|
156
|
-
/** DEPOSIT-path stable-prefix tree cache: content key (latin1) of a
|
|
157
|
-
* deposited input → its plain-fold level PYRAMID, so the NEXT deposit
|
|
158
|
-
* whose prefix it is (a conversation's accumulated context) reuses every
|
|
159
|
-
* full aligned block and refolds only the right edge of each level —
|
|
160
|
-
* O(turn) per deposit instead of O(context), with the tree BIT-IDENTICAL
|
|
161
|
-
* to a from-scratch fold (see FoldPyramid). Purely a performance cache.
|
|
162
|
-
* Entry-count bounded (a pyramid is ~KB/byte of content; only the few
|
|
163
|
-
* live conversation chains matter). */
|
|
164
|
-
_depositTrees: BoundedMap<string, FoldPyramid>;
|
|
165
|
-
/** The byte lengths present in {@link _depositTrees} — the candidate
|
|
166
|
-
* prefix lengths probed (longest first). Drifts on eviction (a stale
|
|
167
|
-
* length only costs a miss); cleared with the map when it outgrows the
|
|
168
|
-
* probe budget. */
|
|
169
|
-
_depositLens: Set<number>;
|
|
170
|
-
/** Mind-lifetime intern memo by NODE IDENTITY: perceived-tree node → its
|
|
171
|
-
* content-addressed id. Valid forever (ids are permanent, Sema nodes
|
|
172
|
-
* immutable); WeakMap, so entries live exactly as long as the pyramid
|
|
173
|
-
* cache keeps the shared subtrees alive. Lets internTreeIds skip whole
|
|
174
|
-
* shared subtrees and indexSubSpans keep its seenBefore window skip. */
|
|
175
|
-
_internIds: WeakMap<Sema, number>;
|
|
176
|
-
}
|
|
177
|
-
/** Read a whole node's bytes. */
|
|
178
|
-
export declare const ALL = 2147483647;
|
|
179
|
-
/** Splice every chosen span in order — the whole cover as one byte string. */
|
|
180
|
-
export declare function spliceAll(segs: Seg[]): Uint8Array | null;
|
|
181
|
-
/** Lift the answer out of the cover for think: the recognised region, free of
|
|
182
|
-
* the asker's surrounding (unrecognised) framing. */
|
|
183
|
-
export declare function liftAnswer(segs: Seg[], queryLen: number): Uint8Array | null;
|
|
184
|
-
/** The CHANGED NODES of a freshly-perceived `tree` against the node ids a previous
|
|
185
|
-
* tracked deposit interned (`prevSeen`). */
|
|
186
|
-
export declare function changedNodes(tree: Sema, ids: Map<Sema, number>, prevSeen: Set<number>): Sema[];
|