@hviana/sema 0.2.7 → 0.2.9
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.
|
@@ -2,6 +2,7 @@ import type { DerivationStep } from "./graph-search.js";
|
|
|
2
2
|
import type { AncestorReach, Attention, AttentionRead, DFMode, MindContext, Region, RegionVote, SaturationInfo, SaturationStop } from "./types.js";
|
|
3
3
|
import { type StructuralPart } from "../geometry.js";
|
|
4
4
|
import { type JunctionSynonymSides } from "./junction.js";
|
|
5
|
+
import type { Vec } from "../vec.js";
|
|
5
6
|
/** How the newly-added graded junction ladder (junction.ts / attention.ts's
|
|
6
7
|
* {@link CrossRegionTier}) is reported on a `junctionVotes` entry. The
|
|
7
8
|
* instrumentation spec this implements predates that ladder and only knew
|
|
@@ -357,11 +358,23 @@ export interface StructuralResonanceProposal {
|
|
|
357
358
|
leftSiblingId?: number;
|
|
358
359
|
rightSiblingId?: number;
|
|
359
360
|
}
|
|
361
|
+
/** A sibling gist cached in the shared, climb-wide memo alongside the
|
|
362
|
+
* COMPLETE stored byte length it was reconstructed from — the length is
|
|
363
|
+
* required to tell whether a cache hit is still valid under a probe whose
|
|
364
|
+
* `maxSiblingBytes` bound is smaller than the one that first cached it. */
|
|
365
|
+
interface CachedSiblingGist {
|
|
366
|
+
gist: Vec;
|
|
367
|
+
length: number;
|
|
368
|
+
}
|
|
360
369
|
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
361
370
|
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
362
371
|
* synonym variants (single- and double-synonym combined, one shared
|
|
363
|
-
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
364
|
-
|
|
372
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
373
|
+
* Variant selection is entirely lightweight (see {@link
|
|
374
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
375
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
376
|
+
* climb via `siblingGistMemo`. */
|
|
377
|
+
export declare function buildStructuralVariants(ctx: MindContext, ra: Region, rb: Region, sides: JunctionSynonymSides, siblingGistMemo: Map<number, CachedSiblingGist>): {
|
|
365
378
|
variants: StructuralVariant[];
|
|
366
379
|
exactLeft: StructuralPart;
|
|
367
380
|
exactRight: StructuralPart;
|
|
@@ -370,7 +383,7 @@ export declare function buildStructuralVariants(ctx: MindContext, ra: Region, rb
|
|
|
370
383
|
* ANN-query each, merge proposals by candidate id, and validate the winner
|
|
371
384
|
* through the SAME structural gates every other tier answers to (saturation,
|
|
372
385
|
* roots, IDF, contrastive margin). Returns null when nothing survives. */
|
|
373
|
-
export declare function structuralResonance(ctx: MindContext, query: Uint8Array, ra: Region, rb: Region, sides: JunctionSynonymSides, k: number, N: number, reachMemo: Map<number, AncestorReach>,
|
|
386
|
+
export declare function structuralResonance(ctx: MindContext, query: Uint8Array, ra: Region, rb: Region, sides: JunctionSynonymSides, siblingGistMemo: Map<number, CachedSiblingGist>, k: number, N: number, reachMemo: Map<number, AncestorReach>,
|
|
374
387
|
/** Each side's OWN individual climb roots (from voteRegions), when it cast
|
|
375
388
|
* one — the self-evidence backstop structural-resonance needs and the
|
|
376
389
|
* exact tier gets for free from literal byte containment (§11's whole
|
|
@@ -916,67 +916,99 @@ const VARIANT_KIND_ORDER = {
|
|
|
916
916
|
"right-synonym": 1,
|
|
917
917
|
"double-synonym": 2,
|
|
918
918
|
};
|
|
919
|
-
/**
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
/** A halo sibling's structural part, occupying the ORIGINAL query-region
|
|
928
|
-
* slot length — the sibling replaces only the DIRECTION, never the query's
|
|
929
|
-
* own bytes, position, or gap (see §6 of the spec this implements). */
|
|
930
|
-
function siblingPart(ctx, sibling, originalRegion) {
|
|
931
|
-
return {
|
|
932
|
-
v: storedNodeGist(ctx, sibling.id),
|
|
933
|
-
len: originalRegion.end - originalRegion.start,
|
|
934
|
-
};
|
|
919
|
+
/** Same deterministic ordering the old implementation applied to already-
|
|
920
|
+
* materialized variants (§8): semantic confidence desc, then kind
|
|
921
|
+
* (left-synonym, right-synonym, double-synonym), then sibling ids asc. */
|
|
922
|
+
function compareStructuralVariantSpecs(a, b) {
|
|
923
|
+
return b.semanticConfidence - a.semanticConfidence ||
|
|
924
|
+
VARIANT_KIND_ORDER[a.kind] - VARIANT_KIND_ORDER[b.kind] ||
|
|
925
|
+
(a.leftSiblingId ?? -1) - (b.leftSiblingId ?? -1) ||
|
|
926
|
+
(a.rightSiblingId ?? -1) - (b.rightSiblingId ?? -1);
|
|
935
927
|
}
|
|
936
|
-
/**
|
|
937
|
-
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const
|
|
943
|
-
const
|
|
944
|
-
|
|
945
|
-
synonymVariants.push({
|
|
946
|
-
left: siblingPart(ctx, ls, ra),
|
|
947
|
-
right: exactRight,
|
|
928
|
+
/** Every single- and double-synonym combination, as cost-free descriptors —
|
|
929
|
+
* no `read`, `gistOf`, `perceive` or `StructuralPart` allocation. Both
|
|
930
|
+
* sibling lists are already bounded by `haloQueryK`, so the O(haloQueryK²)
|
|
931
|
+
* cross-product here is cheap; only the SELECTED specs go on to pay for
|
|
932
|
+
* sibling reconstruction. */
|
|
933
|
+
function buildStructuralVariantSpecs(sides) {
|
|
934
|
+
const specs = [];
|
|
935
|
+
for (const left of sides.leftSiblings) {
|
|
936
|
+
specs.push({
|
|
948
937
|
kind: "left-synonym",
|
|
949
|
-
semanticConfidence:
|
|
950
|
-
leftSiblingId:
|
|
938
|
+
semanticConfidence: left.score,
|
|
939
|
+
leftSiblingId: left.id,
|
|
951
940
|
});
|
|
952
941
|
}
|
|
953
|
-
for (const
|
|
954
|
-
|
|
955
|
-
left: exactLeft,
|
|
956
|
-
right: siblingPart(ctx, rs, rb),
|
|
942
|
+
for (const right of sides.rightSiblings) {
|
|
943
|
+
specs.push({
|
|
957
944
|
kind: "right-synonym",
|
|
958
|
-
semanticConfidence:
|
|
959
|
-
rightSiblingId:
|
|
945
|
+
semanticConfidence: right.score,
|
|
946
|
+
rightSiblingId: right.id,
|
|
960
947
|
});
|
|
961
948
|
}
|
|
962
|
-
for (const
|
|
963
|
-
for (const
|
|
964
|
-
|
|
965
|
-
left: siblingPart(ctx, ls, ra),
|
|
966
|
-
right: siblingPart(ctx, rs, rb),
|
|
949
|
+
for (const left of sides.leftSiblings) {
|
|
950
|
+
for (const right of sides.rightSiblings) {
|
|
951
|
+
specs.push({
|
|
967
952
|
kind: "double-synonym",
|
|
968
|
-
semanticConfidence: Math.min(
|
|
969
|
-
leftSiblingId:
|
|
970
|
-
rightSiblingId:
|
|
953
|
+
semanticConfidence: Math.min(left.score, right.score),
|
|
954
|
+
leftSiblingId: left.id,
|
|
955
|
+
rightSiblingId: right.id,
|
|
971
956
|
});
|
|
972
957
|
}
|
|
973
958
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
959
|
+
specs.sort(compareStructuralVariantSpecs);
|
|
960
|
+
return specs;
|
|
961
|
+
}
|
|
962
|
+
/** A halo sibling's structural gist, bounded to `maxBytes` of stored content
|
|
963
|
+
* and reused across the whole climb. `positiveMemo` (shared across every
|
|
964
|
+
* probe in the climb, passed in by the caller) remembers only successfully
|
|
965
|
+
* reconstructed complete gists together with their complete byte length —
|
|
966
|
+
* a sibling rejected here for being too large for THIS pair's phrase-scale
|
|
967
|
+
* bound may still be admissible for a larger-spanning pair later, so a
|
|
968
|
+
* rejection is never memoized globally, and a sibling cached by a LARGER
|
|
969
|
+
* probe is only reused here when its length still fits THIS probe's
|
|
970
|
+
* (possibly smaller) bound — eligibility must never depend on which probe
|
|
971
|
+
* happened to cache the sibling first. `localMemo` is scoped to one
|
|
972
|
+
* `buildStructuralVariants` call, where every variant shares the same
|
|
973
|
+
* bound, so a `null` there is safe to reuse. */
|
|
974
|
+
function loadBoundedSiblingGist(ctx, id, maxBytes, positiveMemo, localMemo) {
|
|
975
|
+
if (localMemo.has(id)) {
|
|
976
|
+
return localMemo.get(id) ?? null;
|
|
977
|
+
}
|
|
978
|
+
const cached = positiveMemo.get(id);
|
|
979
|
+
if (cached !== undefined) {
|
|
980
|
+
const result = cached.length <= maxBytes ? cached.gist : null;
|
|
981
|
+
localMemo.set(id, result);
|
|
982
|
+
return result;
|
|
983
|
+
}
|
|
984
|
+
const length = ctx.store.contentLen(id, maxBytes + 1);
|
|
985
|
+
if (length <= 0 || length > maxBytes) {
|
|
986
|
+
localMemo.set(id, null);
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
const bytes = read(ctx, id, maxBytes + 1);
|
|
990
|
+
if (bytes.length === 0 || bytes.length > maxBytes) {
|
|
991
|
+
localMemo.set(id, null);
|
|
992
|
+
return null;
|
|
993
|
+
}
|
|
994
|
+
const gist = gistOf(ctx, bytes);
|
|
995
|
+
positiveMemo.set(id, { gist, length });
|
|
996
|
+
localMemo.set(id, gist);
|
|
997
|
+
return gist;
|
|
998
|
+
}
|
|
999
|
+
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
1000
|
+
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
1001
|
+
* synonym variants (single- and double-synonym combined, one shared
|
|
1002
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
1003
|
+
* Variant selection is entirely lightweight (see {@link
|
|
1004
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
1005
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
1006
|
+
* climb via `siblingGistMemo`. */
|
|
1007
|
+
export function buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo) {
|
|
1008
|
+
const leftLen = ra.end - ra.start;
|
|
1009
|
+
const rightLen = rb.end - rb.start;
|
|
1010
|
+
const exactLeft = { v: ra.v, len: leftLen };
|
|
1011
|
+
const exactRight = { v: rb.v, len: rightLen };
|
|
980
1012
|
const variants = [
|
|
981
1013
|
{
|
|
982
1014
|
left: exactLeft,
|
|
@@ -984,8 +1016,43 @@ export function buildStructuralVariants(ctx, ra, rb, sides) {
|
|
|
984
1016
|
kind: "exact-exact",
|
|
985
1017
|
semanticConfidence: 1,
|
|
986
1018
|
},
|
|
987
|
-
...synonymVariants.slice(0, ctx.cfg.haloQueryK),
|
|
988
1019
|
];
|
|
1020
|
+
// Same phrase-scale bound the cross-region junction ladder uses
|
|
1021
|
+
// (`maxInterior`): a sibling whose complete stored content exceeds it is
|
|
1022
|
+
// not materialized as a structural-resonance endpoint, keeping sibling
|
|
1023
|
+
// reconstruction phrase-scale even for a large deposit or conversation
|
|
1024
|
+
// root that merely appeared in a halo result.
|
|
1025
|
+
const maxSiblingBytes = (leftLen + rightLen) * ctx.space.maxGroup;
|
|
1026
|
+
const specs = buildStructuralVariantSpecs(sides);
|
|
1027
|
+
const localGistMemo = new Map();
|
|
1028
|
+
let retainedSynonyms = 0;
|
|
1029
|
+
for (const spec of specs) {
|
|
1030
|
+
if (retainedSynonyms >= ctx.cfg.haloQueryK)
|
|
1031
|
+
break;
|
|
1032
|
+
let left = exactLeft;
|
|
1033
|
+
let right = exactRight;
|
|
1034
|
+
if (spec.leftSiblingId !== undefined) {
|
|
1035
|
+
const gist = loadBoundedSiblingGist(ctx, spec.leftSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
|
|
1036
|
+
if (gist === null)
|
|
1037
|
+
continue;
|
|
1038
|
+
left = { v: gist, len: leftLen };
|
|
1039
|
+
}
|
|
1040
|
+
if (spec.rightSiblingId !== undefined) {
|
|
1041
|
+
const gist = loadBoundedSiblingGist(ctx, spec.rightSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
|
|
1042
|
+
if (gist === null)
|
|
1043
|
+
continue;
|
|
1044
|
+
right = { v: gist, len: rightLen };
|
|
1045
|
+
}
|
|
1046
|
+
variants.push({
|
|
1047
|
+
left,
|
|
1048
|
+
right,
|
|
1049
|
+
kind: spec.kind,
|
|
1050
|
+
semanticConfidence: spec.semanticConfidence,
|
|
1051
|
+
leftSiblingId: spec.leftSiblingId,
|
|
1052
|
+
rightSiblingId: spec.rightSiblingId,
|
|
1053
|
+
});
|
|
1054
|
+
retainedSynonyms++;
|
|
1055
|
+
}
|
|
989
1056
|
return { variants, exactLeft, exactRight };
|
|
990
1057
|
}
|
|
991
1058
|
/** Deterministic best-of tie-break for two proposals ranked for the SAME
|
|
@@ -1012,7 +1079,7 @@ function betterProposal(a, b) {
|
|
|
1012
1079
|
* ANN-query each, merge proposals by candidate id, and validate the winner
|
|
1013
1080
|
* through the SAME structural gates every other tier answers to (saturation,
|
|
1014
1081
|
* roots, IDF, contrastive margin). Returns null when nothing survives. */
|
|
1015
|
-
export async function structuralResonance(ctx, query, ra, rb, sides, k, N, reachMemo,
|
|
1082
|
+
export async function structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo,
|
|
1016
1083
|
/** Each side's OWN individual climb roots (from voteRegions), when it cast
|
|
1017
1084
|
* one — the self-evidence backstop structural-resonance needs and the
|
|
1018
1085
|
* exact tier gets for free from literal byte containment (§11's whole
|
|
@@ -1021,7 +1088,7 @@ export async function structuralResonance(ctx, query, ra, rb, sides, k, N, reach
|
|
|
1021
1088
|
* evidence of a joint whole; it is that side's resonance rediscovering
|
|
1022
1089
|
* itself through a synthetic gist still dominated by its own direction. */
|
|
1023
1090
|
ownRootsA, ownRootsB, trace) {
|
|
1024
|
-
const { variants } = buildStructuralVariants(ctx, ra, rb, sides);
|
|
1091
|
+
const { variants } = buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo);
|
|
1025
1092
|
if (trace)
|
|
1026
1093
|
trace.variantBudget = ctx.cfg.haloQueryK;
|
|
1027
1094
|
const middleBytes = query.subarray(ra.end, rb.start);
|
|
@@ -1177,6 +1244,10 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1177
1244
|
//
|
|
1178
1245
|
// Only MAXIMAL spans compose: a span contained in another candidate is a
|
|
1179
1246
|
// fragment of that candidate's evidence, never independent of it.
|
|
1247
|
+
// Shared across every cross-region probe in this climb: a sibling
|
|
1248
|
+
// successfully reconstructed while probing one pair must not be read and
|
|
1249
|
+
// perceived again while probing another pair in the same climb.
|
|
1250
|
+
const siblingGistMemo = new Map();
|
|
1180
1251
|
const votedSpans = new Set();
|
|
1181
1252
|
for (const rv of rvs.votes)
|
|
1182
1253
|
votedSpans.add(`${rv.start},${rv.end}`);
|
|
@@ -1425,7 +1496,7 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1425
1496
|
}
|
|
1426
1497
|
const ownRootsA = rvs.votes.find((v) => v.start === ra.start && v.end === ra.end)?.roots;
|
|
1427
1498
|
const ownRootsB = rvs.votes.find((v) => v.start === rb.start && v.end === rb.end)?.roots;
|
|
1428
|
-
structuralPick = await structuralResonance(ctx, query, ra, rb, sides, k, N, reachMemo, ownRootsA, ownRootsB, resonanceTrace);
|
|
1499
|
+
structuralPick = await structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo, ownRootsA, ownRootsB, resonanceTrace);
|
|
1429
1500
|
}
|
|
1430
1501
|
if (structuralPick === null) {
|
|
1431
1502
|
pushProbe(reasons.length > 0 ? "resonance-ineligible" : "resonance-rejected");
|
package/package.json
CHANGED
package/src/mind/attention.ts
CHANGED
|
@@ -1549,86 +1549,151 @@ const VARIANT_KIND_ORDER: Record<StructuralVariant["kind"], number> = {
|
|
|
1549
1549
|
"double-synonym": 2,
|
|
1550
1550
|
};
|
|
1551
1551
|
|
|
1552
|
-
/** A
|
|
1553
|
-
*
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1552
|
+
/** A lightweight, cost-free descriptor of one candidate structural variant —
|
|
1553
|
+
* enough to rank it, but with no bytes read and no vector materialized. */
|
|
1554
|
+
interface StructuralVariantSpec {
|
|
1555
|
+
kind: "left-synonym" | "right-synonym" | "double-synonym";
|
|
1556
|
+
semanticConfidence: number;
|
|
1557
|
+
leftSiblingId?: number;
|
|
1558
|
+
rightSiblingId?: number;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/** Same deterministic ordering the old implementation applied to already-
|
|
1562
|
+
* materialized variants (§8): semantic confidence desc, then kind
|
|
1563
|
+
* (left-synonym, right-synonym, double-synonym), then sibling ids asc. */
|
|
1564
|
+
function compareStructuralVariantSpecs(
|
|
1565
|
+
a: StructuralVariantSpec,
|
|
1566
|
+
b: StructuralVariantSpec,
|
|
1567
|
+
): number {
|
|
1568
|
+
return b.semanticConfidence - a.semanticConfidence ||
|
|
1569
|
+
VARIANT_KIND_ORDER[a.kind] - VARIANT_KIND_ORDER[b.kind] ||
|
|
1570
|
+
(a.leftSiblingId ?? -1) - (b.leftSiblingId ?? -1) ||
|
|
1571
|
+
(a.rightSiblingId ?? -1) - (b.rightSiblingId ?? -1);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
/** Every single- and double-synonym combination, as cost-free descriptors —
|
|
1575
|
+
* no `read`, `gistOf`, `perceive` or `StructuralPart` allocation. Both
|
|
1576
|
+
* sibling lists are already bounded by `haloQueryK`, so the O(haloQueryK²)
|
|
1577
|
+
* cross-product here is cheap; only the SELECTED specs go on to pay for
|
|
1578
|
+
* sibling reconstruction. */
|
|
1579
|
+
function buildStructuralVariantSpecs(
|
|
1580
|
+
sides: JunctionSynonymSides,
|
|
1581
|
+
): StructuralVariantSpec[] {
|
|
1582
|
+
const specs: StructuralVariantSpec[] = [];
|
|
1583
|
+
|
|
1584
|
+
for (const left of sides.leftSiblings) {
|
|
1585
|
+
specs.push({
|
|
1586
|
+
kind: "left-synonym",
|
|
1587
|
+
semanticConfidence: left.score,
|
|
1588
|
+
leftSiblingId: left.id,
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
for (const right of sides.rightSiblings) {
|
|
1593
|
+
specs.push({
|
|
1594
|
+
kind: "right-synonym",
|
|
1595
|
+
semanticConfidence: right.score,
|
|
1596
|
+
rightSiblingId: right.id,
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
for (const left of sides.leftSiblings) {
|
|
1601
|
+
for (const right of sides.rightSiblings) {
|
|
1602
|
+
specs.push({
|
|
1603
|
+
kind: "double-synonym",
|
|
1604
|
+
semanticConfidence: Math.min(left.score, right.score),
|
|
1605
|
+
leftSiblingId: left.id,
|
|
1606
|
+
rightSiblingId: right.id,
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
specs.sort(compareStructuralVariantSpecs);
|
|
1612
|
+
|
|
1613
|
+
return specs;
|
|
1559
1614
|
}
|
|
1560
1615
|
|
|
1561
|
-
/** A
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1564
|
-
|
|
1616
|
+
/** A sibling gist cached in the shared, climb-wide memo alongside the
|
|
1617
|
+
* COMPLETE stored byte length it was reconstructed from — the length is
|
|
1618
|
+
* required to tell whether a cache hit is still valid under a probe whose
|
|
1619
|
+
* `maxSiblingBytes` bound is smaller than the one that first cached it. */
|
|
1620
|
+
interface CachedSiblingGist {
|
|
1621
|
+
gist: Vec;
|
|
1622
|
+
length: number;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
/** A halo sibling's structural gist, bounded to `maxBytes` of stored content
|
|
1626
|
+
* and reused across the whole climb. `positiveMemo` (shared across every
|
|
1627
|
+
* probe in the climb, passed in by the caller) remembers only successfully
|
|
1628
|
+
* reconstructed complete gists together with their complete byte length —
|
|
1629
|
+
* a sibling rejected here for being too large for THIS pair's phrase-scale
|
|
1630
|
+
* bound may still be admissible for a larger-spanning pair later, so a
|
|
1631
|
+
* rejection is never memoized globally, and a sibling cached by a LARGER
|
|
1632
|
+
* probe is only reused here when its length still fits THIS probe's
|
|
1633
|
+
* (possibly smaller) bound — eligibility must never depend on which probe
|
|
1634
|
+
* happened to cache the sibling first. `localMemo` is scoped to one
|
|
1635
|
+
* `buildStructuralVariants` call, where every variant shares the same
|
|
1636
|
+
* bound, so a `null` there is safe to reuse. */
|
|
1637
|
+
function loadBoundedSiblingGist(
|
|
1565
1638
|
ctx: MindContext,
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1639
|
+
id: number,
|
|
1640
|
+
maxBytes: number,
|
|
1641
|
+
positiveMemo: Map<number, CachedSiblingGist>,
|
|
1642
|
+
localMemo: Map<number, Vec | null>,
|
|
1643
|
+
): Vec | null {
|
|
1644
|
+
if (localMemo.has(id)) {
|
|
1645
|
+
return localMemo.get(id) ?? null;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
const cached = positiveMemo.get(id);
|
|
1649
|
+
if (cached !== undefined) {
|
|
1650
|
+
const result = cached.length <= maxBytes ? cached.gist : null;
|
|
1651
|
+
localMemo.set(id, result);
|
|
1652
|
+
return result;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
const length = ctx.store.contentLen(id, maxBytes + 1);
|
|
1656
|
+
if (length <= 0 || length > maxBytes) {
|
|
1657
|
+
localMemo.set(id, null);
|
|
1658
|
+
return null;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
const bytes = read(ctx, id, maxBytes + 1);
|
|
1662
|
+
if (bytes.length === 0 || bytes.length > maxBytes) {
|
|
1663
|
+
localMemo.set(id, null);
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
const gist = gistOf(ctx, bytes);
|
|
1668
|
+
positiveMemo.set(id, { gist, length });
|
|
1669
|
+
localMemo.set(id, gist);
|
|
1670
|
+
return gist;
|
|
1573
1671
|
}
|
|
1574
1672
|
|
|
1575
1673
|
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
1576
1674
|
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
1577
1675
|
* synonym variants (single- and double-synonym combined, one shared
|
|
1578
|
-
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
1676
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
1677
|
+
* Variant selection is entirely lightweight (see {@link
|
|
1678
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
1679
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
1680
|
+
* climb via `siblingGistMemo`. */
|
|
1579
1681
|
export function buildStructuralVariants(
|
|
1580
1682
|
ctx: MindContext,
|
|
1581
1683
|
ra: Region,
|
|
1582
1684
|
rb: Region,
|
|
1583
1685
|
sides: JunctionSynonymSides,
|
|
1686
|
+
siblingGistMemo: Map<number, CachedSiblingGist>,
|
|
1584
1687
|
): {
|
|
1585
1688
|
variants: StructuralVariant[];
|
|
1586
1689
|
exactLeft: StructuralPart;
|
|
1587
1690
|
exactRight: StructuralPart;
|
|
1588
1691
|
} {
|
|
1589
|
-
const
|
|
1590
|
-
const
|
|
1692
|
+
const leftLen = ra.end - ra.start;
|
|
1693
|
+
const rightLen = rb.end - rb.start;
|
|
1591
1694
|
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
synonymVariants.push({
|
|
1595
|
-
left: siblingPart(ctx, ls, ra),
|
|
1596
|
-
right: exactRight,
|
|
1597
|
-
kind: "left-synonym",
|
|
1598
|
-
semanticConfidence: ls.score,
|
|
1599
|
-
leftSiblingId: ls.id,
|
|
1600
|
-
});
|
|
1601
|
-
}
|
|
1602
|
-
for (const rs of sides.rightSiblings) {
|
|
1603
|
-
synonymVariants.push({
|
|
1604
|
-
left: exactLeft,
|
|
1605
|
-
right: siblingPart(ctx, rs, rb),
|
|
1606
|
-
kind: "right-synonym",
|
|
1607
|
-
semanticConfidence: rs.score,
|
|
1608
|
-
rightSiblingId: rs.id,
|
|
1609
|
-
});
|
|
1610
|
-
}
|
|
1611
|
-
for (const ls of sides.leftSiblings) {
|
|
1612
|
-
for (const rs of sides.rightSiblings) {
|
|
1613
|
-
synonymVariants.push({
|
|
1614
|
-
left: siblingPart(ctx, ls, ra),
|
|
1615
|
-
right: siblingPart(ctx, rs, rb),
|
|
1616
|
-
kind: "double-synonym",
|
|
1617
|
-
semanticConfidence: Math.min(ls.score, rs.score),
|
|
1618
|
-
leftSiblingId: ls.id,
|
|
1619
|
-
rightSiblingId: rs.id,
|
|
1620
|
-
});
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
// §8: semantic confidence desc, then kind (left-synonym, right-synonym,
|
|
1625
|
-
// double-synonym), then left sibling id asc, then right sibling id asc.
|
|
1626
|
-
synonymVariants.sort((a, b) =>
|
|
1627
|
-
b.semanticConfidence - a.semanticConfidence ||
|
|
1628
|
-
VARIANT_KIND_ORDER[a.kind] - VARIANT_KIND_ORDER[b.kind] ||
|
|
1629
|
-
(a.leftSiblingId ?? -1) - (b.leftSiblingId ?? -1) ||
|
|
1630
|
-
(a.rightSiblingId ?? -1) - (b.rightSiblingId ?? -1)
|
|
1631
|
-
);
|
|
1695
|
+
const exactLeft: StructuralPart = { v: ra.v, len: leftLen };
|
|
1696
|
+
const exactRight: StructuralPart = { v: rb.v, len: rightLen };
|
|
1632
1697
|
|
|
1633
1698
|
const variants: StructuralVariant[] = [
|
|
1634
1699
|
{
|
|
@@ -1637,8 +1702,60 @@ export function buildStructuralVariants(
|
|
|
1637
1702
|
kind: "exact-exact",
|
|
1638
1703
|
semanticConfidence: 1,
|
|
1639
1704
|
},
|
|
1640
|
-
...synonymVariants.slice(0, ctx.cfg.haloQueryK),
|
|
1641
1705
|
];
|
|
1706
|
+
|
|
1707
|
+
// Same phrase-scale bound the cross-region junction ladder uses
|
|
1708
|
+
// (`maxInterior`): a sibling whose complete stored content exceeds it is
|
|
1709
|
+
// not materialized as a structural-resonance endpoint, keeping sibling
|
|
1710
|
+
// reconstruction phrase-scale even for a large deposit or conversation
|
|
1711
|
+
// root that merely appeared in a halo result.
|
|
1712
|
+
const maxSiblingBytes = (leftLen + rightLen) * ctx.space.maxGroup;
|
|
1713
|
+
|
|
1714
|
+
const specs = buildStructuralVariantSpecs(sides);
|
|
1715
|
+
const localGistMemo = new Map<number, Vec | null>();
|
|
1716
|
+
let retainedSynonyms = 0;
|
|
1717
|
+
|
|
1718
|
+
for (const spec of specs) {
|
|
1719
|
+
if (retainedSynonyms >= ctx.cfg.haloQueryK) break;
|
|
1720
|
+
|
|
1721
|
+
let left = exactLeft;
|
|
1722
|
+
let right = exactRight;
|
|
1723
|
+
|
|
1724
|
+
if (spec.leftSiblingId !== undefined) {
|
|
1725
|
+
const gist = loadBoundedSiblingGist(
|
|
1726
|
+
ctx,
|
|
1727
|
+
spec.leftSiblingId,
|
|
1728
|
+
maxSiblingBytes,
|
|
1729
|
+
siblingGistMemo,
|
|
1730
|
+
localGistMemo,
|
|
1731
|
+
);
|
|
1732
|
+
if (gist === null) continue;
|
|
1733
|
+
left = { v: gist, len: leftLen };
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (spec.rightSiblingId !== undefined) {
|
|
1737
|
+
const gist = loadBoundedSiblingGist(
|
|
1738
|
+
ctx,
|
|
1739
|
+
spec.rightSiblingId,
|
|
1740
|
+
maxSiblingBytes,
|
|
1741
|
+
siblingGistMemo,
|
|
1742
|
+
localGistMemo,
|
|
1743
|
+
);
|
|
1744
|
+
if (gist === null) continue;
|
|
1745
|
+
right = { v: gist, len: rightLen };
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
variants.push({
|
|
1749
|
+
left,
|
|
1750
|
+
right,
|
|
1751
|
+
kind: spec.kind,
|
|
1752
|
+
semanticConfidence: spec.semanticConfidence,
|
|
1753
|
+
leftSiblingId: spec.leftSiblingId,
|
|
1754
|
+
rightSiblingId: spec.rightSiblingId,
|
|
1755
|
+
});
|
|
1756
|
+
retainedSynonyms++;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1642
1759
|
return { variants, exactLeft, exactRight };
|
|
1643
1760
|
}
|
|
1644
1761
|
|
|
@@ -1675,6 +1792,7 @@ export async function structuralResonance(
|
|
|
1675
1792
|
ra: Region,
|
|
1676
1793
|
rb: Region,
|
|
1677
1794
|
sides: JunctionSynonymSides,
|
|
1795
|
+
siblingGistMemo: Map<number, CachedSiblingGist>,
|
|
1678
1796
|
k: number,
|
|
1679
1797
|
N: number,
|
|
1680
1798
|
reachMemo: Map<number, AncestorReach>,
|
|
@@ -1692,7 +1810,13 @@ export async function structuralResonance(
|
|
|
1692
1810
|
| { proposal: StructuralResonanceProposal; reach: AncestorReach; idf: number }
|
|
1693
1811
|
| null
|
|
1694
1812
|
> {
|
|
1695
|
-
const { variants } = buildStructuralVariants(
|
|
1813
|
+
const { variants } = buildStructuralVariants(
|
|
1814
|
+
ctx,
|
|
1815
|
+
ra,
|
|
1816
|
+
rb,
|
|
1817
|
+
sides,
|
|
1818
|
+
siblingGistMemo,
|
|
1819
|
+
);
|
|
1696
1820
|
if (trace) trace.variantBudget = ctx.cfg.haloQueryK;
|
|
1697
1821
|
|
|
1698
1822
|
const middleBytes = query.subarray(ra.end, rb.start);
|
|
@@ -1864,6 +1988,10 @@ async function crossRegionVotes(
|
|
|
1864
1988
|
//
|
|
1865
1989
|
// Only MAXIMAL spans compose: a span contained in another candidate is a
|
|
1866
1990
|
// fragment of that candidate's evidence, never independent of it.
|
|
1991
|
+
// Shared across every cross-region probe in this climb: a sibling
|
|
1992
|
+
// successfully reconstructed while probing one pair must not be read and
|
|
1993
|
+
// perceived again while probing another pair in the same climb.
|
|
1994
|
+
const siblingGistMemo = new Map<number, CachedSiblingGist>();
|
|
1867
1995
|
const votedSpans = new Set<string>();
|
|
1868
1996
|
for (const rv of rvs.votes) votedSpans.add(`${rv.start},${rv.end}`);
|
|
1869
1997
|
const seen = new Set<string>();
|
|
@@ -2155,6 +2283,7 @@ async function crossRegionVotes(
|
|
|
2155
2283
|
ra,
|
|
2156
2284
|
rb,
|
|
2157
2285
|
sides,
|
|
2286
|
+
siblingGistMemo,
|
|
2158
2287
|
k,
|
|
2159
2288
|
N,
|
|
2160
2289
|
reachMemo,
|
|
@@ -381,6 +381,7 @@ test("7/8/9. buildStructuralVariants always includes exact-exact, left-synonym,
|
|
|
381
381
|
ra,
|
|
382
382
|
rb,
|
|
383
383
|
sides,
|
|
384
|
+
new Map(),
|
|
384
385
|
);
|
|
385
386
|
assert.equal(variants[0].kind, "exact-exact");
|
|
386
387
|
assert.equal(variants[0].semanticConfidence, 1);
|
|
@@ -410,7 +411,7 @@ test("11. synonym variants are bounded to haloQueryK, in addition to the always-
|
|
|
410
411
|
enc("crimson"),
|
|
411
412
|
enc("square"),
|
|
412
413
|
);
|
|
413
|
-
const { variants } = buildStructuralVariants(m, ra, rb, sides);
|
|
414
|
+
const { variants } = buildStructuralVariants(m, ra, rb, sides, new Map());
|
|
414
415
|
assert.ok(variants.length <= 1 + m.cfg.haloQueryK);
|
|
415
416
|
await m.store.close();
|
|
416
417
|
});
|
|
@@ -428,7 +429,7 @@ test("12. a sibling's structural part keeps the ORIGINAL query-region slot lengt
|
|
|
428
429
|
enc("crimson"),
|
|
429
430
|
enc("square"),
|
|
430
431
|
);
|
|
431
|
-
const { variants } = buildStructuralVariants(m, ra, rb, sides);
|
|
432
|
+
const { variants } = buildStructuralVariants(m, ra, rb, sides, new Map());
|
|
432
433
|
for (const v of variants) {
|
|
433
434
|
assert.equal(
|
|
434
435
|
v.left.len,
|
|
@@ -483,6 +484,7 @@ test("13/18. structuralResonance composes the real middle query bytes and applie
|
|
|
483
484
|
ra,
|
|
484
485
|
rb,
|
|
485
486
|
sides,
|
|
487
|
+
new Map(),
|
|
486
488
|
12,
|
|
487
489
|
N,
|
|
488
490
|
new Map(),
|
|
@@ -520,7 +522,7 @@ test("15. two variants proposing the SAME candidate keep only the higher-effecti
|
|
|
520
522
|
enc("crimson"),
|
|
521
523
|
enc("square"),
|
|
522
524
|
);
|
|
523
|
-
const { variants } = buildStructuralVariants(m, ra, rb, sides);
|
|
525
|
+
const { variants } = buildStructuralVariants(m, ra, rb, sides, new Map());
|
|
524
526
|
// Directly exercise the merge logic's contract: build two synthetic
|
|
525
527
|
// proposals for the SAME id with different effectiveScore and confirm the
|
|
526
528
|
// higher one is what a caller keeps (mirrors betterProposal's tie-break,
|
|
@@ -533,6 +535,7 @@ test("15. two variants proposing the SAME candidate keep only the higher-effecti
|
|
|
533
535
|
ra,
|
|
534
536
|
rb,
|
|
535
537
|
sides,
|
|
538
|
+
new Map(),
|
|
536
539
|
12,
|
|
537
540
|
N,
|
|
538
541
|
new Map(),
|