@hviana/sema 0.5.3 → 0.5.5
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 +6 -6
- package/HOW_IT_WORKS.md +16 -0
- package/dist/src/mind/match.d.ts +53 -0
- package/dist/src/mind/match.js +81 -1
- package/dist/src/mind/mechanisms/recall.js +15 -3
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/mind/match.ts +81 -0
- package/src/mind/mechanisms/recall.ts +29 -3
- package/test/76-reference-binding.test.mjs +72 -0
package/AGENTS.md
CHANGED
|
@@ -179,12 +179,12 @@ matchers (`locate`, `alignRuns`, `alignGraded`, `alignAround`/`frameSlots`,
|
|
|
179
179
|
`bestHaloMate`, `haloSiblings`, `analogyStrength` and its structural tier
|
|
180
180
|
`sharedFrameStrength`, `spanHalo`, `spanSynonymStrength`), projections
|
|
181
181
|
(`follow`, `reverseContext`, `project`, `conceptHop`), the span-shape family
|
|
182
|
-
(`skillExemplar`, `isSpanShaped`, `containsSpan`), and the
|
|
183
|
-
|
|
184
|
-
`carriesFillers`). `mind/traverse.ts` owns the graph
|
|
185
|
-
`reachOf`, `chooseNext`/`chooseAmong`, `guidedFirst`,
|
|
186
|
-
`allWindowsAreScaffolding`, `formsOpenedBy`) and the corpus
|
|
187
|
-
`hubBound`, `hubCap`, `atomReach`).
|
|
182
|
+
(`skillExemplar`, `isSpanShaped`, `containsSpan`), and the STRUCTURAL gates that
|
|
183
|
+
are byte predicates rather than derived thresholds (`isSpanShaped`,
|
|
184
|
+
`carriesFillers`, `voicesDisplacedFiller`). `mind/traverse.ts` owns the graph
|
|
185
|
+
readings (`edgeAncestors`, `reachOf`, `chooseNext`/`chooseAmong`, `guidedFirst`,
|
|
186
|
+
`leadsSomewhere`, `allWindowsAreScaffolding`, `formsOpenedBy`) and the corpus
|
|
187
|
+
scale (`corpusN`, `hubBound`, `hubCap`, `atomReach`).
|
|
188
188
|
|
|
189
189
|
_Follow it:_ before writing a new generalising mechanism, express it as a
|
|
190
190
|
(matcher, direction, gate) triple. If those already exist, the mechanism is a
|
package/HOW_IT_WORKS.md
CHANGED
|
@@ -4314,6 +4314,22 @@ The tier accounts for exactly the query span whose evidence carried the winning
|
|
|
4314
4314
|
point of attention (§17.6's `start`–`end`), not the whole query — a consensus
|
|
4315
4315
|
vote for "ice" among scaffolding does not explain the word "steel". One CONCEPT.
|
|
4316
4316
|
|
|
4317
|
+
One further refusal is specific to grounding _through an anchor_. This tier
|
|
4318
|
+
voices the anchor's continuation, so when the query is the same structure as the
|
|
4319
|
+
anchor with one position filled differently, that continuation speaks the
|
|
4320
|
+
**anchor's** occupant of the position — fluent, specific, and about the wrong
|
|
4321
|
+
thing (`How do I compile main.c?` answered `Run gcc hello.c`). A displaced slot
|
|
4322
|
+
alone does not license the refusal, because it cannot separate a different
|
|
4323
|
+
_thing_ from a different _word_: `symbol` ← `formula` has exactly the shape
|
|
4324
|
+
`main` ← `hello` does, and refusing it silences a correct answer phrased in the
|
|
4325
|
+
corpus's own words. The discriminator is whether the projection still shares
|
|
4326
|
+
perceivable content with the query outside that position — one river window is
|
|
4327
|
+
enough. `The chemical formula for water is H2O.` shares `for water`;
|
|
4328
|
+
`Run gcc hello.c` shares only `.c`, two bytes, below the scale at which overlap
|
|
4329
|
+
stops being chance. The gate refuses only; putting the asker's own occupant in
|
|
4330
|
+
its place is a stronger claim needing the corpus's carriage evidence, which is
|
|
4331
|
+
§20.5's business.
|
|
4332
|
+
|
|
4317
4333
|
### 21.4 Tier 3 — the nearest grounded hit, at the query-relative fraction
|
|
4318
4334
|
|
|
4319
4335
|
Walk the hits nearest-first and ground the first whose grounding explains enough
|
package/dist/src/mind/match.d.ts
CHANGED
|
@@ -173,6 +173,59 @@ export interface FrameInstance {
|
|
|
173
173
|
*
|
|
174
174
|
* Null only for a degenerate pairing (either side empty). */
|
|
175
175
|
export declare function frameSlots(ctx: MindContext, query: Uint8Array, cand: Uint8Array, id: number): FrameInstance | null;
|
|
176
|
+
/** THE DISPLACED-FILLER GATE: does `projection` speak the ANCHOR's occupant of
|
|
177
|
+
* a position the query fills differently?
|
|
178
|
+
*
|
|
179
|
+
* A mechanism grounding through an anchor voices that anchor's continuation.
|
|
180
|
+
* When the query is the same structure as the anchor with one position filled
|
|
181
|
+
* differently — a different filename, a different word — the anchor's
|
|
182
|
+
* continuation is ABOUT THE ANCHOR'S occupant, and voicing it answers a
|
|
183
|
+
* question the asker did not ask. It is worse than silence, because it is
|
|
184
|
+
* fluent and specific and wrong:
|
|
185
|
+
*
|
|
186
|
+
* trained `How do I compile hello.c?` -> `Run gcc hello.c`
|
|
187
|
+
* asked `How do I compile main.c?`
|
|
188
|
+
* voiced `Run gcc hello.c` <- the corpus's file, not the asker's
|
|
189
|
+
*
|
|
190
|
+
* The same shape on the trained 15.7M-node store: `How do you say 'flurbish'
|
|
191
|
+
* in French?` answers "the way to say hello is \"Bonjour\"".
|
|
192
|
+
*
|
|
193
|
+
* THIS IS NOT THE RESTATED-FRAGMENT GUARD. That one asks whether the
|
|
194
|
+
* projection is a piece of the QUERY; this asks whether it is a piece of the
|
|
195
|
+
* ANCHOR that the query displaced. Neither implies the other, and the
|
|
196
|
+
* observed failures pass the restatement guard cleanly.
|
|
197
|
+
*
|
|
198
|
+
* Three conditions, all byte-exact and all necessary:
|
|
199
|
+
*
|
|
200
|
+
* 1. the query and the anchor must be ONE STRUCTURE — what they share has to
|
|
201
|
+
* dominate the query, or the query is not a variant of the anchor at all
|
|
202
|
+
* and the anchor's occupant of anything is beside the point;
|
|
203
|
+
* 2. both sides of the position must reach one river window — below it byte
|
|
204
|
+
* overlap is chance, not evidence (the floor identityBar and the bridge's
|
|
205
|
+
* attestedQ both draw);
|
|
206
|
+
* 3. the projection must voice the anchor's filler and NOT the query's
|
|
207
|
+
* referent. Voicing both is a projection that carried the asker's own
|
|
208
|
+
* occupant through, which is exactly what a licensed reference does and
|
|
209
|
+
* must stay allowed;
|
|
210
|
+
* 4. and the projection must share NO perceivable content with the query
|
|
211
|
+
* outside that position — no run of one river window.
|
|
212
|
+
*
|
|
213
|
+
* GATE 4 IS WHAT SEPARATES A DIFFERENT THING FROM A DIFFERENT WORD, and
|
|
214
|
+
* without it this refuses correct answers. A displaced slot alone cannot
|
|
215
|
+
* tell them apart: `symbol` <- `formula` and `main` <- `hello` are the same
|
|
216
|
+
* shape to the matcher — one substitution slot, frame dominating. Measured
|
|
217
|
+
* on the trained store, gates 1-3 alone silenced
|
|
218
|
+
*
|
|
219
|
+
* Q `What is the chemical symbol for water?`
|
|
220
|
+
* A `The chemical formula for water is H2O.`
|
|
221
|
+
*
|
|
222
|
+
* which is right, and merely phrased in the corpus's own words. The answer
|
|
223
|
+
* shares `the chemical ` and ` for water` with the question, so it is plainly
|
|
224
|
+
* about what was asked. `Run gcc hello.c` against `How do I compile main.c?`
|
|
225
|
+
* shares nothing but `.c` — two bytes, below the window where overlap stops
|
|
226
|
+
* being chance — so it is not about what was asked at all. No new constant:
|
|
227
|
+
* W is the same floor identityBar, attestedQ and the site test already draw. */
|
|
228
|
+
export declare function voicesDisplacedFiller(ctx: MindContext, query: Uint8Array, anchor: Uint8Array, projection: Uint8Array): boolean;
|
|
176
229
|
/** Whether every member is byte-distinct from the others. */
|
|
177
230
|
export declare function distinct(items: readonly Uint8Array[]): boolean;
|
|
178
231
|
/** Substitute every `needle -> repl` pair SIMULTANEOUSLY: one left-to-right
|
package/dist/src/mind/match.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
// thresholds — isSpanShaped and carriesFillers — live here beside the matchers
|
|
31
31
|
// they gate.
|
|
32
32
|
import { addInto, cosine, dot, normalize, zeros } from "../vec.js";
|
|
33
|
-
import { conceptThreshold, identityBar, significanceBar, } from "../geometry.js";
|
|
33
|
+
import { conceptThreshold, dominates, identityBar, significanceBar, } from "../geometry.js";
|
|
34
34
|
import { bytesEqual, indexOf } from "../bytes.js";
|
|
35
35
|
import { chainReach, leafIdRun } from "./canonical.js";
|
|
36
36
|
import { foldTree, gistOf, perceive, read, resolve } from "./primitives.js";
|
|
@@ -440,6 +440,86 @@ export function frameSlots(ctx, query, cand, id) {
|
|
|
440
440
|
const covered = spans.reduce((n, [s, e]) => n + e - s, 0);
|
|
441
441
|
return { id, slots, matched: spans, covered };
|
|
442
442
|
}
|
|
443
|
+
/** THE DISPLACED-FILLER GATE: does `projection` speak the ANCHOR's occupant of
|
|
444
|
+
* a position the query fills differently?
|
|
445
|
+
*
|
|
446
|
+
* A mechanism grounding through an anchor voices that anchor's continuation.
|
|
447
|
+
* When the query is the same structure as the anchor with one position filled
|
|
448
|
+
* differently — a different filename, a different word — the anchor's
|
|
449
|
+
* continuation is ABOUT THE ANCHOR'S occupant, and voicing it answers a
|
|
450
|
+
* question the asker did not ask. It is worse than silence, because it is
|
|
451
|
+
* fluent and specific and wrong:
|
|
452
|
+
*
|
|
453
|
+
* trained `How do I compile hello.c?` -> `Run gcc hello.c`
|
|
454
|
+
* asked `How do I compile main.c?`
|
|
455
|
+
* voiced `Run gcc hello.c` <- the corpus's file, not the asker's
|
|
456
|
+
*
|
|
457
|
+
* The same shape on the trained 15.7M-node store: `How do you say 'flurbish'
|
|
458
|
+
* in French?` answers "the way to say hello is \"Bonjour\"".
|
|
459
|
+
*
|
|
460
|
+
* THIS IS NOT THE RESTATED-FRAGMENT GUARD. That one asks whether the
|
|
461
|
+
* projection is a piece of the QUERY; this asks whether it is a piece of the
|
|
462
|
+
* ANCHOR that the query displaced. Neither implies the other, and the
|
|
463
|
+
* observed failures pass the restatement guard cleanly.
|
|
464
|
+
*
|
|
465
|
+
* Three conditions, all byte-exact and all necessary:
|
|
466
|
+
*
|
|
467
|
+
* 1. the query and the anchor must be ONE STRUCTURE — what they share has to
|
|
468
|
+
* dominate the query, or the query is not a variant of the anchor at all
|
|
469
|
+
* and the anchor's occupant of anything is beside the point;
|
|
470
|
+
* 2. both sides of the position must reach one river window — below it byte
|
|
471
|
+
* overlap is chance, not evidence (the floor identityBar and the bridge's
|
|
472
|
+
* attestedQ both draw);
|
|
473
|
+
* 3. the projection must voice the anchor's filler and NOT the query's
|
|
474
|
+
* referent. Voicing both is a projection that carried the asker's own
|
|
475
|
+
* occupant through, which is exactly what a licensed reference does and
|
|
476
|
+
* must stay allowed;
|
|
477
|
+
* 4. and the projection must share NO perceivable content with the query
|
|
478
|
+
* outside that position — no run of one river window.
|
|
479
|
+
*
|
|
480
|
+
* GATE 4 IS WHAT SEPARATES A DIFFERENT THING FROM A DIFFERENT WORD, and
|
|
481
|
+
* without it this refuses correct answers. A displaced slot alone cannot
|
|
482
|
+
* tell them apart: `symbol` <- `formula` and `main` <- `hello` are the same
|
|
483
|
+
* shape to the matcher — one substitution slot, frame dominating. Measured
|
|
484
|
+
* on the trained store, gates 1-3 alone silenced
|
|
485
|
+
*
|
|
486
|
+
* Q `What is the chemical symbol for water?`
|
|
487
|
+
* A `The chemical formula for water is H2O.`
|
|
488
|
+
*
|
|
489
|
+
* which is right, and merely phrased in the corpus's own words. The answer
|
|
490
|
+
* shares `the chemical ` and ` for water` with the question, so it is plainly
|
|
491
|
+
* about what was asked. `Run gcc hello.c` against `How do I compile main.c?`
|
|
492
|
+
* shares nothing but `.c` — two bytes, below the window where overlap stops
|
|
493
|
+
* being chance — so it is not about what was asked at all. No new constant:
|
|
494
|
+
* W is the same floor identityBar, attestedQ and the site test already draw. */
|
|
495
|
+
export function voicesDisplacedFiller(ctx, query, anchor, projection) {
|
|
496
|
+
const W = ctx.space.maxGroup;
|
|
497
|
+
const inst = frameSlots(ctx, query, anchor, 0);
|
|
498
|
+
if (inst === null)
|
|
499
|
+
return false;
|
|
500
|
+
if (!dominates(inst.covered, query.length))
|
|
501
|
+
return false;
|
|
502
|
+
for (const slot of inst.slots) {
|
|
503
|
+
if (slot.kind !== "substitution")
|
|
504
|
+
continue;
|
|
505
|
+
if (slot.qe - slot.qs < W || slot.filler.length < W)
|
|
506
|
+
continue;
|
|
507
|
+
if (indexOf(projection, slot.filler, 0) < 0)
|
|
508
|
+
continue;
|
|
509
|
+
const referent = query.subarray(slot.qs, slot.qe);
|
|
510
|
+
if (indexOf(projection, referent, 0) >= 0)
|
|
511
|
+
continue;
|
|
512
|
+
// Gate 4: does the projection still speak about the query's FRAME? A run
|
|
513
|
+
// of one window anywhere outside the displaced position is enough — the
|
|
514
|
+
// answer is then about the thing that was asked, in the corpus's own
|
|
515
|
+
// wording. Sharing nothing means it is about something else.
|
|
516
|
+
const shared = alignRuns(ctx, query, projection).some((r) => r.qe - r.qs >= W && (r.qe <= slot.qs || r.qs >= slot.qe));
|
|
517
|
+
if (shared)
|
|
518
|
+
continue;
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
443
523
|
/** Whether every member is byte-distinct from the others. */
|
|
444
524
|
export function distinct(items) {
|
|
445
525
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -8,7 +8,7 @@ import { consensusFloor, dominates, identityBar, reachThreshold, significanceBar
|
|
|
8
8
|
import { gistOf, read, resolve } from "../primitives.js";
|
|
9
9
|
import { bytesEqual, indexOf } from "../../bytes.js";
|
|
10
10
|
import { allWindowsAreScaffolding, corpusN, hubBound } from "../traverse.js";
|
|
11
|
-
import { follow, project, reverseContext } from "../match.js";
|
|
11
|
+
import { follow, project, reverseContext, voicesDisplacedFiller, } 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";
|
|
@@ -270,7 +270,19 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
270
270
|
(forest[0].vote >= minVote ||
|
|
271
271
|
(dominates(forest[0].breadth, 1) && forest[0].peak > Math.LN2))) {
|
|
272
272
|
const g = await project(ctx, forest[0].anchor, queryGist);
|
|
273
|
-
//
|
|
273
|
+
// THE ANCHOR'S OCCUPANT IS NOT THE ASKER'S. This tier grounds an anchor
|
|
274
|
+
// the climb elected, and voices that anchor's continuation. When the
|
|
275
|
+
// query is the same structure with one position filled differently, the
|
|
276
|
+
// continuation speaks the ANCHOR's occupant of that position — a fluent,
|
|
277
|
+
// specific, wrong answer (see voicesDisplacedFiller). Refusing here is
|
|
278
|
+
// silence, not a redirection: putting the asker's referent in its place
|
|
279
|
+
// is a stronger claim that needs the corpus's own carriage evidence, and
|
|
280
|
+
// that is `reference`'s job.
|
|
281
|
+
const anchorBytes = read(ctx, forest[0].anchor, query.length * ctx.space.maxGroup + 1);
|
|
282
|
+
if (g !== null && voicesDisplacedFiller(ctx, query, anchorBytes, g)) {
|
|
283
|
+
ctx.trace?.step("displacedFiller", [rItem(query, "query"), rNode(ctx, forest[0].anchor, "anchor")], [rItem(g, "withheld")], "refused — the anchor's continuation speaks the anchor's own " +
|
|
284
|
+
"occupant of a position this query fills differently");
|
|
285
|
+
} // The anchor cleared the consensus floor, but the floor prices the
|
|
274
286
|
// ANCHOR's evidence, not the projection's: a junk attractor can clear
|
|
275
287
|
// it and project a PIECE OF THE QUERY back at it (the observed
|
|
276
288
|
// "buenos días in English" → "English" fragment). A projection that
|
|
@@ -278,7 +290,7 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
278
290
|
// — never an answer (the same principle as `restates` above, extended
|
|
279
291
|
// to fragments). Genuine anchor groundings — longer than the query,
|
|
280
292
|
// or disjoint from it — pass untouched.
|
|
281
|
-
if (g && !(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
293
|
+
else if (g && !(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
282
294
|
return ground(g, "scaffolding-dominated query — ground the consensus-climb anchor", [[forest[0].start, forest[0].end]], CONCEPT);
|
|
283
295
|
}
|
|
284
296
|
}
|
package/jsr.json
CHANGED
package/package.json
CHANGED
package/src/mind/match.ts
CHANGED
|
@@ -612,6 +612,87 @@ export function frameSlots(
|
|
|
612
612
|
return { id, slots, matched: spans, covered };
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
+
/** THE DISPLACED-FILLER GATE: does `projection` speak the ANCHOR's occupant of
|
|
616
|
+
* a position the query fills differently?
|
|
617
|
+
*
|
|
618
|
+
* A mechanism grounding through an anchor voices that anchor's continuation.
|
|
619
|
+
* When the query is the same structure as the anchor with one position filled
|
|
620
|
+
* differently — a different filename, a different word — the anchor's
|
|
621
|
+
* continuation is ABOUT THE ANCHOR'S occupant, and voicing it answers a
|
|
622
|
+
* question the asker did not ask. It is worse than silence, because it is
|
|
623
|
+
* fluent and specific and wrong:
|
|
624
|
+
*
|
|
625
|
+
* trained `How do I compile hello.c?` -> `Run gcc hello.c`
|
|
626
|
+
* asked `How do I compile main.c?`
|
|
627
|
+
* voiced `Run gcc hello.c` <- the corpus's file, not the asker's
|
|
628
|
+
*
|
|
629
|
+
* The same shape on the trained 15.7M-node store: `How do you say 'flurbish'
|
|
630
|
+
* in French?` answers "the way to say hello is \"Bonjour\"".
|
|
631
|
+
*
|
|
632
|
+
* THIS IS NOT THE RESTATED-FRAGMENT GUARD. That one asks whether the
|
|
633
|
+
* projection is a piece of the QUERY; this asks whether it is a piece of the
|
|
634
|
+
* ANCHOR that the query displaced. Neither implies the other, and the
|
|
635
|
+
* observed failures pass the restatement guard cleanly.
|
|
636
|
+
*
|
|
637
|
+
* Three conditions, all byte-exact and all necessary:
|
|
638
|
+
*
|
|
639
|
+
* 1. the query and the anchor must be ONE STRUCTURE — what they share has to
|
|
640
|
+
* dominate the query, or the query is not a variant of the anchor at all
|
|
641
|
+
* and the anchor's occupant of anything is beside the point;
|
|
642
|
+
* 2. both sides of the position must reach one river window — below it byte
|
|
643
|
+
* overlap is chance, not evidence (the floor identityBar and the bridge's
|
|
644
|
+
* attestedQ both draw);
|
|
645
|
+
* 3. the projection must voice the anchor's filler and NOT the query's
|
|
646
|
+
* referent. Voicing both is a projection that carried the asker's own
|
|
647
|
+
* occupant through, which is exactly what a licensed reference does and
|
|
648
|
+
* must stay allowed;
|
|
649
|
+
* 4. and the projection must share NO perceivable content with the query
|
|
650
|
+
* outside that position — no run of one river window.
|
|
651
|
+
*
|
|
652
|
+
* GATE 4 IS WHAT SEPARATES A DIFFERENT THING FROM A DIFFERENT WORD, and
|
|
653
|
+
* without it this refuses correct answers. A displaced slot alone cannot
|
|
654
|
+
* tell them apart: `symbol` <- `formula` and `main` <- `hello` are the same
|
|
655
|
+
* shape to the matcher — one substitution slot, frame dominating. Measured
|
|
656
|
+
* on the trained store, gates 1-3 alone silenced
|
|
657
|
+
*
|
|
658
|
+
* Q `What is the chemical symbol for water?`
|
|
659
|
+
* A `The chemical formula for water is H2O.`
|
|
660
|
+
*
|
|
661
|
+
* which is right, and merely phrased in the corpus's own words. The answer
|
|
662
|
+
* shares `the chemical ` and ` for water` with the question, so it is plainly
|
|
663
|
+
* about what was asked. `Run gcc hello.c` against `How do I compile main.c?`
|
|
664
|
+
* shares nothing but `.c` — two bytes, below the window where overlap stops
|
|
665
|
+
* being chance — so it is not about what was asked at all. No new constant:
|
|
666
|
+
* W is the same floor identityBar, attestedQ and the site test already draw. */
|
|
667
|
+
export function voicesDisplacedFiller(
|
|
668
|
+
ctx: MindContext,
|
|
669
|
+
query: Uint8Array,
|
|
670
|
+
anchor: Uint8Array,
|
|
671
|
+
projection: Uint8Array,
|
|
672
|
+
): boolean {
|
|
673
|
+
const W = ctx.space.maxGroup;
|
|
674
|
+
const inst = frameSlots(ctx, query, anchor, 0);
|
|
675
|
+
if (inst === null) return false;
|
|
676
|
+
if (!dominates(inst.covered, query.length)) return false;
|
|
677
|
+
for (const slot of inst.slots) {
|
|
678
|
+
if (slot.kind !== "substitution") continue;
|
|
679
|
+
if (slot.qe - slot.qs < W || slot.filler.length < W) continue;
|
|
680
|
+
if (indexOf(projection, slot.filler, 0) < 0) continue;
|
|
681
|
+
const referent = query.subarray(slot.qs, slot.qe);
|
|
682
|
+
if (indexOf(projection, referent, 0) >= 0) continue;
|
|
683
|
+
// Gate 4: does the projection still speak about the query's FRAME? A run
|
|
684
|
+
// of one window anywhere outside the displaced position is enough — the
|
|
685
|
+
// answer is then about the thing that was asked, in the corpus's own
|
|
686
|
+
// wording. Sharing nothing means it is about something else.
|
|
687
|
+
const shared = alignRuns(ctx, query, projection).some((r) =>
|
|
688
|
+
r.qe - r.qs >= W && (r.qe <= slot.qs || r.qs >= slot.qe)
|
|
689
|
+
);
|
|
690
|
+
if (shared) continue;
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
|
|
615
696
|
/** Whether every member is byte-distinct from the others. */
|
|
616
697
|
export function distinct(items: readonly Uint8Array[]): boolean {
|
|
617
698
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -17,7 +17,12 @@ import type { MindContext } from "../types.js";
|
|
|
17
17
|
import { gistOf, read, resolve } from "../primitives.js";
|
|
18
18
|
import { bytesEqual, indexOf } from "../../bytes.js";
|
|
19
19
|
import { allWindowsAreScaffolding, corpusN, hubBound } from "../traverse.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
follow,
|
|
22
|
+
project,
|
|
23
|
+
reverseContext,
|
|
24
|
+
voicesDisplacedFiller,
|
|
25
|
+
} from "../match.js";
|
|
21
26
|
import { CONCEPT, STEP } from "../graph-search.js";
|
|
22
27
|
import { unexplainedLabel } from "../rationale.js";
|
|
23
28
|
import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
|
|
@@ -349,7 +354,28 @@ export async function recallByResonance(
|
|
|
349
354
|
(dominates(forest[0].breadth, 1) && forest[0].peak > Math.LN2))
|
|
350
355
|
) {
|
|
351
356
|
const g = await project(ctx, forest[0].anchor, queryGist);
|
|
352
|
-
//
|
|
357
|
+
// THE ANCHOR'S OCCUPANT IS NOT THE ASKER'S. This tier grounds an anchor
|
|
358
|
+
// the climb elected, and voices that anchor's continuation. When the
|
|
359
|
+
// query is the same structure with one position filled differently, the
|
|
360
|
+
// continuation speaks the ANCHOR's occupant of that position — a fluent,
|
|
361
|
+
// specific, wrong answer (see voicesDisplacedFiller). Refusing here is
|
|
362
|
+
// silence, not a redirection: putting the asker's referent in its place
|
|
363
|
+
// is a stronger claim that needs the corpus's own carriage evidence, and
|
|
364
|
+
// that is `reference`'s job.
|
|
365
|
+
const anchorBytes = read(
|
|
366
|
+
ctx,
|
|
367
|
+
forest[0].anchor,
|
|
368
|
+
query.length * ctx.space.maxGroup + 1,
|
|
369
|
+
);
|
|
370
|
+
if (g !== null && voicesDisplacedFiller(ctx, query, anchorBytes, g)) {
|
|
371
|
+
ctx.trace?.step(
|
|
372
|
+
"displacedFiller",
|
|
373
|
+
[rItem(query, "query"), rNode(ctx, forest[0].anchor, "anchor")],
|
|
374
|
+
[rItem(g, "withheld")],
|
|
375
|
+
"refused — the anchor's continuation speaks the anchor's own " +
|
|
376
|
+
"occupant of a position this query fills differently",
|
|
377
|
+
);
|
|
378
|
+
} // The anchor cleared the consensus floor, but the floor prices the
|
|
353
379
|
// ANCHOR's evidence, not the projection's: a junk attractor can clear
|
|
354
380
|
// it and project a PIECE OF THE QUERY back at it (the observed
|
|
355
381
|
// "buenos días in English" → "English" fragment). A projection that
|
|
@@ -357,7 +383,7 @@ export async function recallByResonance(
|
|
|
357
383
|
// — never an answer (the same principle as `restates` above, extended
|
|
358
384
|
// to fragments). Genuine anchor groundings — longer than the query,
|
|
359
385
|
// or disjoint from it — pass untouched.
|
|
360
|
-
if (g && !(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
386
|
+
else if (g && !(g.length < query.length && indexOf(query, g, 0) >= 0)) {
|
|
361
387
|
return ground(
|
|
362
388
|
g,
|
|
363
389
|
"scaffolding-dominated query — ground the consensus-climb anchor",
|
|
@@ -403,6 +403,78 @@ test("a referent may not be lifted out of the engine's OWN reply", async () => {
|
|
|
403
403
|
await m.store.close();
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
+
// ── THE DISPLACED-FILLER GATE ──────────────────────────────────────────────
|
|
407
|
+
//
|
|
408
|
+
// Reference needs two instances before it will voice a binding: one instance
|
|
409
|
+
// agrees with nothing, so nothing distinguishes "Run gcc hello.c" (a carriage
|
|
410
|
+
// that follows the filename) from "hello.c needs -lm" (a fact about that one
|
|
411
|
+
// file). Abstaining there is right.
|
|
412
|
+
//
|
|
413
|
+
// What is NOT right is what used to happen next. Recall's
|
|
414
|
+
// scaffolding-dominated tier grounds the anchor the climb elected and voices
|
|
415
|
+
// that anchor's continuation — which speaks the ANCHOR's occupant of the very
|
|
416
|
+
// position the query fills differently. Measured on a one-example corpus,
|
|
417
|
+
// `How do I compile main.c?` answered `Run gcc hello.c`; on the trained
|
|
418
|
+
// 15.7M-node store, `How do you say 'flurbish' in French?` answers "the way to
|
|
419
|
+
// say hello is \"Bonjour\"". Fluent, specific, and about the wrong thing.
|
|
420
|
+
//
|
|
421
|
+
// The gate REFUSES ONLY. It never puts the asker's referent in the corpus's
|
|
422
|
+
// place — that is a stronger claim needing the corpus's own carriage evidence,
|
|
423
|
+
// which is what the licence above supplies. Where the corpus cannot license a
|
|
424
|
+
// binding, silence is the honest degradation.
|
|
425
|
+
|
|
426
|
+
test("a projection may not voice the ANCHOR's occupant of a displaced slot", async () => {
|
|
427
|
+
const m = await mindWith([
|
|
428
|
+
["How do I compile hello.c?", "Run gcc hello.c"],
|
|
429
|
+
["What is the capital of France?", "Paris"],
|
|
430
|
+
]);
|
|
431
|
+
const out = clean((await m.respond("How do I compile main.c?")).bytes).trim();
|
|
432
|
+
assert.ok(
|
|
433
|
+
!out.includes("hello"),
|
|
434
|
+
`voiced the corpus's filename for the asker's file: ${JSON.stringify(out)}`,
|
|
435
|
+
);
|
|
436
|
+
assert.equal(out, "", "the honest degradation here is silence");
|
|
437
|
+
await m.store.close();
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("the gate is not the restated-fragment guard", async () => {
|
|
441
|
+
// The refused projection is not a piece of the QUERY — it passes the
|
|
442
|
+
// restatement guard cleanly — it is a piece of the ANCHOR the query
|
|
443
|
+
// displaced. Neither guard implies the other.
|
|
444
|
+
const m = await mindWith([
|
|
445
|
+
["How do I compile hello.c?", "Run gcc hello.c"],
|
|
446
|
+
["What is the capital of France?", "Paris"],
|
|
447
|
+
]);
|
|
448
|
+
const q = "How do I compile main.c?";
|
|
449
|
+
assert.ok(
|
|
450
|
+
!q.includes("Run gcc hello.c"),
|
|
451
|
+
"fixture broken: the projection must NOT be a query fragment",
|
|
452
|
+
);
|
|
453
|
+
assert.equal(clean((await m.respond(q)).bytes).trim(), "");
|
|
454
|
+
await m.store.close();
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
test("a projection that carries the ASKER's own occupant is untouched", async () => {
|
|
458
|
+
// Voicing the anchor's filler AND the query's referent is what a licensed
|
|
459
|
+
// reference does; the gate must not touch it.
|
|
460
|
+
const m = await mindWith(CARRIED);
|
|
461
|
+
const r = await m.respond("How do I compile main.c?");
|
|
462
|
+
assert.equal(clean(r.bytes).trim(), "Run gcc main.c");
|
|
463
|
+
assert.equal(r.provenance, "reference");
|
|
464
|
+
await m.store.close();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
test("a sub-quantum difference does not trip the gate", async () => {
|
|
468
|
+
// Below one river window byte overlap is chance, not a displaced slot.
|
|
469
|
+
const m = await mindWith([
|
|
470
|
+
["What is the capital of France?", "Paris"],
|
|
471
|
+
["Who wrote Hamlet?", "Shakespeare"],
|
|
472
|
+
]);
|
|
473
|
+
const out = clean((await m.respond("What is the capital of Franc?")).bytes);
|
|
474
|
+
assert.match(out, /Paris/, `a near-identical query lost its answer: ${out}`);
|
|
475
|
+
await m.store.close();
|
|
476
|
+
});
|
|
477
|
+
|
|
406
478
|
// ── NO HIJACK ──────────────────────────────────────────────────────────────
|
|
407
479
|
|
|
408
480
|
test("a trained query is answered by its own edge, not by reference", async () => {
|