@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.
- package/AGENTS.md +6 -6
- package/HOW_IT_WORKS.md +16 -0
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/mind/match.ts +81 -0
- package/src/mind/mechanisms/recall.ts +29 -3
- package/test/76-reference-binding.test.mjs +72 -0
- package/dist/example/demo.d.ts +0 -1
- package/dist/example/demo.js +0 -39
- package/dist/example/train_base.d.ts +0 -93
- package/dist/example/train_base.js +0 -2269
- 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 -45
- package/dist/src/canon.js +0 -85
- package/dist/src/config.d.ts +0 -111
- package/dist/src/config.js +0 -91
- package/dist/src/derive/src/deduction.d.ts +0 -136
- package/dist/src/derive/src/deduction.js +0 -159
- package/dist/src/derive/src/index.d.ts +0 -8
- 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 -233
- package/dist/src/geometry.js +0 -1089
- package/dist/src/index.d.ts +0 -17
- package/dist/src/index.js +0 -19
- package/dist/src/ingest-cache.d.ts +0 -41
- package/dist/src/ingest-cache.js +0 -165
- package/dist/src/meter.d.ts +0 -176
- package/dist/src/meter.js +0 -274
- 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 -430
- package/dist/src/mind/attention.js +0 -2418
- package/dist/src/mind/bridge.d.ts +0 -37
- package/dist/src/mind/bridge.js +0 -907
- package/dist/src/mind/canonical.d.ts +0 -34
- package/dist/src/mind/canonical.js +0 -93
- package/dist/src/mind/graph-search.d.ts +0 -294
- package/dist/src/mind/graph-search.js +0 -996
- package/dist/src/mind/index.d.ts +0 -9
- package/dist/src/mind/index.js +0 -5
- package/dist/src/mind/junction.d.ts +0 -137
- package/dist/src/mind/junction.js +0 -358
- package/dist/src/mind/learning.d.ts +0 -75
- package/dist/src/mind/learning.js +0 -265
- package/dist/src/mind/match.d.ts +0 -351
- package/dist/src/mind/match.js +0 -959
- package/dist/src/mind/mechanisms/alu.d.ts +0 -4
- package/dist/src/mind/mechanisms/alu.js +0 -36
- package/dist/src/mind/mechanisms/cast.d.ts +0 -89
- package/dist/src/mind/mechanisms/cast.js +0 -1186
- package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
- package/dist/src/mind/mechanisms/confluence.js +0 -271
- package/dist/src/mind/mechanisms/cover.d.ts +0 -6
- package/dist/src/mind/mechanisms/cover.js +0 -232
- package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
- package/dist/src/mind/mechanisms/extraction.js +0 -327
- package/dist/src/mind/mechanisms/prefix-completion.d.ts +0 -22
- package/dist/src/mind/mechanisms/prefix-completion.js +0 -243
- package/dist/src/mind/mechanisms/recall.d.ts +0 -16
- package/dist/src/mind/mechanisms/recall.js +0 -460
- package/dist/src/mind/mechanisms/reference.d.ts +0 -6
- package/dist/src/mind/mechanisms/reference.js +0 -296
- package/dist/src/mind/mind.d.ts +0 -386
- package/dist/src/mind/mind.js +0 -754
- package/dist/src/mind/pipeline-mechanism.d.ts +0 -238
- package/dist/src/mind/pipeline-mechanism.js +0 -622
- package/dist/src/mind/pipeline.d.ts +0 -49
- package/dist/src/mind/pipeline.js +0 -343
- package/dist/src/mind/primitives.d.ts +0 -85
- package/dist/src/mind/primitives.js +0 -333
- package/dist/src/mind/rationale.d.ts +0 -139
- package/dist/src/mind/rationale.js +0 -163
- package/dist/src/mind/reasoning.d.ts +0 -42
- package/dist/src/mind/reasoning.js +0 -305
- package/dist/src/mind/recognition.d.ts +0 -20
- package/dist/src/mind/recognition.js +0 -696
- package/dist/src/mind/resonance.d.ts +0 -35
- package/dist/src/mind/resonance.js +0 -365
- 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 -196
- package/dist/src/mind/traverse.js +0 -806
- package/dist/src/mind/types.d.ts +0 -418
- package/dist/src/mind/types.js +0 -179
- 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 -313
- package/dist/src/sema.d.ts +0 -41
- package/dist/src/sema.js +0 -77
- package/dist/src/store-sqlite.d.ts +0 -184
- package/dist/src/store-sqlite.js +0 -942
- package/dist/src/store.d.ts +0 -762
- package/dist/src/store.js +0 -1823
- package/dist/src/vec.d.ts +0 -31
- 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
|
-
}
|
package/dist/src/mind/trace.d.ts
DELETED
|
@@ -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;
|
package/dist/src/mind/trace.js
DELETED
|
@@ -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
|
-
}
|