@hviana/sema 0.4.7 → 0.5.1
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/attention.d.ts +15 -10
- package/dist/src/mind/attention.js +15 -10
- 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 +52 -3
- package/dist/src/mind/mind.js +140 -12
- 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 +98 -71
- package/dist/src/mind/recognition.js +153 -26
- package/dist/src/mind/traverse.d.ts +32 -0
- package/dist/src/mind/traverse.js +52 -0
- package/dist/src/mind/types.d.ts +61 -18
- package/dist/src/mind/types.js +68 -19
- 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/attention.ts +15 -10
- 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 +166 -18
- 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 +105 -80
- package/src/mind/recognition.ts +151 -23
- package/src/mind/traverse.ts +52 -0
- package/src/mind/types.ts +104 -44
- 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/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 +1334 -0
|
@@ -12,7 +12,7 @@ import { read, resolve } from "../primitives.js";
|
|
|
12
12
|
import { guidedFirst, hubBound } from "../traverse.js";
|
|
13
13
|
import { conceptHop } from "../match.js";
|
|
14
14
|
import { bridge } from "../resonance.js";
|
|
15
|
-
import { liftAnswer, segRestatesQuery } from "../types.js";
|
|
15
|
+
import { liftAnswer, liftedScaffolding, segRestatesQuery } from "../types.js";
|
|
16
16
|
import { decodeText, unexplainedLabel } from "../rationale.js";
|
|
17
17
|
import { indexOf } from "../../bytes.js";
|
|
18
18
|
import { rItem, rNode, traceDerivation } from "../trace.js";
|
|
@@ -222,6 +222,11 @@ export const coverMechanism = {
|
|
|
222
222
|
moves: 0,
|
|
223
223
|
weight: solved.cost, // A*LD derivation's g-value IS the weight
|
|
224
224
|
unexplained: unexplainedLabel(query, accounted),
|
|
225
|
+
// How much of the composed answer is the asker's own unexplained words
|
|
226
|
+
// (the spans the liftAnswer trace above labels "scaffolding"). Cover is
|
|
227
|
+
// the mechanism that can carry them, because a PASS span still lands in
|
|
228
|
+
// the cover it returns.
|
|
229
|
+
scaffolding: liftedScaffolding(segs, query.length, query, W),
|
|
225
230
|
}];
|
|
226
231
|
},
|
|
227
232
|
};
|
|
@@ -92,6 +92,33 @@ export async function extractBySkill(ctx, query, pre) {
|
|
|
92
92
|
subQuantum++;
|
|
93
93
|
continue;
|
|
94
94
|
}
|
|
95
|
+
// AN UNANCHORED READ IS NOT AN EXTRACTION. This function's contract (see
|
|
96
|
+
// the doc above) is that `accounted` carries "the located frames AND any
|
|
97
|
+
// read span BOUNDED by located frames on both sides", while an open-ended
|
|
98
|
+
// read "remains a guess about where the span stops — it stays unaccounted".
|
|
99
|
+
// EMPTY accounted is the degenerate case of that: NO frame of the exemplar
|
|
100
|
+
// was located in the query at all, so nothing ties the bytes just read to
|
|
101
|
+
// this question — the skill applied its exemplar's geometry to a query it
|
|
102
|
+
// never matched.
|
|
103
|
+
//
|
|
104
|
+
// The live case (analyze_training.ts F, the battery's ONLY wrong non-silent
|
|
105
|
+
// answer): "Which city is France's seat of government?" answered "Which ci"
|
|
106
|
+
// — a fragment of the query itself — from the exemplar "What is dll", with
|
|
107
|
+
// accounted=[] and pieces=1. isSpanShaped is deliberately permissive (a
|
|
108
|
+
// sparse-subsequence check), so it accepts exemplars whose relation to the
|
|
109
|
+
// query is coincidental gap-matching; requiring at least one LOCATED frame
|
|
110
|
+
// is the structural evidence that permissiveness leaves out.
|
|
111
|
+
//
|
|
112
|
+
// Scoped to extraction ON PURPOSE. The same test at the pipeline's
|
|
113
|
+
// post-grounding density check was tried and REVERTED: `accounted` is passed
|
|
114
|
+
// empty BY CONVENTION on recall's own tiers (recall.ts's ground(…, [], …)),
|
|
115
|
+
// so a density veto there refused six legitimate reverse-recall groundings.
|
|
116
|
+
// Here the field is this mechanism's own output and carries its documented
|
|
117
|
+
// meaning, so the test is sound exactly where the convention does not reach.
|
|
118
|
+
if (built.accounted.length === 0) {
|
|
119
|
+
subQuantum++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
95
122
|
if (shapeMisses > 0 || subQuantum > 0) {
|
|
96
123
|
ctx.trace?.step("trySkillAnchors", [
|
|
97
124
|
rItem(query.subarray(0, 0), `skipped ${shapeMisses + subQuantum}`),
|
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
// index and grounds the nearest learned form. Four tiers, orderly degrading
|
|
5
5
|
// from exact self-match to honest echo.
|
|
6
6
|
import { cosine } from "../../vec.js";
|
|
7
|
-
import { conceptThreshold, consensusFloor, identityBar, reachThreshold, significanceBar, } from "../../geometry.js";
|
|
7
|
+
import { conceptThreshold, consensusFloor, dominates, identityBar, reachThreshold, significanceBar, } from "../../geometry.js";
|
|
8
8
|
import { gistOf, read, resolve } from "../primitives.js";
|
|
9
9
|
import { bytesEqual, indexOf } from "../../bytes.js";
|
|
10
|
-
import { corpusN, hubBound } from "../traverse.js";
|
|
10
|
+
import { allWindowsAreScaffolding, corpusN, hubBound } from "../traverse.js";
|
|
11
11
|
import { follow, project, reverseContext } from "../match.js";
|
|
12
12
|
import { CONCEPT, STEP } from "../graph-search.js";
|
|
13
13
|
import { unexplainedLabel } from "../rationale.js";
|
|
14
14
|
import { rItem, rNode } from "../trace.js";
|
|
15
15
|
import { substitutionBridge } from "../bridge.js";
|
|
16
|
+
import { frameFillerSubstitution } from "../frame-filler.js";
|
|
17
|
+
import { prefixCandidates, prefixCompletion } from "../prefix-completion.js";
|
|
16
18
|
/** Recall the answer by resonating the whole query against the content index. */
|
|
17
19
|
export async function recallByResonance(ctx, query, pre) {
|
|
18
20
|
const t = ctx.trace?.enter("recallByResonance", [
|
|
@@ -180,13 +182,92 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
180
182
|
Math.sqrt(otherLen / Math.max(1, query.length)));
|
|
181
183
|
// 2. Scaffolding-dominated.
|
|
182
184
|
if (top.score >= sig) {
|
|
183
|
-
const N = corpusN(ctx);
|
|
184
|
-
const minVote = consensusFloor(N);
|
|
185
185
|
// The committed points of attention ARE the shared climb's roots (same
|
|
186
186
|
// query, same k, same DF mode) — read them from Precomputed instead of
|
|
187
187
|
// re-climbing, so even a traced response pays for the climb once.
|
|
188
188
|
const forest = (await pre.attention()).roots;
|
|
189
|
-
|
|
189
|
+
// TRUST THE ANCHOR ON ITS BREADTH, NOT ON ITS ABSOLUTE VOTE.
|
|
190
|
+
//
|
|
191
|
+
// This gate read `forest[0].vote >= consensusFloor(N)`. Attention.breadth's
|
|
192
|
+
// own contract (types.ts) says why that is the wrong quantity: the IDF vote
|
|
193
|
+
// is "an absolute, ln(N)-scaled quantity that means 'strong' on a small
|
|
194
|
+
// store and 'weak' on a large one for the SAME degree of genuine
|
|
195
|
+
// consensus", while breadth is the SCALE-INVARIANT reading — "a point whose
|
|
196
|
+
// breadth clears `dominates` (> half the query's regions corroborate it) is
|
|
197
|
+
// real consensus; one that does not is a coincidental single-region echo".
|
|
198
|
+
// Attention.peak's contract makes the same point from the other side:
|
|
199
|
+
// comparing a POOLED SUM against a floor that prices ONE region's evidence
|
|
200
|
+
// is a dimensional error.
|
|
201
|
+
//
|
|
202
|
+
// Measured on the 15.7M-node store (N=325,615, so the old floor was 13.19).
|
|
203
|
+
// The absolute vote cannot separate right from wrong at this scale, and the
|
|
204
|
+
// proof is a probe that must stay SILENT:
|
|
205
|
+
//
|
|
206
|
+
// anchor picked by the climb vote breadth correct?
|
|
207
|
+
// "What is the chemical formula …" 10.60 0.556 RIGHT
|
|
208
|
+
// "Qual é a capital de França?" 8.19 0.667 RIGHT
|
|
209
|
+
// "Who wrote the play Romeo …?" 8.25 0.833 RIGHT
|
|
210
|
+
// "How do you say "good morning" …" 10.77 0.800 RIGHT
|
|
211
|
+
// "What is the commercial capital …" 12.69 0.333 Zamunda — MUST be silent
|
|
212
|
+
// "Menene sunan ginin mafi tsayi …" 12.79 0.214 wrong (Hausa)
|
|
213
|
+
// "Today is the 5th of March …" 10.36 0.000 wrong
|
|
214
|
+
//
|
|
215
|
+
// Zamunda's junk attractor outvotes every correct anchor, so no vote
|
|
216
|
+
// threshold admits the right ones without admitting fabrication — while
|
|
217
|
+
// breadth > ½ admits exactly the four correct anchors and nothing else.
|
|
218
|
+
// The old floor was simply never cleared on a corpus this large: the tier
|
|
219
|
+
// was dead code here, which is why 12 probes fell through to silence.
|
|
220
|
+
//
|
|
221
|
+
// `dominates(breadth, 1)` is the SAME half-dominance predicate used
|
|
222
|
+
// throughout, applied to the fraction — no new constant, and the bar the
|
|
223
|
+
// breadth contract names. COST: none; breadth is already computed and
|
|
224
|
+
// carried on every Attention the climb returns.
|
|
225
|
+
//
|
|
226
|
+
// The two readings are ALTERNATIVES, never a substitution. REPLACING the
|
|
227
|
+
// vote test with the breadth test was tried and broke 7 tests: on a small
|
|
228
|
+
// store ln(N) is low, so the vote bar is the one that legitimately fires
|
|
229
|
+
// there, and — as Attention.clusters' own contract warns — "breadth starves
|
|
230
|
+
// a genuine, evenly-split multi-topic query, since no root in a real N-way
|
|
231
|
+
// split can exceed half the vote" (the two 3.1 two-topic fusion tests are
|
|
232
|
+
// exactly that shape). Each reading is sufficient on its own evidence: a
|
|
233
|
+
// vote that clears the absolute floor is strong enough wherever the corpus
|
|
234
|
+
// is small enough for that to mean something, and a breadth past ½ is real
|
|
235
|
+
// consensus at any scale. ORing them keeps every admission the floor
|
|
236
|
+
// already made and adds only the scale-invariant ones it could never see.
|
|
237
|
+
//
|
|
238
|
+
// BREADTH ALSO NEEDS DISCRIMINATIVENESS. Breadth asks how much of the
|
|
239
|
+
// query corroborates the anchor, never whether the anchor SAYS anything: on
|
|
240
|
+
// a one-context store every region trivially corroborates the only anchor
|
|
241
|
+
// there is, so breadth is 1 while the anchor's IDF is 0 — and test/31 A2
|
|
242
|
+
// ("explain quantum chromodynamics" against a lone cat fact) answered the
|
|
243
|
+
// cat, which is fabrication. A region's IDF contribution for an anchor
|
|
244
|
+
// reached through c of N contexts is ln(N/c), so requiring it to exceed
|
|
245
|
+
// ln 2 is requiring c·2 < N — the SAME half-dominance reading used
|
|
246
|
+
// everywhere, expressed in the IDF's own units rather than as a new bar.
|
|
247
|
+
// `peak` is that per-region contribution, and reading it here is what
|
|
248
|
+
// Attention.peak's contract asks of a consumer gating on this evidence.
|
|
249
|
+
//
|
|
250
|
+
// AND THE QUERY MUST SAY SOMETHING. Both readings above price the
|
|
251
|
+
// ANCHOR's evidence; neither asks whether the QUERY discriminates
|
|
252
|
+
// anything. A query that is entirely corpus-global scaffolding gives the
|
|
253
|
+
// corpus nothing to be held to, and this tier — which exists to serve
|
|
254
|
+
// scaffolding-DOMINATED queries — is exactly where that runs out.
|
|
255
|
+
// Measured on the trained store: "What is the capital " answered "Colombo
|
|
256
|
+
// is the commercial capital of Sri Lanka…" on breadth 0.667 / clusters 1,
|
|
257
|
+
// and every window it spells is a hub ("What":572). See
|
|
258
|
+
// allWindowsAreScaffolding for the full separation, including the probes
|
|
259
|
+
// this tier serves CORRECTLY, which all retain a discriminating window
|
|
260
|
+
// ("what is the capital of france" → "f fr":248).
|
|
261
|
+
//
|
|
262
|
+
// DISPERSION WAS TRIED HERE FIRST AND FALSIFIED — do not retry it: the
|
|
263
|
+
// fabrication and the no-punctuation robustness probe have the IDENTICAL
|
|
264
|
+
// profile (breadth 0.667, clusters 1), so requiring clusters >= 2 silenced
|
|
265
|
+
// "what is the capital of france" too and cost the battery a probe.
|
|
266
|
+
const minVote = consensusFloor(corpusN(ctx));
|
|
267
|
+
if (forest.length > 0 &&
|
|
268
|
+
!allWindowsAreScaffolding(ctx, query) &&
|
|
269
|
+
(forest[0].vote >= minVote ||
|
|
270
|
+
(dominates(forest[0].breadth, 1) && forest[0].peak > Math.LN2))) {
|
|
190
271
|
const g = await project(ctx, forest[0].anchor, queryGist);
|
|
191
272
|
// The anchor cleared the consensus floor, but the floor prices the
|
|
192
273
|
// ANCHOR's evidence, not the projection's: a junk attractor can clear
|
|
@@ -212,6 +293,42 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
212
293
|
}
|
|
213
294
|
}
|
|
214
295
|
// 3b. Corroborated-substitution bridge — refusal-path only (bridge.ts).
|
|
296
|
+
// MEMOISED ACROSS EVERY REMAINING TIER, and that is load-bearing rather than
|
|
297
|
+
// tidy: the bridge, prefix completion and the frame filler all read the SAME
|
|
298
|
+
// candidate list, so the exhaustive branch runs at most once per response.
|
|
299
|
+
// Without the memo each tier re-issues it — measured at 490 ms median against
|
|
300
|
+
// 13 ms non-exhaustive (36x).
|
|
301
|
+
const wideIdsOnce = async () => {
|
|
302
|
+
// When the top resonance hit is below the concept threshold, the query
|
|
303
|
+
// gist has no concept-level match to any stored form — an exhaustive √N
|
|
304
|
+
// ANN would only score more vectors below the bar (profiled at 38K–40K
|
|
305
|
+
// annVectorReads per refusing query on a 325K-context store). The
|
|
306
|
+
// bridge's structural channels (junction walks, anchor climbs) are the
|
|
307
|
+
// correct proposal source for a query whose gist has no clean match;
|
|
308
|
+
// the ANN cannot propose what the gist cannot rank.
|
|
309
|
+
// The condition above is the SCORE of the top hit, not the size of the
|
|
310
|
+
// corpus. It used to be spelled `corpusN(ctx) <= (k · W)³`, which asks
|
|
311
|
+
// a different question and answers it wrongly at exactly the scale the
|
|
312
|
+
// note was written from: on the trained store N = 325,608 with k = 24
|
|
313
|
+
// and W = 4 puts the cube at 884,736, so that store took the exhaustive
|
|
314
|
+
// branch — the very branch measured here as 38K–40K annVectorReads.
|
|
315
|
+
// Measured cost of the mismatch: substitutionBridge 8,544ms of a
|
|
316
|
+
// 19,548ms think (44%), against 1,248ms and 14,218ms without it, with
|
|
317
|
+
// every answer in the battery byte-identical and the suite unchanged
|
|
318
|
+
// at 445/445. Corpus size was never the discriminator; whether the
|
|
319
|
+
// gist ranks ANYTHING at concept level is.
|
|
320
|
+
//
|
|
321
|
+
// Reading it as the note states also removes a duplicated (k · W)³ —
|
|
322
|
+
// the same cube gates crossRegionVotes' walk budget, where it likewise
|
|
323
|
+
// never engages at real scale (see attention.ts).
|
|
324
|
+
if (whole.length > 0 && whole[0].score >= conceptThreshold(ctx.store.D)) {
|
|
325
|
+
const exhaustive = await ctx.store.resonate(queryGist, hubBound(ctx), true);
|
|
326
|
+
return exhaustive.map((h) => h.id);
|
|
327
|
+
}
|
|
328
|
+
return whole.map((h) => h.id);
|
|
329
|
+
};
|
|
330
|
+
let wide = null;
|
|
331
|
+
const wideIds = () => (wide ??= wideIdsOnce());
|
|
215
332
|
// Every gist-based tier has failed; before refusing, align the query
|
|
216
333
|
// byte-for-byte against the trained contexts its own stored windows
|
|
217
334
|
// anchor, accepting mismatches only as corpus-attested, concept-bar
|
|
@@ -232,35 +349,6 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
232
349
|
// exact co-occurrence and bounded anchor ascent are the bridge's structural
|
|
233
350
|
// proposal channels, while an exhaustive ANN call made every honest
|
|
234
351
|
// refusal cost hundreds of milliseconds regardless of k.
|
|
235
|
-
const wideIds = async () => {
|
|
236
|
-
// When the top resonance hit is below the concept threshold, the query
|
|
237
|
-
// gist has no concept-level match to any stored form — an exhaustive √N
|
|
238
|
-
// ANN would only score more vectors below the bar (profiled at 38K–40K
|
|
239
|
-
// annVectorReads per refusing query on a 325K-context store). The
|
|
240
|
-
// bridge's structural channels (junction walks, anchor climbs) are the
|
|
241
|
-
// correct proposal source for a query whose gist has no clean match;
|
|
242
|
-
// the ANN cannot propose what the gist cannot rank.
|
|
243
|
-
// The condition above is the SCORE of the top hit, not the size of the
|
|
244
|
-
// corpus. It used to be spelled `corpusN(ctx) <= (k · W)³`, which asks
|
|
245
|
-
// a different question and answers it wrongly at exactly the scale the
|
|
246
|
-
// note was written from: on the trained store N = 325,608 with k = 24
|
|
247
|
-
// and W = 4 puts the cube at 884,736, so that store took the exhaustive
|
|
248
|
-
// branch — the very branch measured here as 38K–40K annVectorReads.
|
|
249
|
-
// Measured cost of the mismatch: substitutionBridge 8,544ms of a
|
|
250
|
-
// 19,548ms think (44%), against 1,248ms and 14,218ms without it, with
|
|
251
|
-
// every answer in the battery byte-identical and the suite unchanged
|
|
252
|
-
// at 445/445. Corpus size was never the discriminator; whether the
|
|
253
|
-
// gist ranks ANYTHING at concept level is.
|
|
254
|
-
//
|
|
255
|
-
// Reading it as the note states also removes a duplicated (k · W)³ —
|
|
256
|
-
// the same cube gates crossRegionVotes' walk budget, where it likewise
|
|
257
|
-
// never engages at real scale (see attention.ts).
|
|
258
|
-
if (whole.length > 0 && whole[0].score >= conceptThreshold(ctx.store.D)) {
|
|
259
|
-
const exhaustive = await ctx.store.resonate(queryGist, hubBound(ctx), true);
|
|
260
|
-
return exhaustive.map((h) => h.id);
|
|
261
|
-
}
|
|
262
|
-
return whole.map((h) => h.id);
|
|
263
|
-
};
|
|
264
352
|
const bridged = await substitutionBridge(ctx, query, wideIds);
|
|
265
353
|
if (bridged !== null) {
|
|
266
354
|
const g = await project(ctx, bridged.id, queryGist);
|
|
@@ -274,7 +362,32 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
274
362
|
const cBytes = ctx.store.bytes(bridged.id);
|
|
275
363
|
const manufactured = g !== null &&
|
|
276
364
|
bridged.subs.some((s) => indexOf(cBytes.subarray(s.cs, s.ce), g, 0) >= 0);
|
|
365
|
+
// THE PREFIX TRAP IS NOT THIS TIER'S TO SPRING. With no substitutions
|
|
366
|
+
// the claim is "a trained context IS this query, up to filler". When
|
|
367
|
+
// the query is a STRICT BYTE PREFIX of that context, the claim is false
|
|
368
|
+
// in the one way that matters: the candidate's extra tail is precisely
|
|
369
|
+
// the DISCRIMINATING part, and dismissing it as filler asserts a
|
|
370
|
+
// specification the asker never made. Measured on a 4,300-fact fixture
|
|
371
|
+
// of "what is the value of <i>?": the query "what is the value of"
|
|
372
|
+
// bridged with subs [] to "what is the value of 0?" and answered "the
|
|
373
|
+
// value of 0 is 0" — one arbitrary pick from 4,300 equally-matching
|
|
374
|
+
// contexts, every one of which fits the query exactly as well.
|
|
375
|
+
//
|
|
376
|
+
// The engine ALREADY has the right machinery for this shape:
|
|
377
|
+
// prefixCompletion runs a few lines below and carries the three guards
|
|
378
|
+
// this tier lacks — unreadable-continuation veto, sub-quantum
|
|
379
|
+
// continuation, and UNIQUENESS (distinct continuations ⇒ refuse), which
|
|
380
|
+
// is exactly what 4,300 competing values must trip. So this is not a
|
|
381
|
+
// new rule and not a new threshold: it is deferring a prefix decision to
|
|
382
|
+
// the tier that owns it (§2.5, one factored machinery). Byte-strict on
|
|
383
|
+
// purpose — a candidate differing by case or punctuation ("what is the
|
|
384
|
+
// capital of france" → "What is the capital of France?") is NOT a byte
|
|
385
|
+
// prefix, keeps grounding here, and is unaffected.
|
|
386
|
+
const strictPrefix = g !== null &&
|
|
387
|
+
cBytes.length > query.length &&
|
|
388
|
+
indexOf(cBytes, query, 0) === 0;
|
|
277
389
|
if (g !== null && g.length > 0 && !restates(g) && !manufactured &&
|
|
390
|
+
!(bridged.subs.length === 0 && strictPrefix) &&
|
|
278
391
|
!(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
279
392
|
return ground(g, bridged.subs.length === 0
|
|
280
393
|
? `identity bridge — a trained context IS this query, up to ` +
|
|
@@ -326,6 +439,73 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
326
439
|
bridged.subs.length === 0);
|
|
327
440
|
}
|
|
328
441
|
}
|
|
442
|
+
// 3b′. PREFIX COMPLETION — refusal-path only (prefix-completion.ts).
|
|
443
|
+
// Inside the bridge's block, and deliberately: it consumes `wideIds`, the
|
|
444
|
+
// list the bridge has already fetched, so it costs a bounded byte compare
|
|
445
|
+
// per candidate and not one resonance. The claim it makes is the
|
|
446
|
+
// strongest in the ladder — every query byte is a LITERAL match from
|
|
447
|
+
// offset zero of a trained form — so it needs no projection and no reach
|
|
448
|
+
// gate. It runs after the bridge only because the bridge answers the
|
|
449
|
+
// richer relation when it can; a prefix match that the bridge also
|
|
450
|
+
// explains is the same trained form either way.
|
|
451
|
+
{
|
|
452
|
+
// The resonance list first; only when it supplies nothing does the
|
|
453
|
+
// write side's leaf-id window index propose (prefixCandidates). That
|
|
454
|
+
// ordering is the whole cost story: a query the ranked list can already
|
|
455
|
+
// explain pays not one extra read, and the fallback's bounded walk is
|
|
456
|
+
// spent only where the alternative is an empty answer. It is a second
|
|
457
|
+
// SUPPLY, not a second mechanism — the same three guards decide.
|
|
458
|
+
const completed = prefixCompletion(ctx, query, await wideIds()) ??
|
|
459
|
+
prefixCompletion(ctx, query, prefixCandidates(ctx, query));
|
|
460
|
+
if (completed !== null) {
|
|
461
|
+
return ground(completed.form, "prefix completion — the query IS the opening of exactly one " +
|
|
462
|
+
"trained form, which this grounds whole",
|
|
463
|
+
// Every query byte is literally matched against the form. The
|
|
464
|
+
// completion is the form's own continuation, not a substitution, so
|
|
465
|
+
// there is nothing to be humble about in the accounting — the same
|
|
466
|
+
// reading the IDENTITY bridge above takes.
|
|
467
|
+
whole_, STEP, false,
|
|
468
|
+
// NOT complete: the query is a proper PREFIX, so the form may carry
|
|
469
|
+
// more past the remainder this tier voiced.
|
|
470
|
+
false);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// 3c. FRAME-FILLER SUBSTITUTION — refusal-path only (frame-filler.ts).
|
|
475
|
+
// The bridge has failed, and for the shape this tier answers it MUST fail:
|
|
476
|
+
// a definite description standing where a proper noun stands is not a
|
|
477
|
+
// similarity relation the bridge can price (raw balance refuses
|
|
478
|
+
// `dominates(6, 37)`, and correctly — that is the France/Spain trap). This
|
|
479
|
+
// tier makes a different claim: not that the two spans resemble each other,
|
|
480
|
+
// but that the store ALREADY HOLDS this query with the filler in the
|
|
481
|
+
// description's place, byte-exactly. A key the store does not hold is
|
|
482
|
+
// discarded, so the answer is always a trained continuation.
|
|
483
|
+
{
|
|
484
|
+
// THE COHORT NEEDS EVIDENCE, AND THE REFUSAL PATH HAS ALREADY BOUGHT IT.
|
|
485
|
+
// This tier reads constituency from what a cohort of exemplars does NOT
|
|
486
|
+
// share, so its resolution is bounded by how many instances of the frame it
|
|
487
|
+
// can see. The top-k resonance hits are too few — on the two-hop probe the
|
|
488
|
+
// exemplars holding the query's discriminative content number TWO, and two
|
|
489
|
+
// structures agree on so little that a whole clause reads as content. The
|
|
490
|
+
// exhaustive list the bridge fetched is the same evidence at ~570 wide, and
|
|
491
|
+
// it is already paid for (memoised above, so this costs no ANN call).
|
|
492
|
+
const filled = frameFillerSubstitution(ctx, query, await wideIds());
|
|
493
|
+
if (filled !== null) {
|
|
494
|
+
const g = await project(ctx, filled.id, queryGist);
|
|
495
|
+
// The same restated-fragment and manufactured-answer guards every tier
|
|
496
|
+
// above applies: a projection contained in the FILLER is the
|
|
497
|
+
// substitution restated as if it were knowledge, not knowledge.
|
|
498
|
+
if (g !== null && g.length > 0 && !restates(g) &&
|
|
499
|
+
indexOf(filled.filler, g, 0) < 0 &&
|
|
500
|
+
!(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
501
|
+
return ground(g, "frame-filler substitution — a trained form IS this query with a " +
|
|
502
|
+
"corroborated filler in the described span's place",
|
|
503
|
+
// The frame is literally matched against the resolved form and the
|
|
504
|
+
// described span is explained by the substitution — the same
|
|
505
|
+
// matched-plus-substituted accounting the bridge reports.
|
|
506
|
+
[[0, query.length]], CONCEPT + STEP);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
329
509
|
}
|
|
330
510
|
// The refusal/echo decision. The echo returns a stored form's bytes AS
|
|
331
511
|
// the answer — a near-identity claim about the query — and identity-grade
|
package/dist/src/mind/mind.d.ts
CHANGED
|
@@ -181,8 +181,9 @@ export declare class Mind implements MindContext {
|
|
|
181
181
|
* serves BOTH entry points: `respond` takes fresh per-response memos,
|
|
182
182
|
* `respondTurn` passes its conversation, whose memos persist across turns
|
|
183
183
|
* (content-keyed, so the previous turn's results are found by this turn's
|
|
184
|
-
* sub-span calls) and whose `resolvedSubtrees`
|
|
185
|
-
*
|
|
184
|
+
* sub-span calls) and whose `resolvedSubtrees` spares foldTree the store
|
|
185
|
+
* probes for every prefix subtree — and, for walks that pass no visitor,
|
|
186
|
+
* the descent as well. respondTurn used to inline its own copy of this
|
|
186
187
|
* and of {@link endResponse}; the two drifted (a memo added to one was
|
|
187
188
|
* silently absent from the other), so there is exactly one pair now. */
|
|
188
189
|
private beginResponse;
|
|
@@ -219,6 +220,20 @@ export declare class Mind implements MindContext {
|
|
|
219
220
|
* they do with the answer afterwards. It must be called between
|
|
220
221
|
* {@link beginResponse} and {@link endResponse}. */
|
|
221
222
|
private _groundAndVoice;
|
|
223
|
+
/** Answer ONE self-contained input.
|
|
224
|
+
*
|
|
225
|
+
* A MULTI-TURN context is not that, and this is the wrong entry point for
|
|
226
|
+
* it. `respond` folds the bytes it is handed with no boundary set, because
|
|
227
|
+
* nothing in a flat byte string says where one turn ended — only the caller
|
|
228
|
+
* who assembled it knows, which is the whole reason `boundaries` is a
|
|
229
|
+
* parameter of {@link perceiveImpl} and never inferred from content. A
|
|
230
|
+
* conversation deposited through {@link ingest} folds its contexts over
|
|
231
|
+
* those turn boundaries, so a hand-concatenated transcript passed here
|
|
232
|
+
* folds differently from the way it was learnt and reaches the trained
|
|
233
|
+
* context node only by luck (measured on a 7-turn conversation: 5/7 here
|
|
234
|
+
* against 7/7 through {@link respondTurn}, same bytes). Use
|
|
235
|
+
* {@link beginConversation} + {@link respondTurn}, or {@link addTurn} to
|
|
236
|
+
* replay turns the Mind should hear but not answer. */
|
|
222
237
|
respond(input: Input, inspectRationale?: InspectRationale): Promise<Response>;
|
|
223
238
|
/** Text view of {@link respond}. NUL bytes (0x00) are stripped before
|
|
224
239
|
* decoding — they are structural padding in text answers. LOSSY for a
|
|
@@ -252,7 +267,41 @@ export declare class Mind implements MindContext {
|
|
|
252
267
|
* This is the primitive for turns the Mind should hear but not answer:
|
|
253
268
|
* replaying a transcript, feeding the OTHER speaker's line in a
|
|
254
269
|
* prediction harness, or restoring context piecewise. {@link
|
|
255
|
-
* respondTurn} = addTurn + think + its own reply appended the same way.
|
|
270
|
+
* respondTurn} = addTurn + think + its own reply appended the same way.
|
|
271
|
+
*
|
|
272
|
+
* ── ON SEPARATORS: THERE IS NO SEPARATOR QUESTION ────────────────────
|
|
273
|
+
*
|
|
274
|
+
* "Never a separator" above says what this method DOES — it appends the
|
|
275
|
+
* bytes you give it and records an OFFSET — not that separator bytes are
|
|
276
|
+
* forbidden, unsupported, or something the engine must be taught about.
|
|
277
|
+
* Sema is agnostic to them, and reviewers keep mistaking that agnosticism
|
|
278
|
+
* for a constraint. To be explicit, because the mistake is easy:
|
|
279
|
+
*
|
|
280
|
+
* 1. A turn boundary is an OFFSET, held here, in `boundaries`. It is
|
|
281
|
+
* never a character the geometry scans for. Nothing downstream asks
|
|
282
|
+
* "what byte separates two turns?" because nothing downstream finds
|
|
283
|
+
* boundaries by looking at content at all.
|
|
284
|
+
* 2. A separator in a CORPUS is ordinary content. If a trainer joins
|
|
285
|
+
* turns with "\n" (example/train_base.ts does), those newlines are
|
|
286
|
+
* simply bytes inside the stream, folded like every other byte. They
|
|
287
|
+
* are a property of that corpus, not of this API and not of the fold.
|
|
288
|
+
* 3. This API can therefore reproduce ANY corpus exactly, with no
|
|
289
|
+
* convention to agree on: replaying a "\n"-joined corpus means passing
|
|
290
|
+
* `"\n" + turnText` as the turn. The separator rides along IN the
|
|
291
|
+
* turn bytes, where it belongs. There is nothing to configure and no
|
|
292
|
+
* mode to select.
|
|
293
|
+
* 4. Inference is not exact-match anyway. Recognition works over
|
|
294
|
+
* sub-spans, canonical equivalence and resonance, so a query that
|
|
295
|
+
* differs from the trained bytes by punctuation or whitespace still
|
|
296
|
+
* reaches the trained forms; it degrades, it does not fail closed.
|
|
297
|
+
*
|
|
298
|
+
* What follows from 1–4: differing separator bytes between a corpus and a
|
|
299
|
+
* query is an ordinary CONTENT difference — the same kind as any other
|
|
300
|
+
* wording difference — and it is measured the same way. It is NOT an
|
|
301
|
+
* incompatibility between the trainer and this API, and it does NOT
|
|
302
|
+
* require choosing a project-wide separator convention. A review that
|
|
303
|
+
* concludes otherwise (this one did, before being corrected) has mistaken
|
|
304
|
+
* its own harness feeding untrained bytes for an architectural defect. */
|
|
256
305
|
addTurn(conv: Conversation, turn: Input): ConversationState;
|
|
257
306
|
/** Grow a conversation's accumulated context by one turn's bytes — raw
|
|
258
307
|
* append plus a boundary offset, pyramid advanced by O(turn), the grown
|