@hviana/sema 0.4.6 → 0.5.0
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 +290 -77
- package/HOW_IT_WORKS.md +2170 -735
- package/dist/example/train_base.d.ts +9 -3
- package/dist/example/train_base.js +21 -4
- package/dist/src/canon.d.ts +19 -0
- package/dist/src/canon.js +28 -0
- package/dist/src/geometry.d.ts +52 -0
- package/dist/src/geometry.js +87 -1
- package/dist/src/mind/bridge.js +27 -1
- package/dist/src/mind/frame-filler.d.ts +15 -0
- package/dist/src/mind/frame-filler.js +535 -0
- package/dist/src/mind/learning.js +6 -11
- package/dist/src/mind/mechanisms/cast.js +72 -2
- package/dist/src/mind/mechanisms/cover.js +6 -1
- package/dist/src/mind/mechanisms/extraction.js +27 -0
- package/dist/src/mind/mechanisms/recall.js +214 -34
- package/dist/src/mind/mind.d.ts +49 -1
- package/dist/src/mind/mind.js +137 -10
- package/dist/src/mind/pipeline-mechanism.d.ts +7 -0
- package/dist/src/mind/pipeline.js +29 -1
- package/dist/src/mind/prefix-completion.d.ts +59 -0
- package/dist/src/mind/prefix-completion.js +270 -0
- package/dist/src/mind/primitives.d.ts +29 -10
- package/dist/src/mind/primitives.js +52 -61
- package/dist/src/mind/recognition.js +119 -9
- package/dist/src/mind/traverse.d.ts +32 -0
- package/dist/src/mind/traverse.js +52 -0
- package/dist/src/mind/types.d.ts +55 -16
- package/dist/src/mind/types.js +68 -19
- package/dist/src/rabitq-ivf/src/rabitq.js +31 -1
- package/dist/src/store.d.ts +21 -0
- package/dist/src/store.js +21 -0
- package/example/train_base.ts +21 -4
- package/package.json +1 -1
- package/src/canon.ts +28 -0
- package/src/geometry.ts +100 -1
- package/src/mind/bridge.ts +34 -0
- package/src/mind/frame-filler.ts +604 -0
- package/src/mind/learning.ts +5 -9
- package/src/mind/mechanisms/cast.ts +70 -2
- package/src/mind/mechanisms/cover.ts +6 -1
- package/src/mind/mechanisms/extraction.ts +27 -0
- package/src/mind/mechanisms/recall.ts +236 -37
- package/src/mind/mind.ts +154 -14
- package/src/mind/pipeline-mechanism.ts +7 -0
- package/src/mind/pipeline.ts +33 -1
- package/src/mind/prefix-completion.ts +314 -0
- package/src/mind/primitives.ts +59 -70
- package/src/mind/recognition.ts +117 -6
- package/src/mind/traverse.ts +52 -0
- package/src/mind/types.ts +98 -42
- package/src/rabitq-ivf/src/rabitq.ts +31 -1
- package/src/store.ts +25 -0
- package/test/13-conversation.test.mjs +13 -0
- package/test/57-fusion-order.test.mjs +65 -0
- package/test/65-ann-recall.test.mjs +331 -0
- package/test/66-query-edge-whitespace.test.mjs +99 -0
- package/test/67-climb-anchor-breadth.test.mjs +113 -0
- package/test/68-extraction-unanchored.test.mjs +79 -0
- package/test/69-frame-filler.test.mjs +115 -0
- package/test/70-prefix-completion.test.mjs +170 -0
- package/test/71-embedded-canon-equivalence.test.mjs +121 -0
- package/test/72-prefix-candidate-supply.test.mjs +114 -0
- package/test/73-scaffolding-only-bridge-abstains.test.mjs +178 -0
- package/test/74-prefix-trap-not-sprung-early.test.mjs +114 -0
- package/test/75-multiturn-context-optimisation.test.mjs +1082 -0
package/AGENTS.md
CHANGED
|
@@ -32,6 +32,10 @@ Hard facts you must not fight:
|
|
|
32
32
|
in new files.
|
|
33
33
|
- **Determinism is the product.** Same seed + same deposit order + same query ⇒
|
|
34
34
|
byte-identical answer. Tests pin it.
|
|
35
|
+
- **Perception is a pure function of the bytes**, and the deposit and inference
|
|
36
|
+
paths must compute the same tree for the same input (2.15). Anything that
|
|
37
|
+
makes one side impose structure the other does not is a correctness bug, not a
|
|
38
|
+
tuning choice.
|
|
35
39
|
|
|
36
40
|
The mental model, top to bottom:
|
|
37
41
|
|
|
@@ -39,11 +43,15 @@ The mental model, top to bottom:
|
|
|
39
43
|
mind/pipeline.ts the grounding decider: mechanisms compete on one cost scale
|
|
40
44
|
mind/mechanisms/* cover · cast · confluence · extraction · recall · alu
|
|
41
45
|
mind/* shared machinery: match/project, attention, recognition,
|
|
42
|
-
junction ascent, graph search, learning, rationale
|
|
46
|
+
junction ascent, graph search, learning, rationale;
|
|
47
|
+
recall's refusal-path tiers (bridge, prefix-completion,
|
|
48
|
+
frame-filler) live beside them, not inside recall.ts
|
|
43
49
|
store.ts AbstractStore: ALL domain logic of the DAG store
|
|
44
50
|
store-sqlite.ts the one concrete backend (thin SQL wrappers)
|
|
45
|
-
geometry.ts + vec/alphabet/sema
|
|
46
|
-
vectors, the fold
|
|
51
|
+
geometry.ts + vec/alphabet/sema/canon
|
|
52
|
+
vectors, the fold (content-defined cuts + two-ended
|
|
53
|
+
seats), every derived threshold, and the injected
|
|
54
|
+
content canonicalizer
|
|
47
55
|
derive/ · alu/ · rabitq-ivf/
|
|
48
56
|
firewalled sublibraries with their own READMEs and tests
|
|
49
57
|
```
|
|
@@ -79,32 +87,55 @@ Every similarity/decision threshold is a **formula** over the vector dimension
|
|
|
79
87
|
D, the perception window W, or the corpus size N, defined once in
|
|
80
88
|
`src/geometry.ts` (`mergeThreshold`, `identityBar`, `reachThreshold`,
|
|
81
89
|
`significanceBar`, `estimatorNoise`, `conceptThreshold`, `consensusFloor`,
|
|
82
|
-
`dominates`, …)
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
`dominates`, …), with the corpus-scale readings beside them in
|
|
91
|
+
`mind/traverse.ts` (`corpusN`, `hubBound`, `hubCap`, `atomReach`, `atomIsHub`).
|
|
92
|
+
`src/config.ts` holds **capacities and budgets only** (cache byte budgets, batch
|
|
93
|
+
sizes, vector-index parameters, query k, ALU precision, the seed).
|
|
85
94
|
|
|
86
95
|
_Follow it:_ if you are about to add a tunable cutoff to config, derive it in
|
|
87
96
|
`geometry.ts` instead. A threshold knob is a design bug here — one was already
|
|
88
97
|
removed once. When a decision needs a scale, express it in D, W, or N.
|
|
89
98
|
|
|
99
|
+
Two derivations bite in practice and are worth knowing before you reach for a
|
|
100
|
+
bar:
|
|
101
|
+
|
|
102
|
+
- `identityBar(D, W, len)` is the SCALE-AWARE identity claim (`1 − W/len`,
|
|
103
|
+
floored at `mergeThreshold`). Reuse `mergeThreshold` for a whole-span claim
|
|
104
|
+
and long spans silently tolerate whole windows of foreign content.
|
|
105
|
+
- A bar calibrated for one quantity does not transfer to another. `chooseNext`
|
|
106
|
+
carries a comment recording exactly this: the consensus floor is priced for
|
|
107
|
+
pooled, N-scaled climb votes, and gating an N-invariant support count against
|
|
108
|
+
it fails once N is large enough (test/40 pins it).
|
|
109
|
+
|
|
90
110
|
### 2.3 Exact decides, approximate proposes
|
|
91
111
|
|
|
92
112
|
Every score from the vector indexes (`resonate`, `resonateHalo`) is a RaBitQ
|
|
93
113
|
_estimate_. Identity is decided only by content-addressed lookup (`resolve`,
|
|
94
|
-
`findLeaf`, `findBranch`), never by
|
|
95
|
-
and gate broad regions; bytes make
|
|
114
|
+
`findLeaf`, `findBranch`, and the canonical fallback `canonResolve`), never by
|
|
115
|
+
`score >= threshold`. Scores rank candidates and gate broad regions; bytes make
|
|
116
|
+
decisions. Even the echo decision in `recall.ts` re-folds the top hit's bytes
|
|
117
|
+
rather than trusting the estimate it already has.
|
|
96
118
|
|
|
97
119
|
The same principle appears as **graded evidence ladders** — exact tier first,
|
|
98
|
-
distributional second, geometric last — in
|
|
120
|
+
distributional second, geometric last — in five places built on one shape:
|
|
99
121
|
|
|
122
|
+
- `resolve` in `mind/primitives.ts`: exact content-addressed fold →
|
|
123
|
+
`canonResolve` (equivalence class, hash-then-verify).
|
|
100
124
|
- `locate` in `mind/match.ts`: exact bytes → halo role → gist.
|
|
101
|
-
- `alignGraded` in `mind/match.ts`: literal W-gram runs → halo-matched sites
|
|
125
|
+
- `alignGraded` in `mind/match.ts`: literal W-gram runs → halo-matched sites
|
|
126
|
+
(the weave adds a third pass from the climb's own proposals — see
|
|
127
|
+
`pipeline-mechanism.ts`).
|
|
102
128
|
- `bridge` in `mind/resonance.ts`: junction containers by identity → edge
|
|
103
129
|
junctions → synonym junctions → whole-gist resonance as last resort.
|
|
130
|
+
- `crossRegionVotes` in `mind/attention.ts`: exact containers → single synonym →
|
|
131
|
+
double synonym → `structuralResonance` (a synthetic gist; the one tier with no
|
|
132
|
+
byte containment behind it, and gated hardest because of it).
|
|
104
133
|
|
|
105
134
|
_Follow it:_ never reorder a ladder's tiers, and never let an approximate tier
|
|
106
|
-
override an exact one.
|
|
107
|
-
|
|
135
|
+
override an exact one. Two asymmetries in `attention.ts` encode that rule and
|
|
136
|
+
must not be flattened: only the EXACT tier may explain ordinary votes away, and
|
|
137
|
+
only container-backed evidence may consume its endpoints. If you need a new
|
|
138
|
+
matcher, add a tier to the shared family (2.5), not a private score check.
|
|
108
139
|
|
|
109
140
|
### 2.4 One cost currency
|
|
110
141
|
|
|
@@ -112,15 +143,27 @@ The graph search's cost ladder (`mind/graph-search.ts`, exported constants) is
|
|
|
112
143
|
the single pricing scheme of the whole mind:
|
|
113
144
|
|
|
114
145
|
```
|
|
115
|
-
MICRO (1e-3) advance over recognised material; per-byte unit of the A* heuristic
|
|
116
|
-
|
|
117
|
-
|
|
146
|
+
MICRO (1e-3) advance over recognised material; per-byte unit of the A* heuristic;
|
|
147
|
+
a RECOMPOSED form's onward edge
|
|
148
|
+
STEP (1) follow one learned edge (EVERY hop, first or fifth); one computed
|
|
149
|
+
result; one projection
|
|
150
|
+
CONCEPT (10) a halo-mediated act (synonym hop, consensus climb); also the price
|
|
151
|
+
of ABANDONING an edge chain early (graph-search's stop-here rule)
|
|
118
152
|
PASS (1000/byte) carry a byte nothing explains
|
|
119
153
|
```
|
|
120
154
|
|
|
121
155
|
Only the _ordering_ matters. The pipeline weighs whole mechanisms in the same
|
|
122
156
|
units: `weight = moves + PASS · unaccounted-bytes`, so a mechanism-level choice
|
|
123
|
-
and a byte-level choice are the same kind of decision.
|
|
157
|
+
and a byte-level choice are the same kind of decision. Weights are compared at
|
|
158
|
+
STEP resolution (`grade = ⌊w/STEP⌋`); at equal grade the candidate reporting
|
|
159
|
+
fewer `scaffolding` bytes wins, and only then does the mechanism list's order
|
|
160
|
+
decide.
|
|
161
|
+
|
|
162
|
+
Two pricings inside `graph-search.ts` are easy to "simplify" and are not free to
|
|
163
|
+
change: charging every edge hop STEP is what makes the lightest derivation the
|
|
164
|
+
SHORTEST chain (charging later hops nothing made every stopping depth tie), and
|
|
165
|
+
the stop-here rule at CONCEPT-above-chain-cost is what keeps a genuine fixpoint
|
|
166
|
+
preferable to giving up at the same depth.
|
|
124
167
|
|
|
125
168
|
_Follow it:_ place any new cost deliberately in the ordering; never make the A\*
|
|
126
169
|
heuristic exceed a real per-byte cost (admissibility breaks silently — answers
|
|
@@ -132,10 +175,13 @@ policy in callers, the engine neutral.
|
|
|
132
175
|
|
|
133
176
|
`mind/match.ts` is the shared family every generalising mechanism configures:
|
|
134
177
|
matchers (`locate`, `alignRuns`, `alignGraded`, `bestHaloMate`, `haloSiblings`,
|
|
135
|
-
`analogyStrength`
|
|
136
|
-
`
|
|
137
|
-
`
|
|
138
|
-
|
|
178
|
+
`analogyStrength` and its structural tier `sharedFrameStrength`, `spanHalo`,
|
|
179
|
+
`spanSynonymStrength`), projections (`follow`, `reverseContext`, `project`,
|
|
180
|
+
`conceptHop`), and the span-shape family (`skillExemplar`, `isSpanShaped`,
|
|
181
|
+
`containsSpan`). `mind/traverse.ts` owns the graph readings (`edgeAncestors`,
|
|
182
|
+
`reachOf`, `chooseNext`/`chooseAmong`, `guidedFirst`, `leadsSomewhere`,
|
|
183
|
+
`allWindowsAreScaffolding`) and the corpus scale (`corpusN`, `hubBound`,
|
|
184
|
+
`hubCap`, `atomReach`).
|
|
139
185
|
|
|
140
186
|
_Follow it:_ before writing a new generalising mechanism, express it as a
|
|
141
187
|
(matcher, direction, gate) triple. If those already exist, the mechanism is a
|
|
@@ -155,21 +201,33 @@ without knowing extraction exists.
|
|
|
155
201
|
|
|
156
202
|
Related single-definition contracts (define once, import everywhere):
|
|
157
203
|
|
|
204
|
+
- `contentLevels` (`geometry.ts`) — the ONE boundary rule: where a stream
|
|
205
|
+
segments and at what level. `contentBoundaries` is a projection of it, not a
|
|
206
|
+
second copy; it used to carry its own rolling-hash loop, which is exactly how
|
|
207
|
+
a write side and a read side drift apart without a type error.
|
|
158
208
|
- `canonical.ts` — the write/read contract for canonical segmentation
|
|
159
209
|
(`canonicalWindows`, `chainReach`, `leafIdRun`, `leafIdPrefix`, `windowIds`).
|
|
160
|
-
Learning writes through it; recognition
|
|
161
|
-
Changing one side means changing this file
|
|
162
|
-
canonical recognition with **no type error**.
|
|
210
|
+
Learning writes through it; recognition, attention, confluence, the bridge and
|
|
211
|
+
prefix-completion read through it. Changing one side means changing this file
|
|
212
|
+
— drift between sides breaks canonical recognition with **no type error**.
|
|
163
213
|
- `junction.ts` — the content-addressed "which learnt whole contains these two
|
|
164
214
|
forms?" ascent, shared by the bridge and cross-region attention, with its
|
|
165
215
|
per-response `WalkCache` and once-per-candidate seed computation.
|
|
166
216
|
- `joinWithBridge` (`resonance.ts`) — the one out-of-search way to join two
|
|
167
217
|
answer spans; it emits a `bridgeMiss` trace step on a bare join.
|
|
218
|
+
- `dismissedKnownContent` (`bridge.ts`) — the one IGNORED-KNOWN test ("does the
|
|
219
|
+
unaccounted remainder contain a STORED window?"), shared by the substitution
|
|
220
|
+
bridge's own acceptance and CAST's frame-tier comparison gate.
|
|
221
|
+
- `sharedReachMemo` (`traverse.ts`) — the one definition of the ancestor-reach
|
|
222
|
+
memo's lifetime (session-scoped between writes, cold under a trace). There
|
|
223
|
+
used to be two memos that never met.
|
|
168
224
|
- `guidedFirst` (`traverse.ts`) — the one answer-shaped "what does this lead
|
|
169
225
|
to?" read (guided pick merged with the first-inserted fallback).
|
|
170
226
|
- `leadsSomewhere` (`traverse.ts`) — the one admission predicate for recognition
|
|
171
227
|
sites (edge-or-halo, via existence probes).
|
|
172
228
|
- `isChunk` (`sema.ts`) — the one "children are all leaves" predicate.
|
|
229
|
+
- `twoEndedSeat` (`sema.ts`) — the one positional-coordinate algebra, shared by
|
|
230
|
+
perception, `fold`, and every synthetic/canonical fold.
|
|
173
231
|
|
|
174
232
|
### 2.6 The mechanism market (the free-will architecture)
|
|
175
233
|
|
|
@@ -195,7 +253,12 @@ Four constraints make the market honest — verify all four for anything you add
|
|
|
195
253
|
(2.8).
|
|
196
254
|
4. **Evidence travels.** Every candidate carries `accounted` (query spans its
|
|
197
255
|
structural evidence explains), `moves` (its acts, priced on the ladder), and
|
|
198
|
-
`unexplained` (a diagnostic label).
|
|
256
|
+
`unexplained` (a diagnostic label). Two optional fields let a mechanism state
|
|
257
|
+
things only it can know: `scaffolding` (answer bytes lifted from spans
|
|
258
|
+
nothing recognised — the equal-grade tie-break) and `complete` (this answer
|
|
259
|
+
is a trained form's own continuation reached through an identity claim about
|
|
260
|
+
the query, so post-grounding must not extend it). The decider honours both
|
|
261
|
+
without ever asking which mechanism set them. It sees only weights.
|
|
199
262
|
|
|
200
263
|
Two disciplines inside the loop:
|
|
201
264
|
|
|
@@ -218,6 +281,16 @@ Evidence accounting rules that bite:
|
|
|
218
281
|
- **Reverse reading is not derivation.** A `reverseContext` projection produces
|
|
219
282
|
bytes but explains nothing forward: `accounted = []`, weight ≈ PASS·|query|.
|
|
220
283
|
It is the designated last resort by arithmetic, not by rule.
|
|
284
|
+
- **An act you PAID for is accounted.** The mirror of the rule above: the
|
|
285
|
+
bridge's corroborated substitutions cost a CONCEPT each in `moves`, so leaving
|
|
286
|
+
their spans unaccounted charges the same act twice — and the PASS-per-byte
|
|
287
|
+
charge is far the larger (measured: a bridge matching 28 of 29 bytes declared
|
|
288
|
+
the whole query unexplained and lost).
|
|
289
|
+
- `accounted` is a COST-LADDER quantity, not a coverage one. `cover.ts`
|
|
290
|
+
deliberately leaves masked computed spans out of it so PASS-bridged bytes are
|
|
291
|
+
still charged, so a fully-explained query can report `accounted: []`. The
|
|
292
|
+
post-grounding fusion gate therefore reads `accounted ∪ pre.computed`, not
|
|
293
|
+
`accounted` alone.
|
|
221
294
|
- `unexplained`, `narrowDecision`, and `thinGrounding` are **observational
|
|
222
295
|
only** — they appear in the trace and never alter the decision.
|
|
223
296
|
|
|
@@ -231,9 +304,16 @@ using the wrong one is a semantic bug the type system cannot catch:
|
|
|
231
304
|
filler/scaffolding gate. Answers "does this discriminate anything in the
|
|
232
305
|
store?"
|
|
233
306
|
- **Weave-local** — reference set: the structures aligned with _this query_.
|
|
234
|
-
Tooling: the `depth[]` array
|
|
235
|
-
Used by CAST's frame gate
|
|
236
|
-
structures this query
|
|
307
|
+
Tooling: the `depth[]` array built in `computeWeave` + `MIN_WEAVE` +
|
|
308
|
+
`dominates`. Used by CAST's frame gate and by the frame filler's constituency
|
|
309
|
+
reading. Answers "does this discriminate among the structures this query
|
|
310
|
+
activates?"
|
|
311
|
+
|
|
312
|
+
`depth[]` counts **distinct covering structures**, not accumulated alignment
|
|
313
|
+
weight: the frame test compares it against a COUNT of aligned points, so
|
|
314
|
+
accumulating weight there compares weight-mass against a cardinality. It reads
|
|
315
|
+
like a harmless refinement and inverts the frame verdict (measured: 29 of 42
|
|
316
|
+
bytes reading FRAME against 6 of 42, with nothing else changed).
|
|
237
317
|
|
|
238
318
|
_Follow it:_ when adding a gate on "shared vs. discriminative", write down which
|
|
239
319
|
population your question is about before choosing the tool. Substituting one for
|
|
@@ -252,10 +332,21 @@ Crucially, the cap is enforced **at the store level**:
|
|
|
252
332
|
`prevCount` — indexed point probes that never decode vectors or unpack blobs.
|
|
253
333
|
Use them for every "does this lead anywhere?" question instead of
|
|
254
334
|
`next(id).length > 0`.
|
|
335
|
+
- Prefix-capped reads: `bytesPrefix(id, cap)` and `contentLen(id, cap)`. A
|
|
336
|
+
candidate that exceeds the cap is rejected without reconstructing it — the
|
|
337
|
+
weave, the junction walks and the bridge all read this way, and uncapped reads
|
|
338
|
+
there cost seconds per query on a large store.
|
|
255
339
|
- `chainRun` climbs transparent scaffolding chains in one bounded read.
|
|
256
340
|
- The full materialising reads (`next`, `prev`, `parents`, `containers`) exist
|
|
257
341
|
for maintenance and inspection only. Keep them off hot paths.
|
|
258
342
|
|
|
343
|
+
`edgeAncestors` is the reference consumer: it decides saturation from LIMITed
|
|
344
|
+
reads alone, by five named stops (predecessor fan-in, distinct-context limit,
|
|
345
|
+
parent fan-out, the cumulative **lateral-cone** bound, and **byte-atom**
|
|
346
|
+
commonality). The last two are the ones a new walk forgets. An atom carries no
|
|
347
|
+
kid/contain rows by construction, so its commonality is unmeasurable and must
|
|
348
|
+
not default to "maximally rare" — `atomReach`/`atomIsHub` are the honest floor.
|
|
349
|
+
|
|
259
350
|
_Follow it:_ any new fan-out walk uses `hubBound`/`hubCap` — do not invent a
|
|
260
351
|
second convention, and do not call `edgeSourceCount()` or
|
|
261
352
|
`Math.ceil(Math.sqrt(...))` inline.
|
|
@@ -282,8 +373,16 @@ respect:
|
|
|
282
373
|
copy first.
|
|
283
374
|
- `contentLen(id, cap?)` reads a node's byte length; pass `cap` when exact
|
|
284
375
|
length beyond a bound doesn't matter.
|
|
285
|
-
-
|
|
286
|
-
|
|
376
|
+
- The **canon index** (`canonAdd`/`canonFind`/`canonCount`/`eachContent`) is an
|
|
377
|
+
OPTIONAL capability: a backend may omit all four, and resolution then simply
|
|
378
|
+
has no equivalence fallback. The store never learns what the equivalence IS —
|
|
379
|
+
the canonicalizer is injected by the caller and every candidate is verified by
|
|
380
|
+
re-canonicalizing its bytes, so a hash collision costs a read, never a wrong
|
|
381
|
+
id.
|
|
382
|
+
- Maintenance entry points (`compactContentIndex`, `repairContentIndex`,
|
|
383
|
+
`Mind.buildCanonIndex`) are batch operations for checkpoints, never the hot
|
|
384
|
+
path. `buildCanonIndex` is incremental — it remembers the last indexed id in
|
|
385
|
+
store meta — and must be run under the SAME canonicalizer queries will carry.
|
|
287
386
|
|
|
288
387
|
### 2.10 The async/sync seam and pre-resolution
|
|
289
388
|
|
|
@@ -298,19 +397,40 @@ Do not try to make the search async.
|
|
|
298
397
|
|
|
299
398
|
Asking never writes, which is the only reason per-response memos are sound.
|
|
300
399
|
`Precomputed` (`pipeline-mechanism.ts`) is the shared response-scoped container:
|
|
301
|
-
eager fields (recognition, computed spans, guide
|
|
302
|
-
for expensive analyses (`attention()` — the
|
|
303
|
-
`
|
|
304
|
-
|
|
305
|
-
nobody asks.
|
|
400
|
+
eager fields (recognition, computed spans, guide, the evidence-breadth constant
|
|
401
|
+
`k`) plus **lazily-cached methods** for expensive analyses (`attention()` — the
|
|
402
|
+
consensus climb, `weave()`, `spanShapedOf`/`spanShapedAll`, `queryWindows`,
|
|
403
|
+
`queryResolved`, `windowsOf`, `reachMemo`) — each computed at most once, shared
|
|
404
|
+
by mechanisms and post-grounding stages, and never computed if nobody asks. The
|
|
405
|
+
async ones are cached **by promise**, so a second caller awaits the first
|
|
406
|
+
computation rather than starting another.
|
|
407
|
+
|
|
408
|
+
Mind-level memos (`climbMemo`, `recogniseMemo`, `perceiveMemo`, `canonMemo`,
|
|
409
|
+
`_resolvedSubtrees`, `_edgeChoice`, `_gistCache`) are created in
|
|
410
|
+
`beginResponse()` and torn down in `endResponse()` — a new memo must be added to
|
|
411
|
+
both. A conversation supplies its own maps for the first four, so they persist
|
|
412
|
+
across turns.
|
|
413
|
+
|
|
414
|
+
**Which memos a trace bypasses, and why the answer is "almost none".** Only
|
|
415
|
+
`_edgeChoice` (via `guidedNext`) and `sharedReachMemo` are trace-bypassed —
|
|
416
|
+
there, a memo hit would swallow a repeat's `disambiguate` step or black out
|
|
417
|
+
reach detail the trace serialises. `perceiveMemo`, `recogniseMemo` and
|
|
418
|
+
`climbMemo` are **always** consulted, tracing or not, and that is a correctness
|
|
419
|
+
contract rather than a speed choice: `recogniseImpl` walks the query tree
|
|
420
|
+
through `foldTree`, whose subtree-resolution fast path skips `visit` — and
|
|
421
|
+
therefore skips EMITTING SITES — for any subtree already cached. A second call
|
|
422
|
+
on identical bytes is not idempotent; it finds strictly fewer sites (observed:
|
|
423
|
+
31 → 5). Bypassing these under trace made every traced turn re-run recognition
|
|
424
|
+
at each of the many call sites that recognise the same query, each call more
|
|
425
|
+
incomplete than the last, measurably changing which mechanism grounded the
|
|
426
|
+
answer (test/42 pins this). Trace steps still fire on a cache hit, so a hit is
|
|
427
|
+
never silent.
|
|
306
428
|
|
|
307
429
|
_Follow it:_ an expensive analysis a new mechanism needs goes on `Precomputed`
|
|
308
|
-
as a lazy method, not inside the mechanism.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
attached (every mechanism must emit its steps); `perceiveMemo` is not.
|
|
313
|
-
Consequence: **never benchmark with a trace attached.**
|
|
430
|
+
as a lazy method, not inside the mechanism. Do not add a `if (!ctx.trace)` guard
|
|
431
|
+
to a memo without checking whether the memoised function is idempotent. And
|
|
432
|
+
still **never benchmark with a trace attached** — the two bypassed memos, plus
|
|
433
|
+
the trace's own allocation, measure a different machine.
|
|
314
434
|
|
|
315
435
|
### 2.12 Caches are budgets, not correctness
|
|
316
436
|
|
|
@@ -320,6 +440,16 @@ under pressure is always speed or reach (a re-perception, a duplicate probe,
|
|
|
320
440
|
reduced resonance until repair), never identity, reconstruction, or a learned
|
|
321
441
|
relation.
|
|
322
442
|
|
|
443
|
+
The deposit-path caches (`_depositTrees`/`_depositLens` for folded segments,
|
|
444
|
+
`_internIds` for already-interned tree nodes, `_resolvedSubtrees` for resolved
|
|
445
|
+
ones) obey the same rule, with one extra obligation: `contentFoldIncremental`
|
|
446
|
+
reuses segments keyed on their **offsets**, which cannot witness that the
|
|
447
|
+
underlying bytes agree. The caller must discharge that structurally — the
|
|
448
|
+
deposit cache is keyed by the prefix's own bytes, and a conversation's fold
|
|
449
|
+
advances only by append. A caller that cannot make the same argument passes no
|
|
450
|
+
`prev` at all; the cold path is always correct. Handing it a mismatched `prev`
|
|
451
|
+
produced a wrong tree on 336 of 400 random streams.
|
|
452
|
+
|
|
323
453
|
_Follow it:_ new caches get budgets and a re-derivation path. If memory grows,
|
|
324
454
|
look for something bypassing a budget — not for a leak in the DAG (nodes are
|
|
325
455
|
meant to accumulate).
|
|
@@ -327,9 +457,11 @@ meant to accumulate).
|
|
|
327
457
|
### 2.13 Honest degradation, visible failure
|
|
328
458
|
|
|
329
459
|
Nothing degrades silently: counters (`danglingReads`, `compactFailures`), trace
|
|
330
|
-
steps (`bridgeMiss`, `narrowDecision`, `thinGrounding
|
|
331
|
-
|
|
332
|
-
|
|
460
|
+
steps (`bridgeMiss`, `narrowDecision`, `thinGrounding`, `skipMechanism` with the
|
|
461
|
+
reason it skipped, `anchorFallback`), the `echoed` flag on recall's last tier,
|
|
462
|
+
`recall-echo` provenance, and the per-region/per-anchor rejection reasons in the
|
|
463
|
+
climb's structured payload. Empty results are legitimate outputs (silence), not
|
|
464
|
+
errors — and several suites assert exactly that (5).
|
|
333
465
|
|
|
334
466
|
_Follow it:_ when your code can degrade, emit a counter or trace step. And mind
|
|
335
467
|
the classic trap: **empty bytes are truthy** — `Uint8Array(0)` passes
|
|
@@ -374,10 +506,41 @@ _Follow it:_ a new layer that wants to be visible bumps a field in `meter.ts`
|
|
|
374
506
|
never a private counter. (`danglingReads`/`compactFailures` in `store.ts` stay:
|
|
375
507
|
those are session-lifetime HEALTH counters, not per-response work.) Add the
|
|
376
508
|
counter to the report the same way, and remember the classic trap: **profile
|
|
377
|
-
without a trace attached**
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
509
|
+
without a trace attached** (2.11).
|
|
510
|
+
|
|
511
|
+
### 2.15 The fold contract: train and infer must agree
|
|
512
|
+
|
|
513
|
+
`perceiveDeposit` and `perceive` must produce the SAME tree for the same bytes.
|
|
514
|
+
That is not a nicety — it is what makes a trained context node and the node
|
|
515
|
+
`resolve(query)` reaches the same node. The deposit path therefore imposes
|
|
516
|
+
nothing: no boundaries, no turn convention, nothing read out of the bytes. When
|
|
517
|
+
the two sides disagreed, the alignment family went quadratic (measured: 5.2M
|
|
518
|
+
cells on a 476-byte context, against 0 when they agree) and cumulative contexts
|
|
519
|
+
stopped resolving to what they were trained as.
|
|
520
|
+
|
|
521
|
+
Three consequences you will meet:
|
|
522
|
+
|
|
523
|
+
- **Boundaries are a separate feature from reuse.** `contentFoldIncremental`
|
|
524
|
+
(segment reuse, transparent, imposes nothing) and `stablePrefixFold`
|
|
525
|
+
(caller-supplied cuts, left-nested, buys prefix-ROOT identity) solve different
|
|
526
|
+
problems. Conflating them is what once put an imposed boundary set on the
|
|
527
|
+
inference path.
|
|
528
|
+
- **A conversation's turn offsets are API metadata**, not a fold instruction.
|
|
529
|
+
They feed `ConversationState`, `answeredSpans` and `currentTurnStart`; the
|
|
530
|
+
geometry never sees them.
|
|
531
|
+
- **Identity must not depend on W**, or on absolute offset. If you are adding
|
|
532
|
+
anything that groups by index — a stride, a tile, a fixed-arity row — you are
|
|
533
|
+
reintroducing the bug content-defined cuts exist to remove. Two such attempts
|
|
534
|
+
are recorded as refuted at `collectRegions` and `contentLevels`; test/59 and
|
|
535
|
+
test/63 pin the invariance floors.
|
|
536
|
+
|
|
537
|
+
_Follow it:_ changes to `contentLevels` — the cut rate, which bits are read, the
|
|
538
|
+
minimum/maximum segment length, the forced cut — are changes to the segment
|
|
539
|
+
DISTRIBUTION every downstream mechanism is fitted to. Each of those four has
|
|
540
|
+
been altered experimentally and cost 5–21 tests. Re-measure the whole suite, not
|
|
541
|
+
the one query that motivated the change.
|
|
542
|
+
|
|
543
|
+
### 2.16 Comment style
|
|
381
544
|
|
|
382
545
|
Comments state _constraints and failure modes_ — "this guard exists because X
|
|
383
546
|
breaks without it", often naming the test that pins the behaviour — never
|
|
@@ -391,28 +554,32 @@ story of the fix.
|
|
|
391
554
|
|
|
392
555
|
## 3. Where things live
|
|
393
556
|
|
|
394
|
-
| Concept
|
|
395
|
-
|
|
|
396
|
-
| Public surface / assembly
|
|
397
|
-
|
|
|
398
|
-
|
|
|
399
|
-
|
|
|
400
|
-
|
|
|
401
|
-
|
|
|
402
|
-
|
|
|
403
|
-
|
|
|
404
|
-
|
|
|
405
|
-
|
|
|
406
|
-
|
|
|
407
|
-
|
|
|
408
|
-
|
|
|
409
|
-
|
|
|
410
|
-
|
|
|
411
|
-
|
|
|
412
|
-
|
|
|
413
|
-
|
|
|
414
|
-
|
|
|
415
|
-
|
|
|
557
|
+
| Concept | File(s) |
|
|
558
|
+
| :-------------------------------------------------- | :-------------------------------------------------------------------------------- |
|
|
559
|
+
| Public surface / assembly | `src/index.ts`, `src/mind/mind.ts` |
|
|
560
|
+
| Conversation API (turns, state, answered spans) | `src/mind/mind.ts` |
|
|
561
|
+
| Config (capacities, budgets, seed) | `src/config.ts` |
|
|
562
|
+
| Derived thresholds, the fold, Hilbert | `src/geometry.ts` |
|
|
563
|
+
| Content canonicalizer (injected, modality-specific) | `src/canon.ts` |
|
|
564
|
+
| Vector primitives, alphabet, node/fold types, seats | `src/vec.ts`, `src/alphabet.ts`, `src/sema.ts` |
|
|
565
|
+
| Perceive / resolve / read primitives | `src/mind/primitives.ts` |
|
|
566
|
+
| Store domain logic / SQLite adapter | `src/store.ts`, `src/store-sqlite.ts` |
|
|
567
|
+
| Mechanism contract + shared `Precomputed` | `src/mind/pipeline-mechanism.ts` |
|
|
568
|
+
| The grounding decider (`think`) | `src/mind/pipeline.ts` |
|
|
569
|
+
| Grounding mechanisms (one file each) | `src/mind/mechanisms/{cover,cast,confluence,extraction,recall,alu}.ts` |
|
|
570
|
+
| Weighted deduction system + cost ladder | `src/mind/graph-search.ts` (engine in `src/derive/`) |
|
|
571
|
+
| Match/project family | `src/mind/match.ts` |
|
|
572
|
+
| Graph traversal, corpus scale, disambiguators | `src/mind/traverse.ts` |
|
|
573
|
+
| Consensus climb + cross-region attention | `src/mind/attention.ts` |
|
|
574
|
+
| Recall's refusal-path tiers | `src/mind/bridge.ts`, `src/mind/prefix-completion.ts`, `src/mind/frame-filler.ts` |
|
|
575
|
+
| Recognition / canonical contract | `src/mind/recognition.ts`, `src/mind/canonical.ts` |
|
|
576
|
+
| Junction ascent (bridge + attention share) | `src/mind/junction.ts`, `src/mind/resonance.ts` |
|
|
577
|
+
| Learning / ingestion / training cache | `src/mind/learning.ts`, `src/ingest-cache.ts` |
|
|
578
|
+
| Post-grounding (reason, fuse, articulate) | `src/mind/reasoning.ts`, `src/mind/articulation.ts` |
|
|
579
|
+
| Rationale / trace | `src/mind/rationale.ts`, `src/mind/trace.ts` |
|
|
580
|
+
| Computational-usage meter | `src/meter.ts` (harness: `bench/profile-inference.mjs`) |
|
|
581
|
+
| Extension host types | `src/extension.ts` |
|
|
582
|
+
| Sublibraries (own READMEs, own tests) | `src/derive/`, `src/alu/`, `src/rabitq-ivf/` |
|
|
416
583
|
|
|
417
584
|
Mind functions are **free functions over `MindContext`** (`mind/types.ts`), not
|
|
418
585
|
methods — `mind.ts` is a thin assembly that implements the context and
|
|
@@ -427,13 +594,19 @@ with no hidden `this` state.
|
|
|
427
594
|
|
|
428
595
|
Implement `PipelineMechanism`: `floor` returns an admissible bound or `null`
|
|
429
596
|
(structurally can't fire); `run` returns candidates with `bytes`, `accounted`,
|
|
430
|
-
`moves`, `unexplained
|
|
431
|
-
|
|
597
|
+
`moves`, `unexplained` (plus `scaffolding`/`complete` when your mechanism can
|
|
598
|
+
state them); add `parse` only if you compute authoritative spans (the ALU's
|
|
599
|
+
`aluToMechanism` in `mechanisms/alu.ts` is the reference). Register with
|
|
432
600
|
`new Mind({ mechanismFactories: [host => yourMechanism(host)] })` (or
|
|
433
601
|
`mechanisms: [...]` if no host is needed); reach meaning only through the
|
|
434
602
|
`ExtensionHost`. Verify the four market constraints (2.6). You never touch
|
|
435
603
|
`think()` or another mechanism's file.
|
|
436
604
|
|
|
605
|
+
If your `floor` needs an expensive shared analysis to be tight, check
|
|
606
|
+
`worthRunning(cheapestBound)` FIRST and return the uninvested bound when it
|
|
607
|
+
already fails — that is the investment discipline (2.6), and `cast.ts` /
|
|
608
|
+
`extraction.ts` are the two reference implementations.
|
|
609
|
+
|
|
437
610
|
### Add an ALU operation
|
|
438
611
|
|
|
439
612
|
One declarative `registry.derive(name, arity, surfaceForms, body)` in the
|
|
@@ -464,6 +637,29 @@ Hilbert-linearizes it; `Grid[]` stacks frames. Anything else: produce a
|
|
|
464
637
|
`Uint8Array` with a deterministic, locality-preserving ordering. Nothing
|
|
465
638
|
downstream changes.
|
|
466
639
|
|
|
640
|
+
A modality may also supply its own **canonicalizer** (`Canon`) and its own
|
|
641
|
+
reading of "edge" — that is the one place presentation rules belong. Nothing in
|
|
642
|
+
the store or the mind's core knows what case or whitespace is; the text entry
|
|
643
|
+
points inject `textCanon`/`textEdgeTrim`, byte and grid inputs inject neither
|
|
644
|
+
(for them `0x20` is content). If you find yourself adding a character class
|
|
645
|
+
inside a mechanism, it belongs here instead.
|
|
646
|
+
|
|
647
|
+
### Hold a conversation
|
|
648
|
+
|
|
649
|
+
```ts
|
|
650
|
+
const conv = mind.beginConversation(savedState); // state optional
|
|
651
|
+
const { response, state } = await mind.respondTurnText(conv, "…");
|
|
652
|
+
mind.addTurn(conv, "…"); // a turn to hear but not answer
|
|
653
|
+
mind.endConversation(conv);
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
Turns append raw bytes plus an offset — never a separator. To replay a corpus
|
|
657
|
+
that joins turns with `"\n"`, pass `"\n" + turnText` as the turn; the separator
|
|
658
|
+
rides inside the turn bytes, where it belongs. `ConversationState` (context,
|
|
659
|
+
boundaries, answered spans) is serialisable and restores exactly. One
|
|
660
|
+
`respondTurn` may be in flight per Mind: the conversation's memos are swapped
|
|
661
|
+
into the response-scoped slots for the turn's duration.
|
|
662
|
+
|
|
467
663
|
### Debug an answer
|
|
468
664
|
|
|
469
665
|
```ts
|
|
@@ -476,7 +672,18 @@ console.log(r.provenance); // cast | join | cover | extract | recall | recall-ec
|
|
|
476
672
|
Read top-down: which mechanism fired (and why the others abstained), what
|
|
477
673
|
recognition found, how the climb voted, which edges were followed
|
|
478
674
|
(`disambiguate` steps carry the evidence). `recall-echo` means "nearest stored
|
|
479
|
-
form, not a derived fact".
|
|
675
|
+
form, not a derived fact".
|
|
676
|
+
|
|
677
|
+
Three steps carry **structured data**, so tooling need not parse notes:
|
|
678
|
+
`decideGrounding` (every candidate's provenance, exact weight, discrete grade,
|
|
679
|
+
unexplained bytes, which won, plus the runner-up margin), `climbConsensus` (per
|
|
680
|
+
region: source, span, selected anchor, IDF, contrastive margin and its rival,
|
|
681
|
+
mutual weight, outcome; per anchor: pooled vote, peak, breadth, clusters, and
|
|
682
|
+
the live commit verdict with its rejection reasons; plus every cross-region
|
|
683
|
+
probe and its tier), and `narrowDecision`. When an answer is wrong, the fastest
|
|
684
|
+
route is usually `decideGrounding` first (was the right mechanism outbid, or did
|
|
685
|
+
it never produce a candidate?), then the per-region climb detail (did the
|
|
686
|
+
evidence vote at all?).
|
|
480
687
|
|
|
481
688
|
### Profile an answer
|
|
482
689
|
|
|
@@ -497,7 +704,8 @@ Use `CachedIngest` (`ingest-cache.ts`) as a drop-in for `mind.ingest` — it
|
|
|
497
704
|
memoises perceive+intern of repeated inputs and routes through the same
|
|
498
705
|
`dispatchIngest` as the direct path (shape detection can't drift). Call
|
|
499
706
|
`store.commit()` at checkpoints; run `compactContentIndex` /
|
|
500
|
-
`repairContentIndex` post-training if eviction was heavy
|
|
707
|
+
`repairContentIndex` post-training if eviction was heavy, and
|
|
708
|
+
`mind.buildCanonIndex()` if queries will carry a canonicalizer (2.9). See
|
|
501
709
|
`example/train_base.ts`. Profiling note: the first `resonate` after a big ingest
|
|
502
710
|
pays the pending index flush; the dominant query-side ANN cost is connector
|
|
503
711
|
pre-resolution (bounded by recognised-site count — don't add another loop over
|
|
@@ -516,10 +724,15 @@ against the built `dist/` (`npm test`; one suite:
|
|
|
516
724
|
- Many tests pin **contracts that look like implementation details** (the bridge
|
|
517
725
|
tier order, the bridge's identity admission vs. its prefix trap and the
|
|
518
726
|
scaffolding reading behind it, the two span-shape readings (`match.ts`),
|
|
519
|
-
`MechanismResult.complete`,
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
727
|
+
`MechanismResult.complete`, fold invariance under shifts (test/59, test/63),
|
|
728
|
+
recognition's idempotence under trace (test/42), the cross-region tier ladder
|
|
729
|
+
(test/51), the instrumentation payloads (test/52–55), determinism, honest
|
|
730
|
+
silence). A "simplification" that fails an existing test is wrong until you
|
|
731
|
+
can argue the _test_ is wrong — several guards exist precisely because a
|
|
732
|
+
plausible simplification once failed a dozen suites.
|
|
733
|
+
- **Honest silence is a tested behaviour, not an absence of one.** Several
|
|
734
|
+
suites assert that a query grounds NOTHING; a change that makes the engine
|
|
735
|
+
more forthcoming fails them, and that is the suite working.
|
|
523
736
|
- Sublibraries test themselves (`src/{alu,derive,rabitq-ivf}/test/`) with zero
|
|
524
737
|
Sema dependency. Keep it so.
|
|
525
738
|
- Performance claims are tested (the rabitq-ivf benchmark asserts sub-linear
|