@hviana/sema 0.2.7 → 0.2.8
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
|
|
@@ -360,8 +361,12 @@ export interface StructuralResonanceProposal {
|
|
|
360
361
|
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
361
362
|
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
362
363
|
* synonym variants (single- and double-synonym combined, one shared
|
|
363
|
-
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
364
|
-
|
|
364
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
365
|
+
* Variant selection is entirely lightweight (see {@link
|
|
366
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
367
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
368
|
+
* climb via `siblingGistMemo`. */
|
|
369
|
+
export declare function buildStructuralVariants(ctx: MindContext, ra: Region, rb: Region, sides: JunctionSynonymSides, siblingGistMemo: Map<number, Vec>): {
|
|
365
370
|
variants: StructuralVariant[];
|
|
366
371
|
exactLeft: StructuralPart;
|
|
367
372
|
exactRight: StructuralPart;
|
|
@@ -370,7 +375,7 @@ export declare function buildStructuralVariants(ctx: MindContext, ra: Region, rb
|
|
|
370
375
|
* ANN-query each, merge proposals by candidate id, and validate the winner
|
|
371
376
|
* through the SAME structural gates every other tier answers to (saturation,
|
|
372
377
|
* 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>,
|
|
378
|
+
export declare function structuralResonance(ctx: MindContext, query: Uint8Array, ra: Region, rb: Region, sides: JunctionSynonymSides, siblingGistMemo: Map<number, Vec>, k: number, N: number, reachMemo: Map<number, AncestorReach>,
|
|
374
379
|
/** Each side's OWN individual climb roots (from voteRegions), when it cast
|
|
375
380
|
* one — the self-evidence backstop structural-resonance needs and the
|
|
376
381
|
* exact tier gets for free from literal byte containment (§11's whole
|
|
@@ -916,67 +916,94 @@ 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 — a sibling rejected here for being too
|
|
966
|
+
* large for THIS pair's phrase-scale bound may still be admissible for a
|
|
967
|
+
* larger-spanning pair later, so a rejection is never memoized globally.
|
|
968
|
+
* `localMemo` is scoped to one `buildStructuralVariants` call, where every
|
|
969
|
+
* variant shares the same bound, so a `null` there is safe to reuse. */
|
|
970
|
+
function loadBoundedSiblingGist(ctx, id, maxBytes, positiveMemo, localMemo) {
|
|
971
|
+
if (localMemo.has(id)) {
|
|
972
|
+
return localMemo.get(id) ?? null;
|
|
973
|
+
}
|
|
974
|
+
const cached = positiveMemo.get(id);
|
|
975
|
+
if (cached !== undefined) {
|
|
976
|
+
localMemo.set(id, cached);
|
|
977
|
+
return cached;
|
|
978
|
+
}
|
|
979
|
+
const length = ctx.store.contentLen(id, maxBytes + 1);
|
|
980
|
+
if (length <= 0 || length > maxBytes) {
|
|
981
|
+
localMemo.set(id, null);
|
|
982
|
+
return null;
|
|
983
|
+
}
|
|
984
|
+
const bytes = read(ctx, id, maxBytes + 1);
|
|
985
|
+
if (bytes.length === 0 || bytes.length > maxBytes) {
|
|
986
|
+
localMemo.set(id, null);
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
const gist = gistOf(ctx, bytes);
|
|
990
|
+
positiveMemo.set(id, gist);
|
|
991
|
+
localMemo.set(id, gist);
|
|
992
|
+
return gist;
|
|
993
|
+
}
|
|
994
|
+
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
995
|
+
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
996
|
+
* synonym variants (single- and double-synonym combined, one shared
|
|
997
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
998
|
+
* Variant selection is entirely lightweight (see {@link
|
|
999
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
1000
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
1001
|
+
* climb via `siblingGistMemo`. */
|
|
1002
|
+
export function buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo) {
|
|
1003
|
+
const leftLen = ra.end - ra.start;
|
|
1004
|
+
const rightLen = rb.end - rb.start;
|
|
1005
|
+
const exactLeft = { v: ra.v, len: leftLen };
|
|
1006
|
+
const exactRight = { v: rb.v, len: rightLen };
|
|
980
1007
|
const variants = [
|
|
981
1008
|
{
|
|
982
1009
|
left: exactLeft,
|
|
@@ -984,8 +1011,43 @@ export function buildStructuralVariants(ctx, ra, rb, sides) {
|
|
|
984
1011
|
kind: "exact-exact",
|
|
985
1012
|
semanticConfidence: 1,
|
|
986
1013
|
},
|
|
987
|
-
...synonymVariants.slice(0, ctx.cfg.haloQueryK),
|
|
988
1014
|
];
|
|
1015
|
+
// Same phrase-scale bound the cross-region junction ladder uses
|
|
1016
|
+
// (`maxInterior`): a sibling whose complete stored content exceeds it is
|
|
1017
|
+
// not materialized as a structural-resonance endpoint, keeping sibling
|
|
1018
|
+
// reconstruction phrase-scale even for a large deposit or conversation
|
|
1019
|
+
// root that merely appeared in a halo result.
|
|
1020
|
+
const maxSiblingBytes = (leftLen + rightLen) * ctx.space.maxGroup;
|
|
1021
|
+
const specs = buildStructuralVariantSpecs(sides);
|
|
1022
|
+
const localGistMemo = new Map();
|
|
1023
|
+
let retainedSynonyms = 0;
|
|
1024
|
+
for (const spec of specs) {
|
|
1025
|
+
if (retainedSynonyms >= ctx.cfg.haloQueryK)
|
|
1026
|
+
break;
|
|
1027
|
+
let left = exactLeft;
|
|
1028
|
+
let right = exactRight;
|
|
1029
|
+
if (spec.leftSiblingId !== undefined) {
|
|
1030
|
+
const gist = loadBoundedSiblingGist(ctx, spec.leftSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
|
|
1031
|
+
if (gist === null)
|
|
1032
|
+
continue;
|
|
1033
|
+
left = { v: gist, len: leftLen };
|
|
1034
|
+
}
|
|
1035
|
+
if (spec.rightSiblingId !== undefined) {
|
|
1036
|
+
const gist = loadBoundedSiblingGist(ctx, spec.rightSiblingId, maxSiblingBytes, siblingGistMemo, localGistMemo);
|
|
1037
|
+
if (gist === null)
|
|
1038
|
+
continue;
|
|
1039
|
+
right = { v: gist, len: rightLen };
|
|
1040
|
+
}
|
|
1041
|
+
variants.push({
|
|
1042
|
+
left,
|
|
1043
|
+
right,
|
|
1044
|
+
kind: spec.kind,
|
|
1045
|
+
semanticConfidence: spec.semanticConfidence,
|
|
1046
|
+
leftSiblingId: spec.leftSiblingId,
|
|
1047
|
+
rightSiblingId: spec.rightSiblingId,
|
|
1048
|
+
});
|
|
1049
|
+
retainedSynonyms++;
|
|
1050
|
+
}
|
|
989
1051
|
return { variants, exactLeft, exactRight };
|
|
990
1052
|
}
|
|
991
1053
|
/** Deterministic best-of tie-break for two proposals ranked for the SAME
|
|
@@ -1012,7 +1074,7 @@ function betterProposal(a, b) {
|
|
|
1012
1074
|
* ANN-query each, merge proposals by candidate id, and validate the winner
|
|
1013
1075
|
* through the SAME structural gates every other tier answers to (saturation,
|
|
1014
1076
|
* roots, IDF, contrastive margin). Returns null when nothing survives. */
|
|
1015
|
-
export async function structuralResonance(ctx, query, ra, rb, sides, k, N, reachMemo,
|
|
1077
|
+
export async function structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo,
|
|
1016
1078
|
/** Each side's OWN individual climb roots (from voteRegions), when it cast
|
|
1017
1079
|
* one — the self-evidence backstop structural-resonance needs and the
|
|
1018
1080
|
* exact tier gets for free from literal byte containment (§11's whole
|
|
@@ -1021,7 +1083,7 @@ export async function structuralResonance(ctx, query, ra, rb, sides, k, N, reach
|
|
|
1021
1083
|
* evidence of a joint whole; it is that side's resonance rediscovering
|
|
1022
1084
|
* itself through a synthetic gist still dominated by its own direction. */
|
|
1023
1085
|
ownRootsA, ownRootsB, trace) {
|
|
1024
|
-
const { variants } = buildStructuralVariants(ctx, ra, rb, sides);
|
|
1086
|
+
const { variants } = buildStructuralVariants(ctx, ra, rb, sides, siblingGistMemo);
|
|
1025
1087
|
if (trace)
|
|
1026
1088
|
trace.variantBudget = ctx.cfg.haloQueryK;
|
|
1027
1089
|
const middleBytes = query.subarray(ra.end, rb.start);
|
|
@@ -1177,6 +1239,10 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1177
1239
|
//
|
|
1178
1240
|
// Only MAXIMAL spans compose: a span contained in another candidate is a
|
|
1179
1241
|
// fragment of that candidate's evidence, never independent of it.
|
|
1242
|
+
// Shared across every cross-region probe in this climb: a sibling
|
|
1243
|
+
// successfully reconstructed while probing one pair must not be read and
|
|
1244
|
+
// perceived again while probing another pair in the same climb.
|
|
1245
|
+
const siblingGistMemo = new Map();
|
|
1180
1246
|
const votedSpans = new Set();
|
|
1181
1247
|
for (const rv of rvs.votes)
|
|
1182
1248
|
votedSpans.add(`${rv.start},${rv.end}`);
|
|
@@ -1425,7 +1491,7 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1425
1491
|
}
|
|
1426
1492
|
const ownRootsA = rvs.votes.find((v) => v.start === ra.start && v.end === ra.end)?.roots;
|
|
1427
1493
|
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);
|
|
1494
|
+
structuralPick = await structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo, ownRootsA, ownRootsB, resonanceTrace);
|
|
1429
1495
|
}
|
|
1430
1496
|
if (structuralPick === null) {
|
|
1431
1497
|
pushProbe(reasons.length > 0 ? "resonance-ineligible" : "resonance-rejected");
|
package/package.json
CHANGED
package/src/mind/attention.ts
CHANGED
|
@@ -1549,86 +1549,137 @@ 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
1559
|
}
|
|
1560
1560
|
|
|
1561
|
-
/**
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1564
|
-
function
|
|
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;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/** A halo sibling's structural gist, bounded to `maxBytes` of stored content
|
|
1617
|
+
* and reused across the whole climb. `positiveMemo` (shared across every
|
|
1618
|
+
* probe in the climb, passed in by the caller) remembers only successfully
|
|
1619
|
+
* reconstructed complete gists — a sibling rejected here for being too
|
|
1620
|
+
* large for THIS pair's phrase-scale bound may still be admissible for a
|
|
1621
|
+
* larger-spanning pair later, so a rejection is never memoized globally.
|
|
1622
|
+
* `localMemo` is scoped to one `buildStructuralVariants` call, where every
|
|
1623
|
+
* variant shares the same bound, so a `null` there is safe to reuse. */
|
|
1624
|
+
function loadBoundedSiblingGist(
|
|
1565
1625
|
ctx: MindContext,
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1626
|
+
id: number,
|
|
1627
|
+
maxBytes: number,
|
|
1628
|
+
positiveMemo: Map<number, Vec>,
|
|
1629
|
+
localMemo: Map<number, Vec | null>,
|
|
1630
|
+
): Vec | null {
|
|
1631
|
+
if (localMemo.has(id)) {
|
|
1632
|
+
return localMemo.get(id) ?? null;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
const cached = positiveMemo.get(id);
|
|
1636
|
+
if (cached !== undefined) {
|
|
1637
|
+
localMemo.set(id, cached);
|
|
1638
|
+
return cached;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
const length = ctx.store.contentLen(id, maxBytes + 1);
|
|
1642
|
+
if (length <= 0 || length > maxBytes) {
|
|
1643
|
+
localMemo.set(id, null);
|
|
1644
|
+
return null;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
const bytes = read(ctx, id, maxBytes + 1);
|
|
1648
|
+
if (bytes.length === 0 || bytes.length > maxBytes) {
|
|
1649
|
+
localMemo.set(id, null);
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
const gist = gistOf(ctx, bytes);
|
|
1654
|
+
positiveMemo.set(id, gist);
|
|
1655
|
+
localMemo.set(id, gist);
|
|
1656
|
+
return gist;
|
|
1573
1657
|
}
|
|
1574
1658
|
|
|
1575
1659
|
/** Build, bound and order every mandatory structural variant (§7-8): the
|
|
1576
1660
|
* exact/exact composition is always kept; up to `ctx.cfg.haloQueryK`
|
|
1577
1661
|
* synonym variants (single- and double-synonym combined, one shared
|
|
1578
|
-
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
1662
|
+
* budget) are appended, ordered by confidence, then kind, then sibling id.
|
|
1663
|
+
* Variant selection is entirely lightweight (see {@link
|
|
1664
|
+
* buildStructuralVariantSpecs}); a sibling's bytes are read and perceived
|
|
1665
|
+
* only for specs actually retained, and at most once per sibling id per
|
|
1666
|
+
* climb via `siblingGistMemo`. */
|
|
1579
1667
|
export function buildStructuralVariants(
|
|
1580
1668
|
ctx: MindContext,
|
|
1581
1669
|
ra: Region,
|
|
1582
1670
|
rb: Region,
|
|
1583
1671
|
sides: JunctionSynonymSides,
|
|
1672
|
+
siblingGistMemo: Map<number, Vec>,
|
|
1584
1673
|
): {
|
|
1585
1674
|
variants: StructuralVariant[];
|
|
1586
1675
|
exactLeft: StructuralPart;
|
|
1587
1676
|
exactRight: StructuralPart;
|
|
1588
1677
|
} {
|
|
1589
|
-
const
|
|
1590
|
-
const
|
|
1591
|
-
|
|
1592
|
-
const synonymVariants: StructuralVariant[] = [];
|
|
1593
|
-
for (const ls of sides.leftSiblings) {
|
|
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
|
-
}
|
|
1678
|
+
const leftLen = ra.end - ra.start;
|
|
1679
|
+
const rightLen = rb.end - rb.start;
|
|
1623
1680
|
|
|
1624
|
-
|
|
1625
|
-
|
|
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
|
-
);
|
|
1681
|
+
const exactLeft: StructuralPart = { v: ra.v, len: leftLen };
|
|
1682
|
+
const exactRight: StructuralPart = { v: rb.v, len: rightLen };
|
|
1632
1683
|
|
|
1633
1684
|
const variants: StructuralVariant[] = [
|
|
1634
1685
|
{
|
|
@@ -1637,8 +1688,60 @@ export function buildStructuralVariants(
|
|
|
1637
1688
|
kind: "exact-exact",
|
|
1638
1689
|
semanticConfidence: 1,
|
|
1639
1690
|
},
|
|
1640
|
-
...synonymVariants.slice(0, ctx.cfg.haloQueryK),
|
|
1641
1691
|
];
|
|
1692
|
+
|
|
1693
|
+
// Same phrase-scale bound the cross-region junction ladder uses
|
|
1694
|
+
// (`maxInterior`): a sibling whose complete stored content exceeds it is
|
|
1695
|
+
// not materialized as a structural-resonance endpoint, keeping sibling
|
|
1696
|
+
// reconstruction phrase-scale even for a large deposit or conversation
|
|
1697
|
+
// root that merely appeared in a halo result.
|
|
1698
|
+
const maxSiblingBytes = (leftLen + rightLen) * ctx.space.maxGroup;
|
|
1699
|
+
|
|
1700
|
+
const specs = buildStructuralVariantSpecs(sides);
|
|
1701
|
+
const localGistMemo = new Map<number, Vec | null>();
|
|
1702
|
+
let retainedSynonyms = 0;
|
|
1703
|
+
|
|
1704
|
+
for (const spec of specs) {
|
|
1705
|
+
if (retainedSynonyms >= ctx.cfg.haloQueryK) break;
|
|
1706
|
+
|
|
1707
|
+
let left = exactLeft;
|
|
1708
|
+
let right = exactRight;
|
|
1709
|
+
|
|
1710
|
+
if (spec.leftSiblingId !== undefined) {
|
|
1711
|
+
const gist = loadBoundedSiblingGist(
|
|
1712
|
+
ctx,
|
|
1713
|
+
spec.leftSiblingId,
|
|
1714
|
+
maxSiblingBytes,
|
|
1715
|
+
siblingGistMemo,
|
|
1716
|
+
localGistMemo,
|
|
1717
|
+
);
|
|
1718
|
+
if (gist === null) continue;
|
|
1719
|
+
left = { v: gist, len: leftLen };
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
if (spec.rightSiblingId !== undefined) {
|
|
1723
|
+
const gist = loadBoundedSiblingGist(
|
|
1724
|
+
ctx,
|
|
1725
|
+
spec.rightSiblingId,
|
|
1726
|
+
maxSiblingBytes,
|
|
1727
|
+
siblingGistMemo,
|
|
1728
|
+
localGistMemo,
|
|
1729
|
+
);
|
|
1730
|
+
if (gist === null) continue;
|
|
1731
|
+
right = { v: gist, len: rightLen };
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
variants.push({
|
|
1735
|
+
left,
|
|
1736
|
+
right,
|
|
1737
|
+
kind: spec.kind,
|
|
1738
|
+
semanticConfidence: spec.semanticConfidence,
|
|
1739
|
+
leftSiblingId: spec.leftSiblingId,
|
|
1740
|
+
rightSiblingId: spec.rightSiblingId,
|
|
1741
|
+
});
|
|
1742
|
+
retainedSynonyms++;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1642
1745
|
return { variants, exactLeft, exactRight };
|
|
1643
1746
|
}
|
|
1644
1747
|
|
|
@@ -1675,6 +1778,7 @@ export async function structuralResonance(
|
|
|
1675
1778
|
ra: Region,
|
|
1676
1779
|
rb: Region,
|
|
1677
1780
|
sides: JunctionSynonymSides,
|
|
1781
|
+
siblingGistMemo: Map<number, Vec>,
|
|
1678
1782
|
k: number,
|
|
1679
1783
|
N: number,
|
|
1680
1784
|
reachMemo: Map<number, AncestorReach>,
|
|
@@ -1692,7 +1796,13 @@ export async function structuralResonance(
|
|
|
1692
1796
|
| { proposal: StructuralResonanceProposal; reach: AncestorReach; idf: number }
|
|
1693
1797
|
| null
|
|
1694
1798
|
> {
|
|
1695
|
-
const { variants } = buildStructuralVariants(
|
|
1799
|
+
const { variants } = buildStructuralVariants(
|
|
1800
|
+
ctx,
|
|
1801
|
+
ra,
|
|
1802
|
+
rb,
|
|
1803
|
+
sides,
|
|
1804
|
+
siblingGistMemo,
|
|
1805
|
+
);
|
|
1696
1806
|
if (trace) trace.variantBudget = ctx.cfg.haloQueryK;
|
|
1697
1807
|
|
|
1698
1808
|
const middleBytes = query.subarray(ra.end, rb.start);
|
|
@@ -1864,6 +1974,10 @@ async function crossRegionVotes(
|
|
|
1864
1974
|
//
|
|
1865
1975
|
// Only MAXIMAL spans compose: a span contained in another candidate is a
|
|
1866
1976
|
// fragment of that candidate's evidence, never independent of it.
|
|
1977
|
+
// Shared across every cross-region probe in this climb: a sibling
|
|
1978
|
+
// successfully reconstructed while probing one pair must not be read and
|
|
1979
|
+
// perceived again while probing another pair in the same climb.
|
|
1980
|
+
const siblingGistMemo = new Map<number, Vec>();
|
|
1867
1981
|
const votedSpans = new Set<string>();
|
|
1868
1982
|
for (const rv of rvs.votes) votedSpans.add(`${rv.start},${rv.end}`);
|
|
1869
1983
|
const seen = new Set<string>();
|
|
@@ -2155,6 +2269,7 @@ async function crossRegionVotes(
|
|
|
2155
2269
|
ra,
|
|
2156
2270
|
rb,
|
|
2157
2271
|
sides,
|
|
2272
|
+
siblingGistMemo,
|
|
2158
2273
|
k,
|
|
2159
2274
|
N,
|
|
2160
2275
|
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(),
|