@hviana/sema 0.5.2 → 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 +115 -53
- package/HOW_IT_WORKS.md +291 -184
- package/jsr.json +6 -0
- package/package.json +1 -1
- package/src/mind/bridge.ts +10 -104
- package/src/mind/match.ts +497 -7
- package/src/mind/{prefix-completion.ts → mechanisms/prefix-completion.ts} +66 -92
- package/src/mind/mechanisms/recall.ts +38 -129
- package/src/mind/mechanisms/reference.ts +343 -0
- package/src/mind/mind.ts +12 -8
- package/src/mind/pipeline-mechanism.ts +120 -3
- package/src/mind/pipeline.ts +16 -2
- package/src/mind/traverse.ts +92 -1
- package/src/store.ts +13 -4
- package/test/33-multi-candidate.test.mjs +21 -11
- package/test/70-prefix-completion.test.mjs +1 -1
- package/test/72-prefix-candidate-supply.test.mjs +7 -9
- package/test/74-prefix-trap-not-sprung-early.test.mjs +1 -1
- package/test/76-reference-binding.test.mjs +543 -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 -39
- package/dist/src/mind/bridge.js +0 -998
- package/dist/src/mind/canonical.d.ts +0 -34
- package/dist/src/mind/canonical.js +0 -93
- package/dist/src/mind/frame-filler.d.ts +0 -15
- package/dist/src/mind/frame-filler.js +0 -535
- 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 -192
- package/dist/src/mind/match.js +0 -666
- 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/recall.d.ts +0 -16
- package/dist/src/mind/mechanisms/recall.js +0 -558
- 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 -183
- package/dist/src/mind/pipeline-mechanism.js +0 -521
- package/dist/src/mind/pipeline.d.ts +0 -49
- package/dist/src/mind/pipeline.js +0 -331
- package/dist/src/mind/prefix-completion.d.ts +0 -59
- package/dist/src/mind/prefix-completion.js +0 -270
- 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 -158
- package/dist/src/mind/traverse.js +0 -716
- 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
- package/src/mind/frame-filler.ts +0 -604
- package/test/69-frame-filler.test.mjs +0 -115
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
// pipeline-mechanism.ts — the uniform grounding-mechanism interface.
|
|
2
|
-
//
|
|
3
|
-
// Every grounding mechanism (CAST, confluence, cover, extraction, recall, ALU,
|
|
4
|
-
// user extensions) implements this ONE interface. The pipeline (think()) sees
|
|
5
|
-
// a list of PipelineMechanism objects — it never imports a mechanism-specific
|
|
6
|
-
// type and never has a special-case branch for any mechanism.
|
|
7
|
-
//
|
|
8
|
-
// The four constraints of the free-will architecture (§14.5):
|
|
9
|
-
// 1. DECOUPLING — mechanisms import nothing from each other or from pipeline.
|
|
10
|
-
// 2. DECLARED COMPETENCE — floor() returns null when impossible, a number when
|
|
11
|
-
// possible. Binary, auditable, no learned scores.
|
|
12
|
-
// 3. VISIBLE BUDGET — every mechanism carries its own caps internally (√N, k).
|
|
13
|
-
// 4. TRAVELING EVIDENCE — run() returns MechanismResult with accounted, moves,
|
|
14
|
-
// and unexplained. The pipeline computes the weight.
|
|
15
|
-
import { indexOf } from "../bytes.js";
|
|
16
|
-
import { dominates } from "../geometry.js";
|
|
17
|
-
import { windowIds } from "./canonical.js";
|
|
18
|
-
import { read, resolve } from "./primitives.js";
|
|
19
|
-
import { alignGraded, skillExemplar } from "./match.js";
|
|
20
|
-
import { climbAttentionAll } from "./attention.js";
|
|
21
|
-
import { sharedReachMemo } from "./traverse.js";
|
|
22
|
-
// ── Precomputed ──────────────────────────────────────────────────────────────
|
|
23
|
-
//
|
|
24
|
-
// Precomputed is a LAZY container for structural analyses of the query — the
|
|
25
|
-
// ONE place a response's shared evidence lives, for inter-mechanism exchange
|
|
26
|
-
// and for analyses future mechanisms will want. Eager fields (rec, computed,
|
|
27
|
-
// guide) are populated by the pipeline before the mechanism loop; everything
|
|
28
|
-
// expensive is a lazily-cached method that computes on first access. A
|
|
29
|
-
// mechanism that never asks for an analysis pays nothing for it; two
|
|
30
|
-
// mechanisms asking for the same analysis pay once.
|
|
31
|
-
//
|
|
32
|
-
// This design serves THREE purposes:
|
|
33
|
-
// 1. SHARING — when two mechanisms need the same analysis, it's computed once
|
|
34
|
-
// (even under trace, where the ctx-level memos are deliberately bypassed).
|
|
35
|
-
// 2. EXTENSIBILITY — a new analysis is one method in one file.
|
|
36
|
-
// 3. DECLARATIVE COST — a mechanism's floor() checks its cheap gates and the
|
|
37
|
-
// pipeline's `worthRunning` predicate BEFORE first-touching an expensive
|
|
38
|
-
// analysis, so lazy analyses are only ever computed for a mechanism that
|
|
39
|
-
// could still win.
|
|
40
|
-
export class Precomputed {
|
|
41
|
-
ctx;
|
|
42
|
-
query;
|
|
43
|
-
rec;
|
|
44
|
-
computed;
|
|
45
|
-
guide;
|
|
46
|
-
/** The response's evidence-breadth constant: how many ranked candidates the
|
|
47
|
-
* resonance probes, the weave alignment, and the climb all consider.
|
|
48
|
-
* Derived once from config; every consumer reads it here. */
|
|
49
|
-
k;
|
|
50
|
-
constructor(ctx, query,
|
|
51
|
-
/** Recognition result (structural + canonical). */
|
|
52
|
-
rec,
|
|
53
|
-
/** Computed spans from mechanisms that implement `parse()` (e.g. ALU). */
|
|
54
|
-
computed,
|
|
55
|
-
/** The query's gist — the response-wide disambiguation guide. */
|
|
56
|
-
guide) {
|
|
57
|
-
this.ctx = ctx;
|
|
58
|
-
this.query = query;
|
|
59
|
-
this.rec = rec;
|
|
60
|
-
this.computed = computed;
|
|
61
|
-
this.guide = guide;
|
|
62
|
-
this.k = ctx.cfg.recallQueryK * 2;
|
|
63
|
-
}
|
|
64
|
-
// ── Cheap lazy analyses ───────────────────────────────────────────────
|
|
65
|
-
_windows;
|
|
66
|
-
/** Content-addressed W-window identities for every position in the query
|
|
67
|
-
* (offset → node id). O(|query|) probes. */
|
|
68
|
-
get queryWindows() {
|
|
69
|
-
return this._windows ??= windowIds(this.ctx, this.query);
|
|
70
|
-
}
|
|
71
|
-
_resolved;
|
|
72
|
-
/** The node id of the query itself, or null when it is not a stored form.
|
|
73
|
-
* O(|query|) probes. */
|
|
74
|
-
get queryResolved() {
|
|
75
|
-
if (this._resolved === undefined) {
|
|
76
|
-
this._resolved = resolve(this.ctx, this.query);
|
|
77
|
-
}
|
|
78
|
-
return this._resolved;
|
|
79
|
-
}
|
|
80
|
-
_anchorWindows = new Map();
|
|
81
|
-
/** Content-addressed W-window identities of one anchor's own bytes
|
|
82
|
-
* (offset → node id), memoised per anchor. Confluence intersects these;
|
|
83
|
-
* any future identity-based mechanism reads the same cache. */
|
|
84
|
-
windowsOf(anchor) {
|
|
85
|
-
let w = this._anchorWindows.get(anchor);
|
|
86
|
-
if (w === undefined) {
|
|
87
|
-
w = windowIds(this.ctx, read(this.ctx, anchor));
|
|
88
|
-
this._anchorWindows.set(anchor, w);
|
|
89
|
-
}
|
|
90
|
-
return w;
|
|
91
|
-
}
|
|
92
|
-
/** Shared memo for {@link reachOf} (structural-IDF reads): a window's
|
|
93
|
-
* ancestor reach is a pure function of the read-only store, so one memo
|
|
94
|
-
* serves every mechanism that prices commonality — AND the consensus
|
|
95
|
-
* climb, which is the largest consumer and used to build its own. The
|
|
96
|
-
* ONE definition of its lifetime lives in traverse.ts
|
|
97
|
-
* ({@link sharedReachMemo}): session-scoped between writes and always cold
|
|
98
|
-
* under a trace. */
|
|
99
|
-
_reach;
|
|
100
|
-
get reachMemo() {
|
|
101
|
-
return this._reach ??= sharedReachMemo(this.ctx);
|
|
102
|
-
}
|
|
103
|
-
// ── Expensive lazy analyses ───────────────────────────────────────────
|
|
104
|
-
//
|
|
105
|
-
// Async, cached-by-promise: the first caller starts the computation, every
|
|
106
|
-
// later caller (any mechanism, any phase) awaits the same promise. A
|
|
107
|
-
// mechanism MUST check its cheap floor gates and the pipeline's
|
|
108
|
-
// `worthRunning` predicate before first-touching one of these.
|
|
109
|
-
/** Charge a lazily-shared analysis to its OWN phase rather than to the
|
|
110
|
-
* mechanism that happened to first-touch it. Without this the profile
|
|
111
|
-
* reads as "cast.floor costs 2 s" when what actually cost 2 s is the
|
|
112
|
-
* consensus climb — which cast merely paid for on everyone's behalf, and
|
|
113
|
-
* which every later consumer then got free. Attribution must follow the
|
|
114
|
-
* work, not the caller. */
|
|
115
|
-
shared(phase, fn) {
|
|
116
|
-
const meter = this.ctx.meter;
|
|
117
|
-
return meter ? meter.time(phase, fn) : fn();
|
|
118
|
-
}
|
|
119
|
-
_attention;
|
|
120
|
-
/** The full consensus climb (roots + ranked anchors) — the query-level
|
|
121
|
-
* evidence CAST, confluence, extraction, recall's scaffolding tier, and
|
|
122
|
-
* fusion all share. Computed on first access; a query no mechanism
|
|
123
|
-
* climbs for (e.g. one an extension decided outright) never pays for it. */
|
|
124
|
-
attention() {
|
|
125
|
-
return this._attention ??= this.shared("attention", () => climbAttentionAll(this.ctx, this.query, this.k));
|
|
126
|
-
}
|
|
127
|
-
_weave;
|
|
128
|
-
/** Result of {@link alignGraded} for the first k ranked anchors —
|
|
129
|
-
* O(k · |query| · |ctx|). Consumed by CAST; reusable by any future
|
|
130
|
-
* mechanism doing analogical transfer. */
|
|
131
|
-
weave() {
|
|
132
|
-
return this._weave ??= this.attention().then((climb) => this.shared("weave", async () => computeWeave(this.ctx, this.query, this, climb)));
|
|
133
|
-
}
|
|
134
|
-
/** Span-shaped classification of one ranked anchor, memoised per anchor id
|
|
135
|
-
* so repeated calls (extraction's own early-exit scan, any future
|
|
136
|
-
* template-based mechanism) never redo the work. Deliberately NOT an
|
|
137
|
-
* eager all-anchors map: `skillExemplar` is the expensive part of
|
|
138
|
-
* extraction (capped fan-out reads plus an O(|ctx|) scan), and most
|
|
139
|
-
* queries are answered by the FIRST ranked anchor that qualifies — paying
|
|
140
|
-
* for every ranked anchor regardless of where the scan stops would turn
|
|
141
|
-
* an early-exit lookup into full O(k) work on every query. */
|
|
142
|
-
_spanShaped = new Map();
|
|
143
|
-
spanShapedOf(anchor) {
|
|
144
|
-
let p = this._spanShaped.get(anchor);
|
|
145
|
-
if (p === undefined) {
|
|
146
|
-
p = this.shared("spanShaped", () => skillExemplar(this.ctx, anchor, this.guide));
|
|
147
|
-
this._spanShaped.set(anchor, p);
|
|
148
|
-
}
|
|
149
|
-
return p;
|
|
150
|
-
}
|
|
151
|
-
/** Every ranked anchor's classification at once, sharing the same
|
|
152
|
-
* per-anchor cache as {@link spanShapedOf} — for a mechanism that
|
|
153
|
-
* genuinely needs the full picture (not an early-exit scan). Mixing
|
|
154
|
-
* access patterns across mechanisms never duplicates work: whichever
|
|
155
|
-
* anchors an early-exit consumer already asked for are reused here, and
|
|
156
|
-
* whichever this computes first are reused by a later early-exit scan. */
|
|
157
|
-
async spanShapedAll() {
|
|
158
|
-
const { ranked } = await this.attention();
|
|
159
|
-
const out = new Map();
|
|
160
|
-
for (const cand of ranked) {
|
|
161
|
-
if (out.has(cand.anchor))
|
|
162
|
-
continue;
|
|
163
|
-
out.set(cand.anchor, await this.spanShapedOf(cand.anchor));
|
|
164
|
-
}
|
|
165
|
-
return out;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
function computeWeave(ctx, query, pre, climb) {
|
|
169
|
-
const quantum = ctx.space.maxGroup;
|
|
170
|
-
const { ranked } = climb;
|
|
171
|
-
const rankedCapped = ranked.length > pre.k ? ranked.slice(0, pre.k) : ranked;
|
|
172
|
-
const depth = new Float64Array(query.length);
|
|
173
|
-
const points = [];
|
|
174
|
-
const byAnchor = new Map();
|
|
175
|
-
// WEAVE-SCALE anchors only: CAST transfers structure between things the
|
|
176
|
-
// QUERY weaves together — query-scale structures. A context an order of
|
|
177
|
-
// magnitude beyond the query is not woven BY the query (the query can at
|
|
178
|
-
// most quote a fragment of it, and fragment-level evidence is exactly what
|
|
179
|
-
// recognition and the cover already handle); CAST's own comparison gate
|
|
180
|
-
// demands `ctx.length ≤ query.length` before it fires, and its
|
|
181
|
-
// substitution seats sit within a quantum of a context's start. W is the
|
|
182
|
-
// perceptual quantum — the same scale multiplier the bridge's phrase-scale
|
|
183
|
-
// contract uses. The prefix-capped read makes an oversized anchor cost a
|
|
184
|
-
// bounded read instead of reconstructing (and then canonically
|
|
185
|
-
// recognising) a corpus-sized deposit: profiled on a 17.7M-node store,
|
|
186
|
-
// uncapped weaves spent 5–8s per query recognising conversation-length
|
|
187
|
-
// anchors that could never form a weave point.
|
|
188
|
-
const askerBytes = query.length -
|
|
189
|
-
ctx.answeredSpans.reduce((n, [start, end]) => n + end - start, 0);
|
|
190
|
-
const capBytes = askerBytes * quantum;
|
|
191
|
-
// RUNS ARE NOT TRIMMED AGAINST EACH OTHER. A point keeps every byte it
|
|
192
|
-
// aligned; exclusivity is a property of STRUCTURES (see "one place, one
|
|
193
|
-
// structure" below), not of individual query bytes.
|
|
194
|
-
//
|
|
195
|
-
// This weave used to build points in the climb's vote order and cut each new
|
|
196
|
-
// point's runs against every point already accepted. It is worth recording
|
|
197
|
-
// what that cost, because the cut was invisible: it did not just resolve
|
|
198
|
-
// ties, it silently DECIDED downstream schemas. A point's `runs[0]` — the
|
|
199
|
-
// run three CAST branches read as "the filler", "the seat", "the name" — was
|
|
200
|
-
// whichever run happened to survive the cut, so those schemas were reading an
|
|
201
|
-
// elimination order as though it were evidence, and the query's own bytes
|
|
202
|
-
// were truncated on the way ("Shakespeare" surviving as "Shakes"). Each
|
|
203
|
-
// consumer now derives its own reading from the runs (cast.ts: `fillerRun`
|
|
204
|
-
// clips at the seat, redirection scans for the naming run, entry counts own
|
|
205
|
-
// bytes and the climb's dispersion), and with those in place removing the cut
|
|
206
|
-
// costs nothing — measured, the same 442 tests pass either way.
|
|
207
|
-
//
|
|
208
|
-
// What the vote order was RIGHT about is kept: which structures belong in the
|
|
209
|
-
// weave is the climb's call, not a local run measure. Arbitrating byte
|
|
210
|
-
// ownership by local evidence instead (longest covering run, then weight,
|
|
211
|
-
// then rank) was implemented and MEASURED, and it evicted the committed
|
|
212
|
-
// root's own evidence — CAST then refused on its own consistency check ("2
|
|
213
|
-
// aligned structure(s), but none is one of the climb's 1 committed root(s)"),
|
|
214
|
-
// test/29 going 9/2 to 7/4. Weave-local measures decide what is FRAME inside
|
|
215
|
-
// the weave (see the frame gates in cast.ts); membership stays the climb's.
|
|
216
|
-
//
|
|
217
|
-
// TWO PASSES. `depth` — how much of the weave agrees on each query byte, and
|
|
218
|
-
// therefore what counts as FRAME — must be the whole weave's, not "whatever
|
|
219
|
-
// has been processed so far": read in one pass it made a candidate's own
|
|
220
|
-
// frame reading depend on its rank, and the proposed-run gate below needs the
|
|
221
|
-
// real thing.
|
|
222
|
-
const cands = [];
|
|
223
|
-
const querySegments = [];
|
|
224
|
-
let segmentStart = 0;
|
|
225
|
-
for (const [start, end] of ctx.answeredSpans) {
|
|
226
|
-
if (segmentStart < start)
|
|
227
|
-
querySegments.push([segmentStart, start]);
|
|
228
|
-
segmentStart = Math.max(segmentStart, end);
|
|
229
|
-
}
|
|
230
|
-
if (segmentStart < query.length) {
|
|
231
|
-
querySegments.push([segmentStart, query.length]);
|
|
232
|
-
}
|
|
233
|
-
const weaveLength = querySegments.reduce((n, [s, e]) => n + e - s, 0);
|
|
234
|
-
const weaveQuery = new Uint8Array(weaveLength);
|
|
235
|
-
const weaveMap = [];
|
|
236
|
-
let compactStart = 0;
|
|
237
|
-
for (const [start, end] of querySegments) {
|
|
238
|
-
weaveQuery.set(query.subarray(start, end), compactStart);
|
|
239
|
-
weaveMap.push({
|
|
240
|
-
compactStart,
|
|
241
|
-
originalStart: start,
|
|
242
|
-
length: end - start,
|
|
243
|
-
});
|
|
244
|
-
compactStart += end - start;
|
|
245
|
-
}
|
|
246
|
-
const segmentOf = (start, end) => {
|
|
247
|
-
let lo = 0;
|
|
248
|
-
let hi = weaveMap.length;
|
|
249
|
-
while (lo < hi) {
|
|
250
|
-
const mid = (lo + hi) >>> 1;
|
|
251
|
-
if (weaveMap[mid].originalStart <= start)
|
|
252
|
-
lo = mid + 1;
|
|
253
|
-
else
|
|
254
|
-
hi = mid;
|
|
255
|
-
}
|
|
256
|
-
const part = lo > 0 ? weaveMap[lo - 1] : undefined;
|
|
257
|
-
return part && end <= part.originalStart + part.length ? part : undefined;
|
|
258
|
-
};
|
|
259
|
-
const weaveSites = pre.rec.sites.flatMap((s) => {
|
|
260
|
-
const part = segmentOf(s.start, s.end);
|
|
261
|
-
return part
|
|
262
|
-
? [{
|
|
263
|
-
...s,
|
|
264
|
-
start: part.compactStart + s.start - part.originalStart,
|
|
265
|
-
end: part.compactStart + s.end - part.originalStart,
|
|
266
|
-
}]
|
|
267
|
-
: [];
|
|
268
|
-
});
|
|
269
|
-
for (const cand of rankedCapped) {
|
|
270
|
-
const ctxBytes = read(ctx, cand.anchor, capBytes + 1);
|
|
271
|
-
if (ctxBytes.length === 0 || ctxBytes.length > capBytes)
|
|
272
|
-
continue;
|
|
273
|
-
// CAST compares structures stated by the asker. Completed assistant turns
|
|
274
|
-
// remain available to recognition and the climb as conversation context,
|
|
275
|
-
// but aligning every candidate across their full prose makes weave work
|
|
276
|
-
// grow with answer length and lets the engine analogise against its own
|
|
277
|
-
// previous output. The compact asker stream is aligned once (so candidate
|
|
278
|
-
// windows are not rebuilt per turn), then every run is split back across
|
|
279
|
-
// the original turn segments so no evidence crosses an omitted boundary.
|
|
280
|
-
const raw = alignGraded(ctx, weaveQuery, ctxBytes, weaveSites).flatMap((r) => {
|
|
281
|
-
let lo = 0;
|
|
282
|
-
let hi = weaveMap.length;
|
|
283
|
-
while (lo < hi) {
|
|
284
|
-
const mid = (lo + hi) >>> 1;
|
|
285
|
-
if (weaveMap[mid].compactStart <= r.qs)
|
|
286
|
-
lo = mid + 1;
|
|
287
|
-
else
|
|
288
|
-
hi = mid;
|
|
289
|
-
}
|
|
290
|
-
const out = [];
|
|
291
|
-
for (let pi = Math.max(0, lo - 1); pi < weaveMap.length; pi++) {
|
|
292
|
-
const part = weaveMap[pi];
|
|
293
|
-
if (part.compactStart >= r.qe)
|
|
294
|
-
break;
|
|
295
|
-
const partEnd = part.compactStart + part.length;
|
|
296
|
-
const start = Math.max(r.qs, part.compactStart);
|
|
297
|
-
const end = Math.min(r.qe, partEnd);
|
|
298
|
-
if (start >= end)
|
|
299
|
-
continue;
|
|
300
|
-
out.push({
|
|
301
|
-
...r,
|
|
302
|
-
qs: part.originalStart + start - part.compactStart,
|
|
303
|
-
qe: part.originalStart + end - part.compactStart,
|
|
304
|
-
cs: r.cs + start - r.qs,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
return out;
|
|
308
|
-
});
|
|
309
|
-
if (raw.length === 0)
|
|
310
|
-
continue;
|
|
311
|
-
// DEPTH COUNTS STRUCTURES, NOT WEIGHT. The frame test is
|
|
312
|
-
// `dominates(depth[i], aligned)` — "more than half the weave shares this
|
|
313
|
-
// byte" — and `aligned` is a COUNT of points. Accumulating graded
|
|
314
|
-
// alignment WEIGHT here compared weight-mass against a cardinality: two
|
|
315
|
-
// different dimensions, meaningful only while truncation happened to keep
|
|
316
|
-
// points.length small and weights near 1.
|
|
317
|
-
//
|
|
318
|
-
// Measured (test/29 C2, only truncation toggled): 9 candidates collapse to
|
|
319
|
-
// 2 points and 29/42 bytes read FRAME; without truncation 9 points survive
|
|
320
|
-
// and only 6/42 do. The elimination was SETTING the frame threshold, so
|
|
321
|
-
// every attempt to change run ownership inverted the frame reading and
|
|
322
|
-
// lost the same 10 tests (442 -> 432, twice, for opposite designs).
|
|
323
|
-
//
|
|
324
|
-
// Counting distinct covering candidates restores the documented meaning
|
|
325
|
-
// exactly and makes the comparison like-for-like, which decouples the
|
|
326
|
-
// frame gate from however many points survive.
|
|
327
|
-
const covered = new Uint8Array(query.length);
|
|
328
|
-
for (const r of raw) {
|
|
329
|
-
for (let i = r.qs; i < r.qe; i++) {
|
|
330
|
-
if (!covered[i]) {
|
|
331
|
-
covered[i] = 1;
|
|
332
|
-
depth[i] += 1;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
cands.push({ cand, ctxBytes, raw });
|
|
337
|
-
}
|
|
338
|
-
for (const { cand, ctxBytes, raw } of cands) {
|
|
339
|
-
const free = [];
|
|
340
|
-
for (const r of raw) {
|
|
341
|
-
if (r.qe - r.qs >= Math.min(quantum, ctxBytes.length)) {
|
|
342
|
-
free.push({ ...r });
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
if (free.length > 0) {
|
|
346
|
-
const pt = {
|
|
347
|
-
anchor: cand.anchor,
|
|
348
|
-
vote: cand.vote,
|
|
349
|
-
ctx: ctxBytes,
|
|
350
|
-
runs: free,
|
|
351
|
-
start: cand.start,
|
|
352
|
-
end: cand.end,
|
|
353
|
-
};
|
|
354
|
-
byAnchor.set(cand.anchor, pt);
|
|
355
|
-
points.push(pt);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
// A byte is FRAME when more than half the weave shares it, and a SPAN is
|
|
359
|
-
// frame when more than half its bytes are — the same two-level
|
|
360
|
-
// half-dominance reading cast.ts's own frame gate uses, over the same
|
|
361
|
-
// `depth`. Read against the accepted POINTS (as cast.ts does), so it is
|
|
362
|
-
// only meaningful once phase 1 has run.
|
|
363
|
-
const framed = (from, to) => {
|
|
364
|
-
let n = 0;
|
|
365
|
-
for (let i = from; i < to; i++)
|
|
366
|
-
if (dominates(depth[i], points.length))
|
|
367
|
-
n++;
|
|
368
|
-
return dominates(n, to - from);
|
|
369
|
-
};
|
|
370
|
-
// PHASE 2 — THE CLIMB'S OWN CONCLUSION IS AN ALIGNMENT THE LITERAL MATCHER
|
|
371
|
-
// CANNOT SEE. `alignRuns` seeds on W-grams, so two forms differing by a
|
|
372
|
-
// single byte share no run at all: on `How is ice like steel?` against a
|
|
373
|
-
// store holding `Ice is cold`, the query's `ice` and the stored `Ice` agree
|
|
374
|
-
// on only `ce ` — three bytes, never seeded — so that structure entered the
|
|
375
|
-
// weave carrying nothing but the ` is ` scaffolding every exemplar shares,
|
|
376
|
-
// lost it to the first point that claimed it, and vanished. The climb had
|
|
377
|
-
// ALREADY identified it: its resonance elected `Ice is cold` from the query
|
|
378
|
-
// span `ce l` and `Steel is hard` from `stee`, two disjoint spans each naming
|
|
379
|
-
// its own structure, weighed through the region's contrastive margin and its
|
|
380
|
-
// IDF — gates the aligner has no equivalent of.
|
|
381
|
-
//
|
|
382
|
-
// So the climb PROPOSES the pairing (which structure, which query span) and
|
|
383
|
-
// bytes DECIDE its terms (§2.3). Three gates, each one measured:
|
|
384
|
-
//
|
|
385
|
-
// • it may only take query bytes NO literal run claimed. Run inline with
|
|
386
|
-
// phase 1 this did the opposite of "exact decides" — a higher-ranked
|
|
387
|
-
// candidate's proposal trimmed a lower-ranked candidate's byte-for-byte
|
|
388
|
-
// match out of existence (`he W`, proposed for `a nickname meaning the
|
|
389
|
-
// divine one`, cut the literal `The ` out of `The Starry Night was
|
|
390
|
-
// painted by Vincent van Gogh.` and CAST's redirection lost its
|
|
391
|
-
// dominant — test/29 C4). Hence a second pass, after every literal run
|
|
392
|
-
// is placed.
|
|
393
|
-
// • the literal agreement must DOMINATE the span. A climb vote is not by
|
|
394
|
-
// itself an alignment: on `The Persistence of Memory was painted by
|
|
395
|
-
// Salvador Dali.` the climb elects `The Starry Night…` from the span
|
|
396
|
-
// ` Dali.`, which shares barely a byte with it — the resonance was
|
|
397
|
-
// carried by the frame those exemplars share. Admitting it let CAST
|
|
398
|
-
// weave points out of pure scaffolding and out-account the correct
|
|
399
|
-
// extraction (test/00, test/24). Where the proposal is real the
|
|
400
|
-
// agreement is overwhelming: both C1 spans agree on three of four bytes.
|
|
401
|
-
// • and the span must not be FRAME. Literal dominance alone is too weak
|
|
402
|
-
// at this scale — a 4-byte span agrees three-of-four with half the
|
|
403
|
-
// corpus by accident (`he W` against `a nickname meaning the divine
|
|
404
|
-
// one`). Frame is the weave-local measure of exactly that.
|
|
405
|
-
const claimed = new Uint8Array(query.length);
|
|
406
|
-
for (const p of points) {
|
|
407
|
-
for (const r of p.runs)
|
|
408
|
-
claimed.fill(1, r.qs, r.qe);
|
|
409
|
-
}
|
|
410
|
-
for (const { cand, ctxBytes } of cands) {
|
|
411
|
-
if (cand.end > cand.start) {
|
|
412
|
-
let qs = cand.start;
|
|
413
|
-
let qe = cand.end;
|
|
414
|
-
while (qs < qe && claimed[qs])
|
|
415
|
-
qs++;
|
|
416
|
-
while (qe > qs && claimed[qe - 1])
|
|
417
|
-
qe--;
|
|
418
|
-
let clear = true;
|
|
419
|
-
for (let i = qs; i < qe; i++)
|
|
420
|
-
if (claimed[i])
|
|
421
|
-
clear = false;
|
|
422
|
-
if (clear && qe - qs >= Math.min(quantum, ctxBytes.length)) {
|
|
423
|
-
// The gate only asks whether the agreement DOMINATES the span, so
|
|
424
|
-
// search DOWNWARD from the whole span and stop at the first hit: the
|
|
425
|
-
// first length found is both the longest agreement and, by
|
|
426
|
-
// construction, already past the dominance bar. At most O(W²) bounded
|
|
427
|
-
// substring probes — a span is one segment (≤ 2W) — where a full
|
|
428
|
-
// longest-common-substring scan would be O(|span|² · |ctx|) against a
|
|
429
|
-
// context that may be W× the query.
|
|
430
|
-
const span = query.subarray(qs, qe);
|
|
431
|
-
const bar = Math.floor(span.length / 2) + 1; // dominates(bar, length)
|
|
432
|
-
let bestLen = 0;
|
|
433
|
-
let bestCs = 0;
|
|
434
|
-
for (let len = span.length; len >= bar && bestLen === 0; len--) {
|
|
435
|
-
for (let off = 0; off + len <= span.length; off++) {
|
|
436
|
-
const at = indexOf(ctxBytes, span.subarray(off, off + len), 0);
|
|
437
|
-
if (at < 0)
|
|
438
|
-
continue;
|
|
439
|
-
bestLen = len;
|
|
440
|
-
// Where the span's FIRST byte lands, so `cs` means the same thing
|
|
441
|
-
// it does for a literal run: the context offset the run starts at.
|
|
442
|
-
bestCs = Math.max(0, at - off);
|
|
443
|
-
break;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
if (bestLen > 0 && !framed(qs, qe)) {
|
|
447
|
-
const run = {
|
|
448
|
-
qs,
|
|
449
|
-
qe,
|
|
450
|
-
cs: bestCs,
|
|
451
|
-
weight: bestLen / (qe - qs),
|
|
452
|
-
proposed: true,
|
|
453
|
-
};
|
|
454
|
-
claimed.fill(1, qs, qe);
|
|
455
|
-
const pt = byAnchor.get(cand.anchor);
|
|
456
|
-
if (!pt) {
|
|
457
|
-
const made = {
|
|
458
|
-
anchor: cand.anchor,
|
|
459
|
-
vote: cand.vote,
|
|
460
|
-
ctx: ctxBytes,
|
|
461
|
-
runs: [run],
|
|
462
|
-
start: cand.start,
|
|
463
|
-
end: cand.end,
|
|
464
|
-
};
|
|
465
|
-
byAnchor.set(cand.anchor, made);
|
|
466
|
-
points.push(made);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
pt.runs.push(run);
|
|
470
|
-
pt.runs.sort((x, y) => x.qs - y.qs);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
// ONE PLACE, ONE STRUCTURE. A stored sentence and the entity it names are
|
|
477
|
-
// not two independent structures when the query's evidence for them is the
|
|
478
|
-
// same bytes — they are one place read at two grains, and admitting both
|
|
479
|
-
// lets a nest of containing sentences outvote the entity the query actually
|
|
480
|
-
// named. Measured on test/29 C2 ("How is Shakespeare like Leonardo da
|
|
481
|
-
// Vinci?"): the five sentences that merely CONTAIN the two names align the
|
|
482
|
-
// same q6-18 / q23-41 the names do, and comparison ended up seated on a
|
|
483
|
-
// 49-byte sentence instead of the 17-byte entity.
|
|
484
|
-
//
|
|
485
|
-
// A point earns its own place in the weave the same way a second point earns
|
|
486
|
-
// CAST's entry: at least one perception quantum of query bytes no
|
|
487
|
-
// better-voted point already explains. Points arrive in the climb's vote
|
|
488
|
-
// order, which is the arbiter this file already trusts for what belongs in
|
|
489
|
-
// the weave; unlike run trimming, nothing is CUT here — a point keeps every
|
|
490
|
-
// byte it aligned or it is not a separate structure at all.
|
|
491
|
-
const coveredOf = (p) => {
|
|
492
|
-
const set = new Set();
|
|
493
|
-
for (const r of p.runs)
|
|
494
|
-
for (let i = r.qs; i < r.qe; i++)
|
|
495
|
-
set.add(i);
|
|
496
|
-
return set;
|
|
497
|
-
};
|
|
498
|
-
const kept = [];
|
|
499
|
-
const keptCover = [];
|
|
500
|
-
for (const p of points) {
|
|
501
|
-
const cov = coveredOf(p);
|
|
502
|
-
let redundant = false;
|
|
503
|
-
for (const other of keptCover) {
|
|
504
|
-
let own = 0;
|
|
505
|
-
for (const i of cov)
|
|
506
|
-
if (!other.has(i))
|
|
507
|
-
own++;
|
|
508
|
-
if (own < quantum) {
|
|
509
|
-
redundant = true;
|
|
510
|
-
break;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (!redundant) {
|
|
514
|
-
kept.push(p);
|
|
515
|
-
keptCover.push(cov);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
points.length = 0;
|
|
519
|
-
points.push(...kept);
|
|
520
|
-
return { points, depth };
|
|
521
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { MindContext } from "./types.js";
|
|
2
|
-
import { type PipelineMechanism } from "./pipeline-mechanism.js";
|
|
3
|
-
export { resolveConcepts, resolveConnectors } from "./mechanisms/cover.js";
|
|
4
|
-
export { aluToMechanism } from "./mechanisms/alu.js";
|
|
5
|
-
export declare const defaultMechanisms: PipelineMechanism[];
|
|
6
|
-
export type Provenance = "cast" | "join" | "cover" | "extract" | "recall" | "recall-echo";
|
|
7
|
-
export interface Thought {
|
|
8
|
-
bytes: Uint8Array;
|
|
9
|
-
provenance: Provenance;
|
|
10
|
-
}
|
|
11
|
-
/** Structured payload of the "decideGrounding" rationale step — the same
|
|
12
|
-
* numbers the human-readable candidate labels already carry, exposed as
|
|
13
|
-
* data so a downstream tool need not parse free text. Purely additive
|
|
14
|
-
* instrumentation: built only under `ctx.trace?.` (optional chaining
|
|
15
|
-
* short-circuits its arguments), never read by inference. */
|
|
16
|
-
export interface DecideGroundingData {
|
|
17
|
-
version: 1;
|
|
18
|
-
/** Every grounding candidate weighed, in consideration order. */
|
|
19
|
-
candidates: Array<{
|
|
20
|
-
provenance: string;
|
|
21
|
-
/** The candidate's exact weight in the one cost ladder. */
|
|
22
|
-
weight: number;
|
|
23
|
-
/** The DISCRETE grade the decision actually compares (floor(weight/STEP)). */
|
|
24
|
-
grade: number;
|
|
25
|
-
/** Query bytes the candidate's accounted spans leave unexplained. */
|
|
26
|
-
unexplainedBytes: number;
|
|
27
|
-
/** Whether this candidate won the decision. */
|
|
28
|
-
decided: boolean;
|
|
29
|
-
}>;
|
|
30
|
-
/** Grade margin between the winner and the runner-up, when both exist —
|
|
31
|
-
* the same quantity the "narrowDecision" step reports as narrow when
|
|
32
|
-
* ≤ 1. Absent for a single-candidate decision. */
|
|
33
|
-
runnerUpMargin?: number;
|
|
34
|
-
}
|
|
35
|
-
/** Structured payload of the "narrowDecision" rationale step. */
|
|
36
|
-
export interface NarrowDecisionData {
|
|
37
|
-
version: 1;
|
|
38
|
-
margin: number;
|
|
39
|
-
}
|
|
40
|
-
/** Think: a single lightest-derivation exploration of the Sema graph.
|
|
41
|
-
*
|
|
42
|
-
* Every answer travels the same path:
|
|
43
|
-
* 1. Pre-computation — recognise, extension parse, guide; everything
|
|
44
|
-
* expensive stays lazy on Precomputed until a mechanism asks.
|
|
45
|
-
* 2. Grounding — every mechanism yields candidates weighed in the one
|
|
46
|
-
* cost ladder; the lightest grounding derivation wins.
|
|
47
|
-
* 3. Post-grounding — diagnostics (narrowDecision, thinGrounding),
|
|
48
|
-
* reasoning (multi-hop), fusion (multi-topic). */
|
|
49
|
-
export declare function think(ctx: MindContext, query: Uint8Array, mechs?: readonly PipelineMechanism[]): Promise<Thought | null>;
|