@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.
Files changed (143) hide show
  1. package/AGENTS.md +6 -6
  2. package/HOW_IT_WORKS.md +16 -0
  3. package/jsr.json +1 -1
  4. package/package.json +1 -1
  5. package/src/mind/match.ts +81 -0
  6. package/src/mind/mechanisms/recall.ts +29 -3
  7. package/test/76-reference-binding.test.mjs +72 -0
  8. package/dist/example/demo.d.ts +0 -1
  9. package/dist/example/demo.js +0 -39
  10. package/dist/example/train_base.d.ts +0 -93
  11. package/dist/example/train_base.js +0 -2269
  12. package/dist/src/alphabet.d.ts +0 -7
  13. package/dist/src/alphabet.js +0 -33
  14. package/dist/src/alu/src/alu.d.ts +0 -185
  15. package/dist/src/alu/src/alu.js +0 -440
  16. package/dist/src/alu/src/expr.d.ts +0 -61
  17. package/dist/src/alu/src/expr.js +0 -318
  18. package/dist/src/alu/src/index.d.ts +0 -11
  19. package/dist/src/alu/src/index.js +0 -19
  20. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  21. package/dist/src/alu/src/kernel-arith.js +0 -264
  22. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  23. package/dist/src/alu/src/kernel-bits.js +0 -152
  24. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  25. package/dist/src/alu/src/kernel-logic.js +0 -60
  26. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  27. package/dist/src/alu/src/kernel-nd.js +0 -208
  28. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  29. package/dist/src/alu/src/kernel-numeric.js +0 -366
  30. package/dist/src/alu/src/operation.d.ts +0 -168
  31. package/dist/src/alu/src/operation.js +0 -189
  32. package/dist/src/alu/src/parser.d.ts +0 -221
  33. package/dist/src/alu/src/parser.js +0 -577
  34. package/dist/src/alu/src/resonance.d.ts +0 -55
  35. package/dist/src/alu/src/resonance.js +0 -126
  36. package/dist/src/alu/src/text.d.ts +0 -31
  37. package/dist/src/alu/src/text.js +0 -73
  38. package/dist/src/alu/src/value.d.ts +0 -109
  39. package/dist/src/alu/src/value.js +0 -300
  40. package/dist/src/alu/test/alu.test.d.ts +0 -1
  41. package/dist/src/alu/test/alu.test.js +0 -764
  42. package/dist/src/bytes.d.ts +0 -14
  43. package/dist/src/bytes.js +0 -59
  44. package/dist/src/canon.d.ts +0 -45
  45. package/dist/src/canon.js +0 -85
  46. package/dist/src/config.d.ts +0 -111
  47. package/dist/src/config.js +0 -91
  48. package/dist/src/derive/src/deduction.d.ts +0 -136
  49. package/dist/src/derive/src/deduction.js +0 -159
  50. package/dist/src/derive/src/index.d.ts +0 -8
  51. package/dist/src/derive/src/index.js +0 -11
  52. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  53. package/dist/src/derive/src/priority-queue.js +0 -73
  54. package/dist/src/derive/src/rewrite.d.ts +0 -56
  55. package/dist/src/derive/src/rewrite.js +0 -100
  56. package/dist/src/derive/src/trie.d.ts +0 -90
  57. package/dist/src/derive/src/trie.js +0 -217
  58. package/dist/src/derive/test/derive.test.d.ts +0 -1
  59. package/dist/src/derive/test/derive.test.js +0 -122
  60. package/dist/src/extension.d.ts +0 -37
  61. package/dist/src/extension.js +0 -7
  62. package/dist/src/geometry.d.ts +0 -233
  63. package/dist/src/geometry.js +0 -1089
  64. package/dist/src/index.d.ts +0 -17
  65. package/dist/src/index.js +0 -19
  66. package/dist/src/ingest-cache.d.ts +0 -41
  67. package/dist/src/ingest-cache.js +0 -165
  68. package/dist/src/meter.d.ts +0 -176
  69. package/dist/src/meter.js +0 -274
  70. package/dist/src/mind/articulation.d.ts +0 -6
  71. package/dist/src/mind/articulation.js +0 -99
  72. package/dist/src/mind/attention.d.ts +0 -430
  73. package/dist/src/mind/attention.js +0 -2418
  74. package/dist/src/mind/bridge.d.ts +0 -37
  75. package/dist/src/mind/bridge.js +0 -907
  76. package/dist/src/mind/canonical.d.ts +0 -34
  77. package/dist/src/mind/canonical.js +0 -93
  78. package/dist/src/mind/graph-search.d.ts +0 -294
  79. package/dist/src/mind/graph-search.js +0 -996
  80. package/dist/src/mind/index.d.ts +0 -9
  81. package/dist/src/mind/index.js +0 -5
  82. package/dist/src/mind/junction.d.ts +0 -137
  83. package/dist/src/mind/junction.js +0 -358
  84. package/dist/src/mind/learning.d.ts +0 -75
  85. package/dist/src/mind/learning.js +0 -265
  86. package/dist/src/mind/match.d.ts +0 -351
  87. package/dist/src/mind/match.js +0 -959
  88. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  89. package/dist/src/mind/mechanisms/alu.js +0 -36
  90. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  91. package/dist/src/mind/mechanisms/cast.js +0 -1186
  92. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  93. package/dist/src/mind/mechanisms/confluence.js +0 -271
  94. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  95. package/dist/src/mind/mechanisms/cover.js +0 -232
  96. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  97. package/dist/src/mind/mechanisms/extraction.js +0 -327
  98. package/dist/src/mind/mechanisms/prefix-completion.d.ts +0 -22
  99. package/dist/src/mind/mechanisms/prefix-completion.js +0 -243
  100. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  101. package/dist/src/mind/mechanisms/recall.js +0 -460
  102. package/dist/src/mind/mechanisms/reference.d.ts +0 -6
  103. package/dist/src/mind/mechanisms/reference.js +0 -296
  104. package/dist/src/mind/mind.d.ts +0 -386
  105. package/dist/src/mind/mind.js +0 -754
  106. package/dist/src/mind/pipeline-mechanism.d.ts +0 -238
  107. package/dist/src/mind/pipeline-mechanism.js +0 -622
  108. package/dist/src/mind/pipeline.d.ts +0 -49
  109. package/dist/src/mind/pipeline.js +0 -343
  110. package/dist/src/mind/primitives.d.ts +0 -85
  111. package/dist/src/mind/primitives.js +0 -333
  112. package/dist/src/mind/rationale.d.ts +0 -139
  113. package/dist/src/mind/rationale.js +0 -163
  114. package/dist/src/mind/reasoning.d.ts +0 -42
  115. package/dist/src/mind/reasoning.js +0 -305
  116. package/dist/src/mind/recognition.d.ts +0 -20
  117. package/dist/src/mind/recognition.js +0 -696
  118. package/dist/src/mind/resonance.d.ts +0 -35
  119. package/dist/src/mind/resonance.js +0 -365
  120. package/dist/src/mind/trace.d.ts +0 -15
  121. package/dist/src/mind/trace.js +0 -73
  122. package/dist/src/mind/traverse.d.ts +0 -196
  123. package/dist/src/mind/traverse.js +0 -806
  124. package/dist/src/mind/types.d.ts +0 -418
  125. package/dist/src/mind/types.js +0 -179
  126. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  127. package/dist/src/rabitq-ivf/src/database.js +0 -201
  128. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  129. package/dist/src/rabitq-ivf/src/index.js +0 -4
  130. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  131. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  132. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  133. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  134. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  135. package/dist/src/rabitq-ivf/src/rabitq.js +0 -313
  136. package/dist/src/sema.d.ts +0 -41
  137. package/dist/src/sema.js +0 -77
  138. package/dist/src/store-sqlite.d.ts +0 -184
  139. package/dist/src/store-sqlite.js +0 -942
  140. package/dist/src/store.d.ts +0 -762
  141. package/dist/src/store.js +0 -1823
  142. package/dist/src/vec.d.ts +0 -31
  143. package/dist/src/vec.js +0 -109
@@ -1,622 +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 { conceptThreshold, dominates } from "../geometry.js";
17
- import { windowIds } from "./canonical.js";
18
- import { read, resolve } from "./primitives.js";
19
- import { alignGraded, frameSlots, skillExemplar, } from "./match.js";
20
- import { climbAttentionAll } from "./attention.js";
21
- import { hubBound, 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
- _resonance;
120
- /** The response's ONE top-k content-index read: the k learnt forms nearest
121
- * the whole-query gist, ranked. Recall's every gist tier is built on it,
122
- * and {@link frames} assembles the frame inventory from it.
123
- *
124
- * An ANN query is the single most expensive read in the engine, and two
125
- * mechanisms asking the same question of the same gist is the one
126
- * duplication a profile shows as doubled `annVectorReads` with nothing to
127
- * account for it. Cached BY PROMISE, so a second caller awaits the first. */
128
- resonance() {
129
- return this._resonance ??= this.shared("resonance", () => this.ctx.store.resonate(this.guide, this.k));
130
- }
131
- _wide;
132
- /** The response's WIDE candidate list — the top-k when the query's gist has
133
- * no concept-level match anywhere, and an exhaustive √N read when it does.
134
- *
135
- * Every mechanism that has to look PAST the top-k reads this one list: the
136
- * substitution bridge, prefix completion and the frame filler all did, and
137
- * it was memoised inside recall for exactly that reason (measured: 490 ms
138
- * median re-issued against 13 ms non-exhaustive, 36x). A memo inside one
139
- * mechanism only serves that mechanism's own tiers, so it lives here now —
140
- * the same move `resonance` made for the top-k.
141
- *
142
- * THE CONDITION IS THE TOP HIT'S SCORE, NOT THE CORPUS SIZE. When nothing
143
- * ranks at concept level, an exhaustive ANN only scores more vectors below
144
- * the bar (profiled at 38K–40K annVectorReads per refusing query on a 325K-
145
- * context store); the structural channels — junction walks, anchor climbs,
146
- * the write side's window index — are the correct proposal source there,
147
- * because the ANN cannot propose what the gist cannot rank. This was once
148
- * spelled `corpusN(ctx) <= (k · W)³`, which asks a different question and
149
- * answers it wrongly at exactly the scale it was written from: at N =
150
- * 325,608 with k = 24 and W = 4 the cube is 884,736, so that store took the
151
- * exhaustive branch — the very branch measured above. Measured cost of the
152
- * mismatch: substitutionBridge 8,544 ms of a 19,548 ms think (44%), against
153
- * 1,248 ms and 14,218 ms without it, every answer byte-identical. */
154
- wideResonance() {
155
- return this._wide ??= this.shared("wideResonance", async () => {
156
- const hits = await this.resonance();
157
- if (hits.length > 0 &&
158
- hits[0].score >= conceptThreshold(this.ctx.store.D)) {
159
- const exhaustive = await this.ctx.store.resonate(this.guide, hubBound(this.ctx), true);
160
- return exhaustive.map((h) => h.id);
161
- }
162
- return hits.map((h) => h.id);
163
- });
164
- }
165
- _frames;
166
- /** THE FRAME INVENTORY — every ranked candidate that reads as an instance of
167
- * the same frame as the query, each with the query spans it leaves VARIABLE
168
- * ({@link FrameInstance}). The one place the engine represents "a position
169
- * whose occupant comes from the context rather than the corpus".
170
- *
171
- * AN INVENTORY, NOT AN ELECTION. It reports every pairing and elects no
172
- * frame, deliberately: a slot is a property of a PAIRING, not of the query,
173
- * and different candidates put slots in different places. Committing to one
174
- * reading here would push whichever consumer asked first onto everyone else
175
- * — the market's decoupling (§2.6) broken from inside the shared container,
176
- * and the population error §2.7 names. Each consumer groups and commits
177
- * for its own question; reference elects the modal slot signature, and a
178
- * consumer wanting a different reading is not fighting this one.
179
- *
180
- * NO LICENCE EITHER. Knowing a span is variable is safe for every consumer
181
- * — it can only improve an alignment. Knowing one may be VOICED through is
182
- * a different and much stronger claim, gated separately by
183
- * {@link carriesFillers}, which needs projections this must not perform. */
184
- frames() {
185
- return this._frames ??= this.shared("frames", async () => {
186
- const ctx = this.ctx;
187
- const W = ctx.space.maxGroup;
188
- // PHRASE SCALE, the same bound the bridge and the frame filler put on a
189
- // candidate's bytes: a form an order of magnitude longer than the query
190
- // is not a candidate for BEING it with a span replaced.
191
- const capBytes = this.query.length * W;
192
- const out = [];
193
- for (const h of await this.resonance()) {
194
- // REJECT BY LENGTH BEFORE RECONSTRUCTING (§2.8): `contentLen` is an
195
- // indexed read, `bytesPrefix` rebuilds a subtree. ONLY the phrase-scale
196
- // cap is applied — it is a bounded-read discipline, not a judgement.
197
- //
198
- // A LOWER bound was here too (`dominates(len, query.length)`, on the
199
- // reasoning that a candidate shorter than half the query cannot supply
200
- // a frame that dominates it). That is reference's gate wearing a cost
201
- // argument's clothes, and it hid the very pairings another consumer
202
- // needs: `What is the capital of France?` (30 B) against `What is the
203
- // capital of the country where the Eiffel Tower is?` (61 B) was
204
- // rejected before it was ever read — a definite description standing
205
- // where a noun stands, which is exactly the shape the frame filler
206
- // exists for.
207
- const len = ctx.store.contentLen(h.id, capBytes + 1);
208
- if (len === 0 || len > capBytes)
209
- continue;
210
- const cand = ctx.store.bytesPrefix(h.id, capBytes + 1);
211
- if (cand.length === 0 || cand.length > capBytes)
212
- continue;
213
- const inst = frameSlots(ctx, this.query, cand, h.id);
214
- if (inst !== null)
215
- out.push(inst);
216
- }
217
- return out;
218
- });
219
- }
220
- _attention;
221
- /** The full consensus climb (roots + ranked anchors) — the query-level
222
- * evidence CAST, confluence, extraction, recall's scaffolding tier, and
223
- * fusion all share. Computed on first access; a query no mechanism
224
- * climbs for (e.g. one an extension decided outright) never pays for it. */
225
- attention() {
226
- return this._attention ??= this.shared("attention", () => climbAttentionAll(this.ctx, this.query, this.k));
227
- }
228
- _weave;
229
- /** Result of {@link alignGraded} for the first k ranked anchors —
230
- * O(k · |query| · |ctx|). Consumed by CAST; reusable by any future
231
- * mechanism doing analogical transfer. */
232
- weave() {
233
- return this._weave ??= this.attention().then((climb) => this.shared("weave", async () => computeWeave(this.ctx, this.query, this, climb)));
234
- }
235
- /** Span-shaped classification of one ranked anchor, memoised per anchor id
236
- * so repeated calls (extraction's own early-exit scan, any future
237
- * template-based mechanism) never redo the work. Deliberately NOT an
238
- * eager all-anchors map: `skillExemplar` is the expensive part of
239
- * extraction (capped fan-out reads plus an O(|ctx|) scan), and most
240
- * queries are answered by the FIRST ranked anchor that qualifies — paying
241
- * for every ranked anchor regardless of where the scan stops would turn
242
- * an early-exit lookup into full O(k) work on every query. */
243
- _spanShaped = new Map();
244
- spanShapedOf(anchor) {
245
- let p = this._spanShaped.get(anchor);
246
- if (p === undefined) {
247
- p = this.shared("spanShaped", () => skillExemplar(this.ctx, anchor, this.guide));
248
- this._spanShaped.set(anchor, p);
249
- }
250
- return p;
251
- }
252
- /** Every ranked anchor's classification at once, sharing the same
253
- * per-anchor cache as {@link spanShapedOf} — for a mechanism that
254
- * genuinely needs the full picture (not an early-exit scan). Mixing
255
- * access patterns across mechanisms never duplicates work: whichever
256
- * anchors an early-exit consumer already asked for are reused here, and
257
- * whichever this computes first are reused by a later early-exit scan. */
258
- async spanShapedAll() {
259
- const { ranked } = await this.attention();
260
- const out = new Map();
261
- for (const cand of ranked) {
262
- if (out.has(cand.anchor))
263
- continue;
264
- out.set(cand.anchor, await this.spanShapedOf(cand.anchor));
265
- }
266
- return out;
267
- }
268
- }
269
- function computeWeave(ctx, query, pre, climb) {
270
- const quantum = ctx.space.maxGroup;
271
- const { ranked } = climb;
272
- const rankedCapped = ranked.length > pre.k ? ranked.slice(0, pre.k) : ranked;
273
- const depth = new Float64Array(query.length);
274
- const points = [];
275
- const byAnchor = new Map();
276
- // WEAVE-SCALE anchors only: CAST transfers structure between things the
277
- // QUERY weaves together — query-scale structures. A context an order of
278
- // magnitude beyond the query is not woven BY the query (the query can at
279
- // most quote a fragment of it, and fragment-level evidence is exactly what
280
- // recognition and the cover already handle); CAST's own comparison gate
281
- // demands `ctx.length ≤ query.length` before it fires, and its
282
- // substitution seats sit within a quantum of a context's start. W is the
283
- // perceptual quantum — the same scale multiplier the bridge's phrase-scale
284
- // contract uses. The prefix-capped read makes an oversized anchor cost a
285
- // bounded read instead of reconstructing (and then canonically
286
- // recognising) a corpus-sized deposit: profiled on a 17.7M-node store,
287
- // uncapped weaves spent 5–8s per query recognising conversation-length
288
- // anchors that could never form a weave point.
289
- const askerBytes = query.length -
290
- ctx.answeredSpans.reduce((n, [start, end]) => n + end - start, 0);
291
- const capBytes = askerBytes * quantum;
292
- // RUNS ARE NOT TRIMMED AGAINST EACH OTHER. A point keeps every byte it
293
- // aligned; exclusivity is a property of STRUCTURES (see "one place, one
294
- // structure" below), not of individual query bytes.
295
- //
296
- // This weave used to build points in the climb's vote order and cut each new
297
- // point's runs against every point already accepted. It is worth recording
298
- // what that cost, because the cut was invisible: it did not just resolve
299
- // ties, it silently DECIDED downstream schemas. A point's `runs[0]` — the
300
- // run three CAST branches read as "the filler", "the seat", "the name" — was
301
- // whichever run happened to survive the cut, so those schemas were reading an
302
- // elimination order as though it were evidence, and the query's own bytes
303
- // were truncated on the way ("Shakespeare" surviving as "Shakes"). Each
304
- // consumer now derives its own reading from the runs (cast.ts: `fillerRun`
305
- // clips at the seat, redirection scans for the naming run, entry counts own
306
- // bytes and the climb's dispersion), and with those in place removing the cut
307
- // costs nothing — measured, the same 442 tests pass either way.
308
- //
309
- // What the vote order was RIGHT about is kept: which structures belong in the
310
- // weave is the climb's call, not a local run measure. Arbitrating byte
311
- // ownership by local evidence instead (longest covering run, then weight,
312
- // then rank) was implemented and MEASURED, and it evicted the committed
313
- // root's own evidence — CAST then refused on its own consistency check ("2
314
- // aligned structure(s), but none is one of the climb's 1 committed root(s)"),
315
- // test/29 going 9/2 to 7/4. Weave-local measures decide what is FRAME inside
316
- // the weave (see the frame gates in cast.ts); membership stays the climb's.
317
- //
318
- // TWO PASSES. `depth` — how much of the weave agrees on each query byte, and
319
- // therefore what counts as FRAME — must be the whole weave's, not "whatever
320
- // has been processed so far": read in one pass it made a candidate's own
321
- // frame reading depend on its rank, and the proposed-run gate below needs the
322
- // real thing.
323
- const cands = [];
324
- const querySegments = [];
325
- let segmentStart = 0;
326
- for (const [start, end] of ctx.answeredSpans) {
327
- if (segmentStart < start)
328
- querySegments.push([segmentStart, start]);
329
- segmentStart = Math.max(segmentStart, end);
330
- }
331
- if (segmentStart < query.length) {
332
- querySegments.push([segmentStart, query.length]);
333
- }
334
- const weaveLength = querySegments.reduce((n, [s, e]) => n + e - s, 0);
335
- const weaveQuery = new Uint8Array(weaveLength);
336
- const weaveMap = [];
337
- let compactStart = 0;
338
- for (const [start, end] of querySegments) {
339
- weaveQuery.set(query.subarray(start, end), compactStart);
340
- weaveMap.push({
341
- compactStart,
342
- originalStart: start,
343
- length: end - start,
344
- });
345
- compactStart += end - start;
346
- }
347
- const segmentOf = (start, end) => {
348
- let lo = 0;
349
- let hi = weaveMap.length;
350
- while (lo < hi) {
351
- const mid = (lo + hi) >>> 1;
352
- if (weaveMap[mid].originalStart <= start)
353
- lo = mid + 1;
354
- else
355
- hi = mid;
356
- }
357
- const part = lo > 0 ? weaveMap[lo - 1] : undefined;
358
- return part && end <= part.originalStart + part.length ? part : undefined;
359
- };
360
- const weaveSites = pre.rec.sites.flatMap((s) => {
361
- const part = segmentOf(s.start, s.end);
362
- return part
363
- ? [{
364
- ...s,
365
- start: part.compactStart + s.start - part.originalStart,
366
- end: part.compactStart + s.end - part.originalStart,
367
- }]
368
- : [];
369
- });
370
- for (const cand of rankedCapped) {
371
- const ctxBytes = read(ctx, cand.anchor, capBytes + 1);
372
- if (ctxBytes.length === 0 || ctxBytes.length > capBytes)
373
- continue;
374
- // CAST compares structures stated by the asker. Completed assistant turns
375
- // remain available to recognition and the climb as conversation context,
376
- // but aligning every candidate across their full prose makes weave work
377
- // grow with answer length and lets the engine analogise against its own
378
- // previous output. The compact asker stream is aligned once (so candidate
379
- // windows are not rebuilt per turn), then every run is split back across
380
- // the original turn segments so no evidence crosses an omitted boundary.
381
- const raw = alignGraded(ctx, weaveQuery, ctxBytes, weaveSites).flatMap((r) => {
382
- let lo = 0;
383
- let hi = weaveMap.length;
384
- while (lo < hi) {
385
- const mid = (lo + hi) >>> 1;
386
- if (weaveMap[mid].compactStart <= r.qs)
387
- lo = mid + 1;
388
- else
389
- hi = mid;
390
- }
391
- const out = [];
392
- for (let pi = Math.max(0, lo - 1); pi < weaveMap.length; pi++) {
393
- const part = weaveMap[pi];
394
- if (part.compactStart >= r.qe)
395
- break;
396
- const partEnd = part.compactStart + part.length;
397
- const start = Math.max(r.qs, part.compactStart);
398
- const end = Math.min(r.qe, partEnd);
399
- if (start >= end)
400
- continue;
401
- out.push({
402
- ...r,
403
- qs: part.originalStart + start - part.compactStart,
404
- qe: part.originalStart + end - part.compactStart,
405
- cs: r.cs + start - r.qs,
406
- });
407
- }
408
- return out;
409
- });
410
- if (raw.length === 0)
411
- continue;
412
- // DEPTH COUNTS STRUCTURES, NOT WEIGHT. The frame test is
413
- // `dominates(depth[i], aligned)` — "more than half the weave shares this
414
- // byte" — and `aligned` is a COUNT of points. Accumulating graded
415
- // alignment WEIGHT here compared weight-mass against a cardinality: two
416
- // different dimensions, meaningful only while truncation happened to keep
417
- // points.length small and weights near 1.
418
- //
419
- // Measured (test/29 C2, only truncation toggled): 9 candidates collapse to
420
- // 2 points and 29/42 bytes read FRAME; without truncation 9 points survive
421
- // and only 6/42 do. The elimination was SETTING the frame threshold, so
422
- // every attempt to change run ownership inverted the frame reading and
423
- // lost the same 10 tests (442 -> 432, twice, for opposite designs).
424
- //
425
- // Counting distinct covering candidates restores the documented meaning
426
- // exactly and makes the comparison like-for-like, which decouples the
427
- // frame gate from however many points survive.
428
- const covered = new Uint8Array(query.length);
429
- for (const r of raw) {
430
- for (let i = r.qs; i < r.qe; i++) {
431
- if (!covered[i]) {
432
- covered[i] = 1;
433
- depth[i] += 1;
434
- }
435
- }
436
- }
437
- cands.push({ cand, ctxBytes, raw });
438
- }
439
- for (const { cand, ctxBytes, raw } of cands) {
440
- const free = [];
441
- for (const r of raw) {
442
- if (r.qe - r.qs >= Math.min(quantum, ctxBytes.length)) {
443
- free.push({ ...r });
444
- }
445
- }
446
- if (free.length > 0) {
447
- const pt = {
448
- anchor: cand.anchor,
449
- vote: cand.vote,
450
- ctx: ctxBytes,
451
- runs: free,
452
- start: cand.start,
453
- end: cand.end,
454
- };
455
- byAnchor.set(cand.anchor, pt);
456
- points.push(pt);
457
- }
458
- }
459
- // A byte is FRAME when more than half the weave shares it, and a SPAN is
460
- // frame when more than half its bytes are — the same two-level
461
- // half-dominance reading cast.ts's own frame gate uses, over the same
462
- // `depth`. Read against the accepted POINTS (as cast.ts does), so it is
463
- // only meaningful once phase 1 has run.
464
- const framed = (from, to) => {
465
- let n = 0;
466
- for (let i = from; i < to; i++)
467
- if (dominates(depth[i], points.length))
468
- n++;
469
- return dominates(n, to - from);
470
- };
471
- // PHASE 2 — THE CLIMB'S OWN CONCLUSION IS AN ALIGNMENT THE LITERAL MATCHER
472
- // CANNOT SEE. `alignRuns` seeds on W-grams, so two forms differing by a
473
- // single byte share no run at all: on `How is ice like steel?` against a
474
- // store holding `Ice is cold`, the query's `ice` and the stored `Ice` agree
475
- // on only `ce ` — three bytes, never seeded — so that structure entered the
476
- // weave carrying nothing but the ` is ` scaffolding every exemplar shares,
477
- // lost it to the first point that claimed it, and vanished. The climb had
478
- // ALREADY identified it: its resonance elected `Ice is cold` from the query
479
- // span `ce l` and `Steel is hard` from `stee`, two disjoint spans each naming
480
- // its own structure, weighed through the region's contrastive margin and its
481
- // IDF — gates the aligner has no equivalent of.
482
- //
483
- // So the climb PROPOSES the pairing (which structure, which query span) and
484
- // bytes DECIDE its terms (§2.3). Three gates, each one measured:
485
- //
486
- // • it may only take query bytes NO literal run claimed. Run inline with
487
- // phase 1 this did the opposite of "exact decides" — a higher-ranked
488
- // candidate's proposal trimmed a lower-ranked candidate's byte-for-byte
489
- // match out of existence (`he W`, proposed for `a nickname meaning the
490
- // divine one`, cut the literal `The ` out of `The Starry Night was
491
- // painted by Vincent van Gogh.` and CAST's redirection lost its
492
- // dominant — test/29 C4). Hence a second pass, after every literal run
493
- // is placed.
494
- // • the literal agreement must DOMINATE the span. A climb vote is not by
495
- // itself an alignment: on `The Persistence of Memory was painted by
496
- // Salvador Dali.` the climb elects `The Starry Night…` from the span
497
- // ` Dali.`, which shares barely a byte with it — the resonance was
498
- // carried by the frame those exemplars share. Admitting it let CAST
499
- // weave points out of pure scaffolding and out-account the correct
500
- // extraction (test/00, test/24). Where the proposal is real the
501
- // agreement is overwhelming: both C1 spans agree on three of four bytes.
502
- // • and the span must not be FRAME. Literal dominance alone is too weak
503
- // at this scale — a 4-byte span agrees three-of-four with half the
504
- // corpus by accident (`he W` against `a nickname meaning the divine
505
- // one`). Frame is the weave-local measure of exactly that.
506
- const claimed = new Uint8Array(query.length);
507
- for (const p of points) {
508
- for (const r of p.runs)
509
- claimed.fill(1, r.qs, r.qe);
510
- }
511
- for (const { cand, ctxBytes } of cands) {
512
- if (cand.end > cand.start) {
513
- let qs = cand.start;
514
- let qe = cand.end;
515
- while (qs < qe && claimed[qs])
516
- qs++;
517
- while (qe > qs && claimed[qe - 1])
518
- qe--;
519
- let clear = true;
520
- for (let i = qs; i < qe; i++)
521
- if (claimed[i])
522
- clear = false;
523
- if (clear && qe - qs >= Math.min(quantum, ctxBytes.length)) {
524
- // The gate only asks whether the agreement DOMINATES the span, so
525
- // search DOWNWARD from the whole span and stop at the first hit: the
526
- // first length found is both the longest agreement and, by
527
- // construction, already past the dominance bar. At most O(W²) bounded
528
- // substring probes — a span is one segment (≤ 2W) — where a full
529
- // longest-common-substring scan would be O(|span|² · |ctx|) against a
530
- // context that may be W× the query.
531
- const span = query.subarray(qs, qe);
532
- const bar = Math.floor(span.length / 2) + 1; // dominates(bar, length)
533
- let bestLen = 0;
534
- let bestCs = 0;
535
- for (let len = span.length; len >= bar && bestLen === 0; len--) {
536
- for (let off = 0; off + len <= span.length; off++) {
537
- const at = indexOf(ctxBytes, span.subarray(off, off + len), 0);
538
- if (at < 0)
539
- continue;
540
- bestLen = len;
541
- // Where the span's FIRST byte lands, so `cs` means the same thing
542
- // it does for a literal run: the context offset the run starts at.
543
- bestCs = Math.max(0, at - off);
544
- break;
545
- }
546
- }
547
- if (bestLen > 0 && !framed(qs, qe)) {
548
- const run = {
549
- qs,
550
- qe,
551
- cs: bestCs,
552
- weight: bestLen / (qe - qs),
553
- proposed: true,
554
- };
555
- claimed.fill(1, qs, qe);
556
- const pt = byAnchor.get(cand.anchor);
557
- if (!pt) {
558
- const made = {
559
- anchor: cand.anchor,
560
- vote: cand.vote,
561
- ctx: ctxBytes,
562
- runs: [run],
563
- start: cand.start,
564
- end: cand.end,
565
- };
566
- byAnchor.set(cand.anchor, made);
567
- points.push(made);
568
- }
569
- else {
570
- pt.runs.push(run);
571
- pt.runs.sort((x, y) => x.qs - y.qs);
572
- }
573
- }
574
- }
575
- }
576
- }
577
- // ONE PLACE, ONE STRUCTURE. A stored sentence and the entity it names are
578
- // not two independent structures when the query's evidence for them is the
579
- // same bytes — they are one place read at two grains, and admitting both
580
- // lets a nest of containing sentences outvote the entity the query actually
581
- // named. Measured on test/29 C2 ("How is Shakespeare like Leonardo da
582
- // Vinci?"): the five sentences that merely CONTAIN the two names align the
583
- // same q6-18 / q23-41 the names do, and comparison ended up seated on a
584
- // 49-byte sentence instead of the 17-byte entity.
585
- //
586
- // A point earns its own place in the weave the same way a second point earns
587
- // CAST's entry: at least one perception quantum of query bytes no
588
- // better-voted point already explains. Points arrive in the climb's vote
589
- // order, which is the arbiter this file already trusts for what belongs in
590
- // the weave; unlike run trimming, nothing is CUT here — a point keeps every
591
- // byte it aligned or it is not a separate structure at all.
592
- const coveredOf = (p) => {
593
- const set = new Set();
594
- for (const r of p.runs)
595
- for (let i = r.qs; i < r.qe; i++)
596
- set.add(i);
597
- return set;
598
- };
599
- const kept = [];
600
- const keptCover = [];
601
- for (const p of points) {
602
- const cov = coveredOf(p);
603
- let redundant = false;
604
- for (const other of keptCover) {
605
- let own = 0;
606
- for (const i of cov)
607
- if (!other.has(i))
608
- own++;
609
- if (own < quantum) {
610
- redundant = true;
611
- break;
612
- }
613
- }
614
- if (!redundant) {
615
- kept.push(p);
616
- keptCover.push(cov);
617
- }
618
- }
619
- points.length = 0;
620
- points.push(...kept);
621
- return { points, depth };
622
- }
@@ -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" | "reference" | "recall" | "recall-echo" | "prefix";
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>;