@hviana/sema 0.5.2 → 0.5.3
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 +114 -52
- package/HOW_IT_WORKS.md +275 -184
- package/dist/src/mind/bridge.d.ts +5 -7
- package/dist/src/mind/bridge.js +6 -97
- package/dist/src/mind/match.d.ts +159 -0
- package/dist/src/mind/match.js +300 -7
- package/dist/src/mind/mechanisms/prefix-completion.d.ts +22 -0
- package/dist/src/mind/{prefix-completion.js → mechanisms/prefix-completion.js} +64 -91
- package/dist/src/mind/mechanisms/recall.js +10 -108
- package/dist/src/mind/mechanisms/reference.d.ts +6 -0
- package/dist/src/mind/mechanisms/reference.js +296 -0
- package/dist/src/mind/mind.d.ts +1 -1
- package/dist/src/mind/pipeline-mechanism.d.ts +56 -1
- package/dist/src/mind/pipeline-mechanism.js +104 -3
- package/dist/src/mind/pipeline.d.ts +1 -1
- package/dist/src/mind/pipeline.js +13 -1
- package/dist/src/mind/traverse.d.ts +38 -0
- package/dist/src/mind/traverse.js +91 -1
- package/dist/src/store.d.ts +4 -4
- package/jsr.json +6 -0
- package/package.json +1 -1
- package/src/mind/bridge.ts +10 -104
- package/src/mind/match.ts +416 -7
- package/src/mind/{prefix-completion.ts → mechanisms/prefix-completion.ts} +66 -92
- package/src/mind/mechanisms/recall.ts +9 -126
- 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 +471 -0
- package/dist/src/mind/frame-filler.d.ts +0 -15
- package/dist/src/mind/frame-filler.js +0 -535
- package/dist/src/mind/prefix-completion.d.ts +0 -59
- package/src/mind/frame-filler.ts +0 -604
- package/test/69-frame-filler.test.mjs +0 -115
|
@@ -16,14 +16,21 @@
|
|
|
16
16
|
import type { AncestorReach, MindContext, Recognition } from "./types.js";
|
|
17
17
|
import type { AttentionRead } from "./types.js";
|
|
18
18
|
import type { ComputedSpan } from "../extension.js";
|
|
19
|
+
import type { Hit } from "../store.js";
|
|
19
20
|
import type { Vec } from "../vec.js";
|
|
20
21
|
import { indexOf } from "../bytes.js";
|
|
21
|
-
import { dominates } from "../geometry.js";
|
|
22
|
+
import { conceptThreshold, dominates } from "../geometry.js";
|
|
22
23
|
import { windowIds } from "./canonical.js";
|
|
23
24
|
import { read, resolve } from "./primitives.js";
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
alignGraded,
|
|
27
|
+
type FrameInstance,
|
|
28
|
+
frameSlots,
|
|
29
|
+
type GradedRun,
|
|
30
|
+
skillExemplar,
|
|
31
|
+
} from "./match.js";
|
|
25
32
|
import { climbAttentionAll } from "./attention.js";
|
|
26
|
-
import { sharedReachMemo } from "./traverse.js";
|
|
33
|
+
import { hubBound, sharedReachMemo } from "./traverse.js";
|
|
27
34
|
|
|
28
35
|
// ── Precomputed ──────────────────────────────────────────────────────────────
|
|
29
36
|
//
|
|
@@ -125,6 +132,116 @@ export class Precomputed {
|
|
|
125
132
|
return meter ? meter.time(phase, fn) : fn();
|
|
126
133
|
}
|
|
127
134
|
|
|
135
|
+
private _resonance?: Promise<ReadonlyArray<Hit>>;
|
|
136
|
+
/** The response's ONE top-k content-index read: the k learnt forms nearest
|
|
137
|
+
* the whole-query gist, ranked. Recall's every gist tier is built on it,
|
|
138
|
+
* and {@link frames} assembles the frame inventory from it.
|
|
139
|
+
*
|
|
140
|
+
* An ANN query is the single most expensive read in the engine, and two
|
|
141
|
+
* mechanisms asking the same question of the same gist is the one
|
|
142
|
+
* duplication a profile shows as doubled `annVectorReads` with nothing to
|
|
143
|
+
* account for it. Cached BY PROMISE, so a second caller awaits the first. */
|
|
144
|
+
resonance(): Promise<ReadonlyArray<Hit>> {
|
|
145
|
+
return this._resonance ??= this.shared(
|
|
146
|
+
"resonance",
|
|
147
|
+
() => this.ctx.store.resonate(this.guide, this.k),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _wide?: Promise<ReadonlyArray<number>>;
|
|
152
|
+
/** The response's WIDE candidate list — the top-k when the query's gist has
|
|
153
|
+
* no concept-level match anywhere, and an exhaustive √N read when it does.
|
|
154
|
+
*
|
|
155
|
+
* Every mechanism that has to look PAST the top-k reads this one list: the
|
|
156
|
+
* substitution bridge, prefix completion and the frame filler all did, and
|
|
157
|
+
* it was memoised inside recall for exactly that reason (measured: 490 ms
|
|
158
|
+
* median re-issued against 13 ms non-exhaustive, 36x). A memo inside one
|
|
159
|
+
* mechanism only serves that mechanism's own tiers, so it lives here now —
|
|
160
|
+
* the same move `resonance` made for the top-k.
|
|
161
|
+
*
|
|
162
|
+
* THE CONDITION IS THE TOP HIT'S SCORE, NOT THE CORPUS SIZE. When nothing
|
|
163
|
+
* ranks at concept level, an exhaustive ANN only scores more vectors below
|
|
164
|
+
* the bar (profiled at 38K–40K annVectorReads per refusing query on a 325K-
|
|
165
|
+
* context store); the structural channels — junction walks, anchor climbs,
|
|
166
|
+
* the write side's window index — are the correct proposal source there,
|
|
167
|
+
* because the ANN cannot propose what the gist cannot rank. This was once
|
|
168
|
+
* spelled `corpusN(ctx) <= (k · W)³`, which asks a different question and
|
|
169
|
+
* answers it wrongly at exactly the scale it was written from: at N =
|
|
170
|
+
* 325,608 with k = 24 and W = 4 the cube is 884,736, so that store took the
|
|
171
|
+
* exhaustive branch — the very branch measured above. Measured cost of the
|
|
172
|
+
* mismatch: substitutionBridge 8,544 ms of a 19,548 ms think (44%), against
|
|
173
|
+
* 1,248 ms and 14,218 ms without it, every answer byte-identical. */
|
|
174
|
+
wideResonance(): Promise<ReadonlyArray<number>> {
|
|
175
|
+
return this._wide ??= this.shared("wideResonance", async () => {
|
|
176
|
+
const hits = await this.resonance();
|
|
177
|
+
if (
|
|
178
|
+
hits.length > 0 &&
|
|
179
|
+
hits[0].score >= conceptThreshold(this.ctx.store.D)
|
|
180
|
+
) {
|
|
181
|
+
const exhaustive = await this.ctx.store.resonate(
|
|
182
|
+
this.guide,
|
|
183
|
+
hubBound(this.ctx),
|
|
184
|
+
true,
|
|
185
|
+
);
|
|
186
|
+
return exhaustive.map((h) => h.id);
|
|
187
|
+
}
|
|
188
|
+
return hits.map((h) => h.id);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private _frames?: Promise<ReadonlyArray<FrameInstance>>;
|
|
193
|
+
/** THE FRAME INVENTORY — every ranked candidate that reads as an instance of
|
|
194
|
+
* the same frame as the query, each with the query spans it leaves VARIABLE
|
|
195
|
+
* ({@link FrameInstance}). The one place the engine represents "a position
|
|
196
|
+
* whose occupant comes from the context rather than the corpus".
|
|
197
|
+
*
|
|
198
|
+
* AN INVENTORY, NOT AN ELECTION. It reports every pairing and elects no
|
|
199
|
+
* frame, deliberately: a slot is a property of a PAIRING, not of the query,
|
|
200
|
+
* and different candidates put slots in different places. Committing to one
|
|
201
|
+
* reading here would push whichever consumer asked first onto everyone else
|
|
202
|
+
* — the market's decoupling (§2.6) broken from inside the shared container,
|
|
203
|
+
* and the population error §2.7 names. Each consumer groups and commits
|
|
204
|
+
* for its own question; reference elects the modal slot signature, and a
|
|
205
|
+
* consumer wanting a different reading is not fighting this one.
|
|
206
|
+
*
|
|
207
|
+
* NO LICENCE EITHER. Knowing a span is variable is safe for every consumer
|
|
208
|
+
* — it can only improve an alignment. Knowing one may be VOICED through is
|
|
209
|
+
* a different and much stronger claim, gated separately by
|
|
210
|
+
* {@link carriesFillers}, which needs projections this must not perform. */
|
|
211
|
+
frames(): Promise<ReadonlyArray<FrameInstance>> {
|
|
212
|
+
return this._frames ??= this.shared("frames", async () => {
|
|
213
|
+
const ctx = this.ctx;
|
|
214
|
+
const W = ctx.space.maxGroup;
|
|
215
|
+
// PHRASE SCALE, the same bound the bridge and the frame filler put on a
|
|
216
|
+
// candidate's bytes: a form an order of magnitude longer than the query
|
|
217
|
+
// is not a candidate for BEING it with a span replaced.
|
|
218
|
+
const capBytes = this.query.length * W;
|
|
219
|
+
const out: FrameInstance[] = [];
|
|
220
|
+
for (const h of await this.resonance()) {
|
|
221
|
+
// REJECT BY LENGTH BEFORE RECONSTRUCTING (§2.8): `contentLen` is an
|
|
222
|
+
// indexed read, `bytesPrefix` rebuilds a subtree. ONLY the phrase-scale
|
|
223
|
+
// cap is applied — it is a bounded-read discipline, not a judgement.
|
|
224
|
+
//
|
|
225
|
+
// A LOWER bound was here too (`dominates(len, query.length)`, on the
|
|
226
|
+
// reasoning that a candidate shorter than half the query cannot supply
|
|
227
|
+
// a frame that dominates it). That is reference's gate wearing a cost
|
|
228
|
+
// argument's clothes, and it hid the very pairings another consumer
|
|
229
|
+
// needs: `What is the capital of France?` (30 B) against `What is the
|
|
230
|
+
// capital of the country where the Eiffel Tower is?` (61 B) was
|
|
231
|
+
// rejected before it was ever read — a definite description standing
|
|
232
|
+
// where a noun stands, which is exactly the shape the frame filler
|
|
233
|
+
// exists for.
|
|
234
|
+
const len = ctx.store.contentLen(h.id, capBytes + 1);
|
|
235
|
+
if (len === 0 || len > capBytes) continue;
|
|
236
|
+
const cand = ctx.store.bytesPrefix(h.id, capBytes + 1);
|
|
237
|
+
if (cand.length === 0 || cand.length > capBytes) continue;
|
|
238
|
+
const inst = frameSlots(ctx, this.query, cand, h.id);
|
|
239
|
+
if (inst !== null) out.push(inst);
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
128
245
|
private _attention?: Promise<AttentionRead>;
|
|
129
246
|
/** The full consensus climb (roots + ranked anchors) — the query-level
|
|
130
247
|
* evidence CAST, confluence, extraction, recall's scaffolding tier, and
|
package/src/mind/pipeline.ts
CHANGED
|
@@ -23,6 +23,8 @@ import { coverMechanism } from "./mechanisms/cover.js";
|
|
|
23
23
|
import { castMechanism } from "./mechanisms/cast.js";
|
|
24
24
|
import { confluenceMechanism } from "./mechanisms/confluence.js";
|
|
25
25
|
import { extractionMechanism } from "./mechanisms/extraction.js";
|
|
26
|
+
import { referenceMechanism } from "./mechanisms/reference.js";
|
|
27
|
+
import { prefixMechanism } from "./mechanisms/prefix-completion.js";
|
|
26
28
|
import { recallMechanism } from "./mechanisms/recall.js";
|
|
27
29
|
|
|
28
30
|
// Re-exports: cover's pre-resolution helpers and the ALU adapter kept
|
|
@@ -60,13 +62,23 @@ async function collectComputed(
|
|
|
60
62
|
// floor pruning every mechanism is already subject to — not by asking
|
|
61
63
|
// "is this an extension?". Grade TIES keep the earlier candidate, so this
|
|
62
64
|
// order is also the tie-break priority: cover, cast, confluence, extraction,
|
|
63
|
-
// recall.
|
|
65
|
+
// reference, recall.
|
|
66
|
+
//
|
|
67
|
+
// REFERENCE sits after extraction and before recall because that is what its
|
|
68
|
+
// claim is worth: extraction READS a span out of the query (no synthesis),
|
|
69
|
+
// reference voices one through a learnt slot, and recall's tiers degrade
|
|
70
|
+
// toward echo and silence. It does not PRUNE recall — its floor is two
|
|
71
|
+
// projections, so recall's one-STEP floor still clears `worthRunning` — and it
|
|
72
|
+
// is not meant to: both run, share one resonance read
|
|
73
|
+
// (Precomputed.resonance), and the ladder decides.
|
|
64
74
|
export const defaultMechanisms: PipelineMechanism[] = [
|
|
65
75
|
coverMechanism,
|
|
66
76
|
castMechanism,
|
|
67
77
|
confluenceMechanism,
|
|
68
78
|
extractionMechanism,
|
|
79
|
+
referenceMechanism,
|
|
69
80
|
recallMechanism,
|
|
81
|
+
prefixMechanism,
|
|
70
82
|
];
|
|
71
83
|
|
|
72
84
|
// ── think — the main inference pipeline ─────────────────────────────────────
|
|
@@ -76,8 +88,10 @@ export type Provenance =
|
|
|
76
88
|
| "join"
|
|
77
89
|
| "cover"
|
|
78
90
|
| "extract"
|
|
91
|
+
| "reference"
|
|
79
92
|
| "recall"
|
|
80
|
-
| "recall-echo"
|
|
93
|
+
| "recall-echo"
|
|
94
|
+
| "prefix";
|
|
81
95
|
|
|
82
96
|
export interface Thought {
|
|
83
97
|
bytes: Uint8Array;
|
package/src/mind/traverse.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { cosine, Vec } from "../vec.js";
|
|
10
10
|
import type { AncestorReach, MindContext, SaturationStop } from "./types.js";
|
|
11
11
|
import { gistOf, read } from "./primitives.js";
|
|
12
|
-
import { leafIdRun } from "./canonical.js";
|
|
12
|
+
import { canonicalWindows, leafIdPrefix, leafIdRun } from "./canonical.js";
|
|
13
13
|
|
|
14
14
|
// ── Session structural memo ─────────────────────────────────────────────
|
|
15
15
|
//
|
|
@@ -836,3 +836,94 @@ export function allWindowsAreScaffolding(
|
|
|
836
836
|
}
|
|
837
837
|
return sawOne;
|
|
838
838
|
}
|
|
839
|
+
|
|
840
|
+
// ── THE PREFIX SUPPLY ───────────────────────────────────────────────────────
|
|
841
|
+
//
|
|
842
|
+
// A RETRIEVAL capability, not a grounding one: "which trained forms does this
|
|
843
|
+
// byte run OPEN?" It lived inside a recall tier, which is the wrong altitude
|
|
844
|
+
// — it reads the write side's own leaf-id window index and answers a question
|
|
845
|
+
// about the STORE, so any mechanism may ask it.
|
|
846
|
+
|
|
847
|
+
/** Trained forms the query may OPEN, proposed from the write side's own
|
|
848
|
+
* leaf-id window index — the supply of last resort for prefix completion.
|
|
849
|
+
*
|
|
850
|
+
* WHY A SECOND SUPPLY EXISTS. The ranked list prefix completion normally reads
|
|
851
|
+
* is a resonance list, and resonance cannot rank a proper prefix: measured on
|
|
852
|
+
* the trained store, cos(prefix, form) falls from 0.9629 at a one-byte
|
|
853
|
+
* truncation to 0.6206 at three bytes, against a reachThreshold of 0.8750.
|
|
854
|
+
* Three bytes of truncation put the answer out of reach on GEOMETRY, not on a
|
|
855
|
+
* bug, so no k and no re-ranking recovers it.
|
|
856
|
+
*
|
|
857
|
+
* WHY THIS ROUTE WORKS WHERE THE FOLD DOES NOT. A query's own fold is
|
|
858
|
+
* useless here: content addressing is not phrase-position-invariant, so a
|
|
859
|
+
* standalone prefix folds to a DIFFERENT node than the same bytes sitting
|
|
860
|
+
* inside a longer deposit, and neither the prefix's own node nor its
|
|
861
|
+
* ancestors lead to the deposit (measured: the 22-byte prefix of the
|
|
862
|
+
* photosynthesis form resolves, is shared by 6 contexts, and does not have
|
|
863
|
+
* the form among its ancestors). Leaf ids ARE position-invariant — they are
|
|
864
|
+
* content-addressed on single bytes — and `indexSubSpans` already interns a
|
|
865
|
+
* flat branch over every canonical WINDOW of a deposit's leaf-id stream, with
|
|
866
|
+
* containment edges to the chunks that window spans. A query that is a
|
|
867
|
+
* prefix therefore shares those window nodes exactly, and reaches the deposit
|
|
868
|
+
* by climbing containment then parents. Nothing is added to the write side;
|
|
869
|
+
* this reads an index training already built.
|
|
870
|
+
*
|
|
871
|
+
* BOUNDED (§2.8), AND WITH NO NEW THRESHOLD. The window whose containment is
|
|
872
|
+
* SMALLEST carries the most evidence, and one saturated at `hubBound` carries
|
|
873
|
+
* none — that is the same √N reading of "hub" the rest of the mind uses, not
|
|
874
|
+
* a tuned knob. The upward walk spends a budget of `hubBound` nodes and
|
|
875
|
+
* fans out by W, so a hub query enumerates nothing and the caller stays
|
|
876
|
+
* silent rather than guessing (§2.13). Measured on the trained store: the
|
|
877
|
+
* photosynthesis form at a one-byte truncation picks a window with 52
|
|
878
|
+
* containers, visits 446 nodes, and yields exactly ONE candidate that
|
|
879
|
+
* survives the caller's byte compare — the form itself.
|
|
880
|
+
*
|
|
881
|
+
* These are PROPOSALS only. Every candidate still faces the byte-exact
|
|
882
|
+
* prefix compare and all three guards below, so a wrong proposal costs one
|
|
883
|
+
* bounded read and can never be voiced (§2.3). */
|
|
884
|
+
export function formsOpenedBy(
|
|
885
|
+
ctx: MindContext,
|
|
886
|
+
query: Uint8Array,
|
|
887
|
+
): number[] {
|
|
888
|
+
const store = ctx.store;
|
|
889
|
+
const W = ctx.space.maxGroup;
|
|
890
|
+
const run = leafIdPrefix(ctx, query);
|
|
891
|
+
// The widest canonical window is the most discriminative one the write side
|
|
892
|
+
// ever interned; a query too short to spell one carries no window evidence.
|
|
893
|
+
const len = canonicalWindows(W)[1];
|
|
894
|
+
if (run.length < len) return [];
|
|
895
|
+
const bound = hubBound(ctx);
|
|
896
|
+
|
|
897
|
+
let best: number | null = null;
|
|
898
|
+
let bestN = 0;
|
|
899
|
+
for (let off = 0; off + len <= run.length; off++) {
|
|
900
|
+
const wid = store.findBranch(run.slice(off, off + len));
|
|
901
|
+
if (wid === null) continue;
|
|
902
|
+
const n = store.containersSlice(wid, 0, bound).length;
|
|
903
|
+
// Empty says the window spans no chunk; saturated says it is a hub, whose
|
|
904
|
+
// containment discriminates nothing. Neither is evidence.
|
|
905
|
+
if (n === 0 || n >= bound) continue;
|
|
906
|
+
if (best === null || n < bestN) {
|
|
907
|
+
best = wid;
|
|
908
|
+
bestN = n;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (best === null) return [];
|
|
912
|
+
|
|
913
|
+
let frontier = store.containersSlice(best, 0, bound);
|
|
914
|
+
const seen = new Set<number>(frontier);
|
|
915
|
+
let budget = bound;
|
|
916
|
+
while (frontier.length > 0 && budget > 0) {
|
|
917
|
+
const next: number[] = [];
|
|
918
|
+
for (const f of frontier) {
|
|
919
|
+
if (budget-- <= 0) break;
|
|
920
|
+
for (const p of store.parentsFirst(f, W)) {
|
|
921
|
+
if (seen.has(p)) continue;
|
|
922
|
+
seen.add(p);
|
|
923
|
+
next.push(p);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
frontier = next;
|
|
927
|
+
}
|
|
928
|
+
return [...seen];
|
|
929
|
+
}
|
package/src/store.ts
CHANGED
|
@@ -970,16 +970,25 @@ export abstract class AbstractStore implements Store {
|
|
|
970
970
|
/** Content (gist) index write buffer. */
|
|
971
971
|
protected _contentBuffer: Array<{ id: NodeId; vector: Float32Array }> = [];
|
|
972
972
|
/** Halo index write buffer — keyed by id so repeats within a batch coalesce. */
|
|
973
|
-
protected _haloBuffer
|
|
973
|
+
protected _haloBuffer: Map<NodeId, Float32Array> = new Map<
|
|
974
|
+
NodeId,
|
|
975
|
+
Float32Array
|
|
976
|
+
>();
|
|
974
977
|
/** Containment write buffer: child → new parents, merged on flush cadence. */
|
|
975
|
-
protected _containBuf
|
|
978
|
+
protected _containBuf: Map<NodeId, Set<NodeId>> = new Map<
|
|
979
|
+
NodeId,
|
|
980
|
+
Set<NodeId>
|
|
981
|
+
>();
|
|
976
982
|
|
|
977
983
|
/** Dedup-target candidates still in the write buffer (keyed by id). Only
|
|
978
984
|
* roots that have gained an edge/halo are targets; a fresh intermediate
|
|
979
985
|
* branch is never folded onto. */
|
|
980
|
-
protected _nearDedupBuf
|
|
986
|
+
protected _nearDedupBuf: Map<NodeId, Float32Array> = new Map<
|
|
987
|
+
NodeId,
|
|
988
|
+
Float32Array
|
|
989
|
+
>();
|
|
981
990
|
/** Ids currently in `_contentBuffer` (not yet flushed) — O(1) membership. */
|
|
982
|
-
protected _bufferedIds = new Set<NodeId>();
|
|
991
|
+
protected _bufferedIds: Set<NodeId> = new Set<NodeId>();
|
|
983
992
|
|
|
984
993
|
// ── Transparent-chain cache ────────────────────────────────────────────
|
|
985
994
|
|
|
@@ -171,18 +171,28 @@ test("3 — a near-tie between the winner and runner-up emits narrowDecision", a
|
|
|
171
171
|
["water is frigid so water is freezing", "freezing"],
|
|
172
172
|
]);
|
|
173
173
|
// The near-tie has to be REAL: two candidates whose accounted spans are the
|
|
174
|
-
// same, separated by a single move. `
|
|
175
|
-
// extraction and recall both explain the
|
|
176
|
-
//
|
|
174
|
+
// same, separated by a single move. `water is hard so water is ???` is that
|
|
175
|
+
// — extraction and recall both explain the same span (grades 25011 and
|
|
176
|
+
// 25010, margin 1).
|
|
177
177
|
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
|
|
178
|
+
// THIS FIXTURE HAS NOW BEEN REPLACED TWICE, BOTH TIMES FOR THE SAME REASON:
|
|
179
|
+
// a mechanism that genuinely explains the query started firing, and a
|
|
180
|
+
// decisive win is the opposite of what this test pins.
|
|
181
|
+
//
|
|
182
|
+
// * `steel is frigid so steel is ???` was a near-tie only while CAST could
|
|
183
|
+
// not fire on it — CAST's subject gate used to reject any point whose
|
|
184
|
+
// alignment continued PAST the seat, which that fixture's recurrence
|
|
185
|
+
// guarantees. With CAST firing it wins by 22008.
|
|
186
|
+
// * `steel is hard so steel is` was a near-tie only while prefix
|
|
187
|
+
// completion was a buried recall TIER. As a market mechanism it grounds
|
|
188
|
+
// that query for what it is — the literal opening of exactly one trained
|
|
189
|
+
// form — at grade 1 against 21010, and answers `steel is hard so steel
|
|
190
|
+
// is strong`. That is a better answer, not a regression.
|
|
191
|
+
//
|
|
192
|
+
// The lesson for whoever re-fixtures this next: pick a query no mechanism can
|
|
193
|
+
// explain OUTRIGHT. A trailing `???` is what keeps this one honest — it is
|
|
194
|
+
// not the prefix of anything trained.
|
|
195
|
+
const { steps } = await trace(m, "water is hard so water is ???");
|
|
186
196
|
const narrow = stepsNamed(steps, "narrowDecision");
|
|
187
197
|
assert.equal(narrow.length, 1, "expected exactly one narrowDecision step");
|
|
188
198
|
assert.ok(/margin \d+ grade-unit/.test(narrow[0].note), narrow[0].note);
|
|
@@ -36,7 +36,7 @@ import { test } from "node:test";
|
|
|
36
36
|
import assert from "node:assert/strict";
|
|
37
37
|
import { Mind } from "../dist/src/index.js";
|
|
38
38
|
import { SQliteStore } from "../dist/src/store-sqlite.js";
|
|
39
|
-
import { prefixCompletion } from "../dist/src/mind/prefix-completion.js";
|
|
39
|
+
import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
|
|
40
40
|
|
|
41
41
|
const enc = (s) => new TextEncoder().encode(s);
|
|
42
42
|
const dec = new TextDecoder();
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// 0.9629 at a one-byte truncation to 0.6206 at three bytes, against a
|
|
9
9
|
// reachThreshold of 0.8750. The mechanism's guards were therefore never
|
|
10
10
|
// reached — the trace read `candidates: 24, opened: 0` — and the query answered
|
|
11
|
-
// nothing. `
|
|
11
|
+
// nothing. `formsOpenedBy` is the second SUPPLY that closes it, reading the
|
|
12
12
|
// leaf-id WINDOW index `indexSubSpans` already writes at deposit time. No
|
|
13
13
|
// ingestion, storage or fold change is involved: this test would pass on a
|
|
14
14
|
// store trained before the supply existed.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// WHY THE ASSERTIONS ARE SHAPED THIS WAY. On a small fixture resonance may
|
|
17
17
|
// well return the form by luck, and then an end-to-end "does it answer?" test
|
|
18
18
|
// would pass with the supply deleted — pinning nothing. So the contract is
|
|
19
|
-
// asserted on `
|
|
19
|
+
// asserted on `formsOpenedBy` DIRECTLY, and the resonance list is asserted
|
|
20
20
|
// to lack the form, which is what makes the supply load-bearing rather than
|
|
21
21
|
// redundant.
|
|
22
22
|
//
|
|
@@ -27,10 +27,8 @@ import { test } from "node:test";
|
|
|
27
27
|
import assert from "node:assert/strict";
|
|
28
28
|
import { Mind } from "../dist/src/index.js";
|
|
29
29
|
import { SQliteStore } from "../dist/src/store-sqlite.js";
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
prefixCompletion,
|
|
33
|
-
} from "../dist/src/mind/prefix-completion.js";
|
|
30
|
+
import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
|
|
31
|
+
import { formsOpenedBy } from "../dist/src/mind/traverse.js";
|
|
34
32
|
import { gistOf, resolve } from "../dist/src/mind/primitives.js";
|
|
35
33
|
|
|
36
34
|
const enc = (s) => new TextEncoder().encode(s);
|
|
@@ -71,7 +69,7 @@ test("a proper prefix reaches its trained form through the window supply", async
|
|
|
71
69
|
// prefix is a LARGE-CORPUS property — cos falls to 0.6206 at a three-byte
|
|
72
70
|
// truncation against a 0.8750 bar, on a 15.7M-node store — and cannot be
|
|
73
71
|
// reproduced at this scale. That is why the contract below is asserted on
|
|
74
|
-
// `
|
|
72
|
+
// `formsOpenedBy` DIRECTLY: deleting or emptying the supply fails this
|
|
75
73
|
// test regardless of what resonance happens to return.
|
|
76
74
|
const ranked = (await m.store.resonate(gistOf(m, query), 64)).map((h) =>
|
|
77
75
|
h.id
|
|
@@ -84,7 +82,7 @@ test("a proper prefix reaches its trained form through the window supply", async
|
|
|
84
82
|
);
|
|
85
83
|
|
|
86
84
|
// THE CONTRACT — the write side's own window index proposes the form.
|
|
87
|
-
const proposed =
|
|
85
|
+
const proposed = formsOpenedBy(m, query);
|
|
88
86
|
assert.ok(
|
|
89
87
|
proposed.includes(formId),
|
|
90
88
|
`the window supply must propose the trained form the query opens ` +
|
|
@@ -105,7 +103,7 @@ test("a proper prefix reaches its trained form through the window supply", async
|
|
|
105
103
|
// supply that widened until it found something would be the real defect.
|
|
106
104
|
const hub = enc("The ");
|
|
107
105
|
assert.equal(
|
|
108
|
-
prefixCompletion(m, hub,
|
|
106
|
+
prefixCompletion(m, hub, formsOpenedBy(m, hub)),
|
|
109
107
|
null,
|
|
110
108
|
"a query carrying no discriminative window must stay silent",
|
|
111
109
|
);
|
|
@@ -31,7 +31,7 @@ import { test } from "node:test";
|
|
|
31
31
|
import assert from "node:assert/strict";
|
|
32
32
|
import { Mind } from "../dist/src/index.js";
|
|
33
33
|
import { SQliteStore } from "../dist/src/store-sqlite.js";
|
|
34
|
-
import { prefixCompletion } from "../dist/src/mind/prefix-completion.js";
|
|
34
|
+
import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
|
|
35
35
|
import { resolve } from "../dist/src/mind/primitives.js";
|
|
36
36
|
|
|
37
37
|
const enc = (s) => new TextEncoder().encode(s);
|