@hviana/sema 0.1.7 → 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/example/train_base.ts +29 -4
- package/package.json +1 -1
- package/src/alu/src/parser.ts +105 -4
- package/src/canon.ts +65 -0
- package/src/geometry.ts +26 -30
- package/src/index.ts +1 -0
- package/src/mind/learning.ts +39 -1
- package/src/mind/match.ts +29 -6
- package/src/mind/mechanisms/cast.ts +33 -13
- package/src/mind/mechanisms/confluence.ts +15 -1
- package/src/mind/mechanisms/recall.ts +116 -41
- package/src/mind/mind.ts +172 -29
- package/src/mind/primitives.ts +66 -1
- package/src/mind/recognition.ts +10 -0
- package/src/mind/types.ts +10 -0
- package/src/store-sqlite.ts +68 -0
- package/src/store.ts +27 -0
- package/test/13-conversation.test.mjs +77 -27
- package/test/35-prefix-edge.test.mjs +86 -0
- 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 -2232
- 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 -212
- package/dist/src/alu/src/parser.js +0 -469
- 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/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 -517
- package/dist/src/index.d.ts +0 -15
- package/dist/src/index.js +0 -17
- 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 -201
- package/dist/src/mind/match.d.ts +0 -111
- package/dist/src/mind/match.js +0 -422
- 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 -447
- package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
- package/dist/src/mind/mechanisms/confluence.js +0 -213
- 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 -166
- package/dist/src/mind/mind.d.ts +0 -211
- package/dist/src/mind/mind.js +0 -433
- 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 -54
- package/dist/src/mind/primitives.js +0 -184
- 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 -236
- 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 -176
- 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 -176
- package/dist/src/store-sqlite.js +0 -890
- package/dist/src/store.d.ts +0 -642
- package/dist/src/store.js +0 -1612
- package/dist/src/vec.d.ts +0 -31
- package/dist/src/vec.js +0 -109
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
// confluence.ts — Confluence Join (Section 4 of the mind).
|
|
2
|
-
//
|
|
3
|
-
// THE CLASS THIS SOLVES: conjunctive queries — answers that are stored in NO
|
|
4
|
-
// single fact and exist only as the INTERSECTION of independent evidence
|
|
5
|
-
// streams. "Which material is translucent and featherlight?" No learnt form
|
|
6
|
-
// contains the answer; each constraint reaches its own set of exemplars, and
|
|
7
|
-
// the entity satisfying both lives exactly where those sets MEET. Every
|
|
8
|
-
// other mechanism produces its answer by following ONE evidence path (a
|
|
9
|
-
// chain, a reverse step, a halo hop, one aligned frame); the consensus climb
|
|
10
|
-
// SUMS votes, fusion CONCATENATES topics, CAST COMPARES two seats — none of
|
|
11
|
-
// them intersects, so this class was previously answered wrong (fusion pairs
|
|
12
|
-
// one fact per constraint, from DIFFERENT entities).
|
|
13
|
-
//
|
|
14
|
-
// THE MEET IS NATIVE, NOT A BYTE SCAN. The store is content-addressed: any
|
|
15
|
-
// content two deposits share IS the same node id, interned once at write
|
|
16
|
-
// time (hash-consing) — so "what do these two facts have in common?" is a
|
|
17
|
-
// SET INTERSECTION OF IDENTITIES the write side already computed, asked
|
|
18
|
-
// through the canonical window read (leafIdRun/findBranch — the same
|
|
19
|
-
// write/read contract recognition runs on). Three identity/structure tests
|
|
20
|
-
// make the whole mechanism:
|
|
21
|
-
//
|
|
22
|
-
// • constraint streams — the consensus climb's ranked anchors, each bound
|
|
23
|
-
// to the query spans whose DISCRIMINATIVE windows it holds by identity
|
|
24
|
-
// (a resonance-voted anchor holding none of the query's discriminative
|
|
25
|
-
// content is no constraint at all); two streams are independent when
|
|
26
|
-
// the content they bind is disjoint;
|
|
27
|
-
// • the meet — window ids present in BOTH anchors and ABSENT from the
|
|
28
|
-
// query: shared-with-query windows are the constraint being re-named
|
|
29
|
-
// (or its scaffolding), so subtracting the query's own window ids
|
|
30
|
-
// leaves exactly the content the question asks FOR — the open seat;
|
|
31
|
-
// • the filler/scaffolding separator — the same structural IDF the climb
|
|
32
|
-
// derives (edgeAncestors' contextsReached): shared content reaching a
|
|
33
|
-
// corpus minority of contexts is an entity, content reaching a majority
|
|
34
|
-
// is frame scaffolding. No statistics, no learning — the same global-
|
|
35
|
-
// quantity-from-capped-local-probes reading that makes the climb's IDF
|
|
36
|
-
// work, pointed at a new question.
|
|
37
|
-
//
|
|
38
|
-
// HONESTY: the meet can only ever name content that structurally exists in
|
|
39
|
-
// two independently learnt exemplars — an empty intersection yields null and
|
|
40
|
-
// the ordinary pipeline decides. Confluence cannot fabricate.
|
|
41
|
-
import { read } from "../primitives.js";
|
|
42
|
-
import { corpusN, reachOf } from "../traverse.js";
|
|
43
|
-
import { dominates } from "../../geometry.js";
|
|
44
|
-
import { STEP } from "../graph-search.js";
|
|
45
|
-
import { unexplainedLabel } from "../rationale.js";
|
|
46
|
-
import { rItem, rNode } from "../trace.js";
|
|
47
|
-
/** The main confluence entry point. Given a query, detect whether it weaves
|
|
48
|
-
* two or more INDEPENDENT constraints (ranked anchors supported by disjoint
|
|
49
|
-
* query spans), intersect the constraints' evidence by content-addressed
|
|
50
|
-
* identity, and return the discriminative content the streams share — the
|
|
51
|
-
* entity that satisfies all constraints at once. Null when the query is
|
|
52
|
-
* not conjunctive or nothing lies in the intersection. */
|
|
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
|
-
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]);
|
|
98
|
-
}
|
|
99
|
-
if (cover.length > 0) {
|
|
100
|
-
streams.push({ anchor: cand.anchor, vote: cand.vote, ids, cover, held });
|
|
101
|
-
}
|
|
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
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
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
|
-
};
|
|
181
|
-
}
|
|
182
|
-
// ── Pipeline mechanism ──────────────────────────────────────────────────────
|
|
183
|
-
export const confluenceMechanism = {
|
|
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
|
-
},
|
|
213
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { MindContext } from "../types.js";
|
|
2
|
-
import type { Site } from "../graph-search.js";
|
|
3
|
-
import type { PipelineMechanism } from "../pipeline-mechanism.js";
|
|
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>>;
|
|
6
|
-
export declare const coverMechanism: PipelineMechanism;
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// mechanisms/cover.ts — Cover (Grounding II): the query's own decomposition
|
|
2
|
-
// composes an answer through ONE lightest-derivation search.
|
|
3
|
-
//
|
|
4
|
-
// Cover consumes recognition directly (its axioms are the query's own
|
|
5
|
-
// decomposition) plus the computed spans any parse()-bearing mechanism
|
|
6
|
-
// contributed: computed spans MASK colliding recognised sites and enter the
|
|
7
|
-
// search at zero cost ("computation always wins", §16.3) — which is also why
|
|
8
|
-
// cover runs FIRST in defaultMechanisms: a computed-backed cover becomes a
|
|
9
|
-
// near-zero-cost incumbent that prunes the other mechanisms through the
|
|
10
|
-
// ordinary admissible-floor check, with no extension special-case anywhere.
|
|
11
|
-
import { read, resolve } from "../primitives.js";
|
|
12
|
-
import { guidedFirst } from "../traverse.js";
|
|
13
|
-
import { conceptHop } from "../match.js";
|
|
14
|
-
import { bridge } from "../resonance.js";
|
|
15
|
-
import { liftAnswer } from "../types.js";
|
|
16
|
-
import { decodeText, unexplainedLabel } from "../rationale.js";
|
|
17
|
-
import { rItem, rNode, traceDerivation } from "../trace.js";
|
|
18
|
-
// ── Concept / connector pre-resolution ──────────────────────────────────────
|
|
19
|
-
export async function resolveConcepts(ctx, sites) {
|
|
20
|
-
const target = new Map();
|
|
21
|
-
const visited = new Set();
|
|
22
|
-
for (const { payload: n } of sites) {
|
|
23
|
-
if (visited.has(n))
|
|
24
|
-
continue;
|
|
25
|
-
visited.add(n);
|
|
26
|
-
if (ctx.store.hasNext(n))
|
|
27
|
-
continue;
|
|
28
|
-
const hop = await conceptHop(ctx, n);
|
|
29
|
-
if (hop !== null)
|
|
30
|
-
target.set(n, hop);
|
|
31
|
-
}
|
|
32
|
-
if (target.size > 0) {
|
|
33
|
-
ctx.trace?.step("resolveConcepts", [...target.keys()].map((n) => rNode(ctx, n, "edgeless-form")), [...target.values()].map((h) => rNode(ctx, h, "concept-sibling")), "borrow a synonym's continuation edge for each edge-less form (a concept/halo hop)");
|
|
34
|
-
}
|
|
35
|
-
return target;
|
|
36
|
-
}
|
|
37
|
-
export async function resolveConnectors(ctx, sites) {
|
|
38
|
-
const links = new Map();
|
|
39
|
-
const ordered = [...sites].sort((a, b) => a.start - b.start);
|
|
40
|
-
const answerOf = (n) => guidedFirst(ctx, n) ?? n;
|
|
41
|
-
const bridgePair = async (l, r) => {
|
|
42
|
-
if (l === r || links.has(l + "," + r))
|
|
43
|
-
return;
|
|
44
|
-
const link = await bridge(ctx, read(ctx, l), read(ctx, r));
|
|
45
|
-
if (link !== null)
|
|
46
|
-
links.set(l + "," + r, link);
|
|
47
|
-
};
|
|
48
|
-
for (let i = 0; i + 1 < ordered.length; i++) {
|
|
49
|
-
if (ordered[i].end !== ordered[i + 1].start)
|
|
50
|
-
continue;
|
|
51
|
-
const lefts = [ordered[i].payload, answerOf(ordered[i].payload)];
|
|
52
|
-
const rights = [ordered[i + 1].payload, answerOf(ordered[i + 1].payload)];
|
|
53
|
-
for (const l of new Set(lefts)) {
|
|
54
|
-
for (const r of new Set(rights)) {
|
|
55
|
-
await bridgePair(l, r);
|
|
56
|
-
await bridgePair(r, l);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const orderedNodes = [];
|
|
61
|
-
const seenN = new Set();
|
|
62
|
-
for (const s of ordered) {
|
|
63
|
-
const node = guidedFirst(ctx, s.payload) ?? s.payload;
|
|
64
|
-
if (seenN.has(node))
|
|
65
|
-
continue;
|
|
66
|
-
seenN.add(node);
|
|
67
|
-
orderedNodes.push({ node, bytes: read(ctx, node) });
|
|
68
|
-
}
|
|
69
|
-
if (orderedNodes.length >= 3) {
|
|
70
|
-
const first = orderedNodes[0];
|
|
71
|
-
const W = ctx.space.maxGroup;
|
|
72
|
-
let middleBytes = 0; // Σ bytes of the answers BETWEEN first and m-th
|
|
73
|
-
for (let m = 1; m < orderedNodes.length; m++) {
|
|
74
|
-
const key = first.node + "," + orderedNodes[m].node;
|
|
75
|
-
if (links.has(key)) {
|
|
76
|
-
middleBytes += orderedNodes[m].bytes.length;
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
// The N-ary interior legitimately holds every intermediate answer
|
|
80
|
-
// plus one W-quantum of glue per joint — pass that allowance so the
|
|
81
|
-
// bridge's phrase-scale cap admits the whole learnt run.
|
|
82
|
-
const allowance = middleBytes + (m + 1) * W;
|
|
83
|
-
const interior = await bridge(ctx, first.bytes, orderedNodes[m].bytes, allowance);
|
|
84
|
-
if (interior !== null)
|
|
85
|
-
links.set(key, interior);
|
|
86
|
-
middleBytes += orderedNodes[m].bytes.length;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (links.size > 0) {
|
|
90
|
-
ctx.trace?.step("resolveConnectors", ordered.map((s) => rItem(read(ctx, s.payload), "answer", s.payload)), [...links.entries()].map(([pair, bytes]) => ({
|
|
91
|
-
text: `${pair}: "${decodeText(bytes)}"`,
|
|
92
|
-
role: "connector",
|
|
93
|
-
})), "the bytes the graph splices between adjacent answers (asked of the gist space)");
|
|
94
|
-
}
|
|
95
|
-
return links;
|
|
96
|
-
}
|
|
97
|
-
// ── Pipeline mechanism ──────────────────────────────────────────────────────
|
|
98
|
-
export const coverMechanism = {
|
|
99
|
-
name: "cover",
|
|
100
|
-
provenance: "cover",
|
|
101
|
-
async floor(_ctx, _query, _pre, _worthRunning) {
|
|
102
|
-
return 0;
|
|
103
|
-
},
|
|
104
|
-
async run(ctx, query, pre) {
|
|
105
|
-
const { rec, computed } = pre;
|
|
106
|
-
// Masking: computed spans are authoritative. Remove recognised sites
|
|
107
|
-
// that overlap any computed span before building the cover search.
|
|
108
|
-
const sites = computed.length === 0
|
|
109
|
-
? rec.sites
|
|
110
|
-
: rec.sites.filter((s) => !computed.some((u) => s.start < u.j && u.i < s.end));
|
|
111
|
-
if (computed.length > 0 && sites.length < rec.sites.length) {
|
|
112
|
-
ctx.trace?.step("maskByComputation", rec.sites.map((s) => rItem(query.subarray(s.start, s.end), "form", s.payload, [
|
|
113
|
-
s.start,
|
|
114
|
-
s.end,
|
|
115
|
-
])), sites.map((s) => rItem(query.subarray(s.start, s.end), "form", s.payload, [
|
|
116
|
-
s.start,
|
|
117
|
-
s.end,
|
|
118
|
-
])), "a computation always wins: recognised forms overlapping a computed span are dropped");
|
|
119
|
-
}
|
|
120
|
-
if (sites.length === 0 && computed.length === 0)
|
|
121
|
-
return [];
|
|
122
|
-
const connectors = await resolveConnectors(ctx, sites);
|
|
123
|
-
let splits = rec.splits;
|
|
124
|
-
if (computed.length > 0) {
|
|
125
|
-
splits = new Set(rec.splits);
|
|
126
|
-
for (const u of computed) {
|
|
127
|
-
splits.add(u.i);
|
|
128
|
-
splits.add(u.j);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const concepts = await resolveConcepts(ctx, sites);
|
|
132
|
-
const coverDeps = [
|
|
133
|
-
ctx.trace?.lastIndex("recognise"),
|
|
134
|
-
ctx.trace?.lastIndex("computeExtensions"),
|
|
135
|
-
ctx.trace?.lastIndex("resolveConcepts"),
|
|
136
|
-
ctx.trace?.lastIndex("resolveConnectors"),
|
|
137
|
-
].filter((x) => x !== undefined);
|
|
138
|
-
// Convert ComputedSpan[] to ComputedResult[] for the graph search.
|
|
139
|
-
const computedResults = computed.map((u) => ({
|
|
140
|
-
i: u.i,
|
|
141
|
-
j: u.j,
|
|
142
|
-
bytes: u.bytes,
|
|
143
|
-
node: resolve(ctx, u.bytes) ?? undefined,
|
|
144
|
-
}));
|
|
145
|
-
const tCover = ctx.trace?.enter("cover", [
|
|
146
|
-
...sites.map((s) => rItem(query.subarray(s.start, s.end), "form", s.payload, [
|
|
147
|
-
s.start,
|
|
148
|
-
s.end,
|
|
149
|
-
])),
|
|
150
|
-
...computedResults.map((u) => rItem(u.bytes, "computed")),
|
|
151
|
-
], coverDeps.length ? coverDeps : undefined);
|
|
152
|
-
const solved = ctx.search.cover(query.length, sites, concepts, rec.leaves, splits, undefined, connectors, computedResults, ctx.trace ? (steps) => traceDerivation(ctx, steps) : undefined);
|
|
153
|
-
const segs = solved && solved.segs;
|
|
154
|
-
tCover?.done(segs === null
|
|
155
|
-
? []
|
|
156
|
-
: segs.map((s) => rItem(s.bytes, s.rec ? "chosen" : "bridge", s.node, [s.i, s.j])), segs === null
|
|
157
|
-
? "no cover of the query composed"
|
|
158
|
-
: "lightest derivation: the chosen spans, left to right");
|
|
159
|
-
if (segs === null)
|
|
160
|
-
return [];
|
|
161
|
-
const composed = liftAnswer(segs, query.length);
|
|
162
|
-
if (composed === null)
|
|
163
|
-
return [];
|
|
164
|
-
ctx.trace?.step("liftAnswer", segs.map((s) => rItem(s.bytes, s.rec ? "chosen" : "scaffolding", s.node, [s.i, s.j])), [rItem(composed, "answer", resolve(ctx, composed) ?? undefined)], "lift the recognised region out of the asker's framing", tCover ? [tCover.index] : undefined);
|
|
165
|
-
// accounted = RECOGNISED cover spans only — PASS-carried bytes
|
|
166
|
-
// are priced in cost already; the diagnostic label reflects the
|
|
167
|
-
// same distinction.
|
|
168
|
-
const accounted = segs
|
|
169
|
-
.filter((s) => s.rec)
|
|
170
|
-
.map((s) => [s.i, s.j]);
|
|
171
|
-
return [{
|
|
172
|
-
bytes: composed,
|
|
173
|
-
accounted,
|
|
174
|
-
moves: 0,
|
|
175
|
-
weight: solved.cost, // A*LD derivation's g-value IS the weight
|
|
176
|
-
unexplained: unexplainedLabel(query, accounted),
|
|
177
|
-
}];
|
|
178
|
-
},
|
|
179
|
-
};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { Vec } from "../../vec.js";
|
|
2
|
-
import type { MindContext } from "../types.js";
|
|
3
|
-
import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
|
|
4
|
-
/** Find the first span-shaped skill exemplar among the ranked anchors from
|
|
5
|
-
* climbAttentionAll and read the analogous span from the query. Returns
|
|
6
|
-
* the extracted bytes PLUS the query spans the skill ACCOUNTED FOR — the
|
|
7
|
-
* located frames AND any read span BOUNDED by located frames on both
|
|
8
|
-
* sides, the elementary evidence think's grounding decider weighs. A
|
|
9
|
-
* bounded read is explained: the skill located both its borders in the
|
|
10
|
-
* query and emitted exactly what sits between them. An OPEN-ENDED read
|
|
11
|
-
* (the exemplar's answer reaches the context's end, so the query is read
|
|
12
|
-
* to its own end with no located right border) remains a guess about where
|
|
13
|
-
* the span stops — it stays unaccounted, priced by exclusion like the
|
|
14
|
-
* cover's bridged bytes. (Accounting frames only — the earlier convention
|
|
15
|
-
* — let a CAST juxtaposition that merely echoed the query's exact site
|
|
16
|
-
* outweigh a correct bounded extraction: the same span counted as
|
|
17
|
-
* explained for one mechanism and not the other, and the asymmetry, not
|
|
18
|
-
* the answers' merits, decided the grounding.) Null when no skill
|
|
19
|
-
* applies. */
|
|
20
|
-
export declare function extractBySkill(ctx: MindContext, query: Uint8Array, pre: Precomputed): Promise<{
|
|
21
|
-
bytes: Uint8Array;
|
|
22
|
-
accounted: Array<[number, number]>;
|
|
23
|
-
unexplained: string;
|
|
24
|
-
} | null>;
|
|
25
|
-
/** Decompose an answer into substrings of its surrounding context, in order —
|
|
26
|
-
* the STRONG span-shape reading (see the section note above). Returns null
|
|
27
|
-
* when no greedy longest-run decomposition exists. Adjacent runs that
|
|
28
|
-
* connect contiguously are merged. */
|
|
29
|
-
export declare function answerRunsInContext(_ctx: MindContext, context: Uint8Array, answer: Uint8Array): Array<{
|
|
30
|
-
start: number;
|
|
31
|
-
end: number;
|
|
32
|
-
ansLen: number;
|
|
33
|
-
}> | null;
|
|
34
|
-
/** Check whether an anchor is a span-shaped skill exemplar: it represents a
|
|
35
|
-
* fact whose context and answer together form a span-in-context pattern.
|
|
36
|
-
* If the anchor has a nextOf continuation, that is the answer and the anchor
|
|
37
|
-
* itself is the context. Otherwise the anchor's prevOf parents provide
|
|
38
|
-
* candidate contexts, and the longest one whose span is span-shaped wins. */
|
|
39
|
-
export declare function skillExemplar(ctx: MindContext, anchor: number, guide?: Vec | null): Promise<{
|
|
40
|
-
contextBytes: Uint8Array;
|
|
41
|
-
answerBytes: Uint8Array;
|
|
42
|
-
} | null>;
|
|
43
|
-
/** Whether the answer is a SPARSE subsequence of the context (bytes in
|
|
44
|
-
* order, arbitrary gaps) — the OPEN span-shape reading (see the section
|
|
45
|
-
* note above). This is what lets extraction validate a MULTI-PIECE
|
|
46
|
-
* exemplar whose answer is stitched from several context runs — but it is
|
|
47
|
-
* deliberately permissive, so it must never be used as evidence that one
|
|
48
|
-
* span was "drawn from" another (see {@link containsSpan} for that).
|
|
49
|
-
*
|
|
50
|
-
* There is deliberately NO containsSpan pre-check here: strict containment
|
|
51
|
-
* IMPLIES the subsequence embedding (a contiguous run, or a resolved node —
|
|
52
|
-
* whose content-addressed identity means its bytes occur contiguously — is
|
|
53
|
-
* an in-order embedding with zero gaps), so the scan below decides alone,
|
|
54
|
-
* with the same truth value. The old pre-check re-perceived the context
|
|
55
|
-
* (a full river fold) per CANDIDATE in skillExemplar's √N-capped loop —
|
|
56
|
-
* pure cost, no discrimination. */
|
|
57
|
-
export declare function isSpanShaped(_ctx: MindContext, context: Uint8Array, answer: Uint8Array): boolean;
|
|
58
|
-
/** STRICT containment: the answer's resolved node appears in the context's
|
|
59
|
-
* folded tree, or the answer occurs as one CONTIGUOUS byte run of the
|
|
60
|
-
* context. This is real evidence the answer was drawn from the context.
|
|
61
|
-
* Fusion gates on this — the sparse-subsequence reading of
|
|
62
|
-
* {@link isSpanShaped} is trivially satisfied by short answers over long
|
|
63
|
-
* queries ("cold" is a gap-tolerant subsequence of most sentences holding
|
|
64
|
-
* c…o…l…d in order), and gating fusion on it silently starved multi-topic
|
|
65
|
-
* queries of their further points of attention. */
|
|
66
|
-
export declare function containsSpan(ctx: MindContext, context: Uint8Array, answer: Uint8Array): boolean;
|
|
67
|
-
export declare const extractionMechanism: PipelineMechanism;
|