@hviana/sema 0.3.0 → 0.4.0
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 +71 -5
- package/dist/src/derive/src/deduction.d.ts +12 -1
- package/dist/src/derive/src/deduction.js +5 -1
- package/dist/src/derive/src/index.d.ts +1 -0
- package/dist/src/geometry.d.ts +3 -30
- package/dist/src/geometry.js +330 -82
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/meter.d.ts +171 -0
- package/dist/src/meter.js +269 -0
- package/dist/src/mind/attention.d.ts +0 -4
- package/dist/src/mind/attention.js +251 -23
- package/dist/src/mind/bridge.d.ts +10 -1
- package/dist/src/mind/bridge.js +179 -10
- package/dist/src/mind/canonical.d.ts +6 -1
- package/dist/src/mind/canonical.js +6 -1
- package/dist/src/mind/graph-search.d.ts +9 -0
- package/dist/src/mind/graph-search.js +59 -19
- package/dist/src/mind/junction.d.ts +10 -0
- package/dist/src/mind/junction.js +14 -0
- package/dist/src/mind/match.d.ts +40 -0
- package/dist/src/mind/match.js +125 -1
- package/dist/src/mind/mechanisms/cast.js +63 -6
- package/dist/src/mind/mechanisms/extraction.d.ts +0 -34
- package/dist/src/mind/mechanisms/extraction.js +1 -88
- package/dist/src/mind/mechanisms/recall.d.ts +3 -0
- package/dist/src/mind/mechanisms/recall.js +77 -14
- package/dist/src/mind/mind.d.ts +55 -4
- package/dist/src/mind/mind.js +110 -91
- package/dist/src/mind/pipeline-mechanism.d.ts +33 -3
- package/dist/src/mind/pipeline-mechanism.js +179 -10
- package/dist/src/mind/pipeline.js +52 -10
- package/dist/src/mind/primitives.d.ts +11 -15
- package/dist/src/mind/primitives.js +47 -28
- package/dist/src/mind/reasoning.d.ts +7 -1
- package/dist/src/mind/reasoning.js +40 -8
- package/dist/src/mind/recognition.js +93 -20
- package/dist/src/mind/traverse.d.ts +11 -0
- package/dist/src/mind/traverse.js +58 -5
- package/dist/src/mind/types.d.ts +28 -5
- package/dist/src/store.d.ts +15 -0
- package/dist/src/store.js +91 -6
- package/package.json +1 -1
- package/src/derive/src/deduction.ts +15 -0
- package/src/derive/src/index.ts +1 -0
- package/src/geometry.ts +350 -122
- package/src/index.ts +1 -0
- package/src/meter.ts +333 -0
- package/src/mind/attention.ts +268 -31
- package/src/mind/bridge.ts +187 -10
- package/src/mind/canonical.ts +6 -1
- package/src/mind/graph-search.ts +60 -21
- package/src/mind/junction.ts +12 -0
- package/src/mind/match.ts +146 -1
- package/src/mind/mechanisms/cast.ts +62 -6
- package/src/mind/mechanisms/extraction.ts +2 -103
- package/src/mind/mechanisms/recall.ts +84 -17
- package/src/mind/mind.ts +139 -98
- package/src/mind/pipeline-mechanism.ts +203 -13
- package/src/mind/pipeline.ts +65 -8
- package/src/mind/primitives.ts +49 -33
- package/src/mind/reasoning.ts +39 -7
- package/src/mind/recognition.ts +89 -19
- package/src/mind/traverse.ts +59 -5
- package/src/mind/types.ts +28 -5
- package/src/store.ts +75 -6
- package/test/14-scaling.test.mjs +17 -7
- package/test/31-audit.test.mjs +4 -1
- package/test/33-multi-candidate.test.mjs +13 -1
- package/test/36-already-answered-fusion.test.mjs +10 -3
- package/test/46-recognise-multibyte-edge.test.mjs +3 -3
- package/test/53-cross-region-probe-instrumentation.test.mjs +36 -6
- package/test/55-cost-meter.test.mjs +284 -0
- package/test/56-bridge-identity-admission.test.mjs +209 -0
- package/test/57-fusion-order.test.mjs +104 -0
- package/test/58-subquantum-sites.test.mjs +112 -0
- package/test/59-fold-invariance.test.mjs +226 -0
|
@@ -12,7 +12,7 @@ import { composeStructuralGist, consensusFloor, dominates, estimatorNoise, } fro
|
|
|
12
12
|
import { foldTree, gistOf, latin1Key, perceive, read } from "./primitives.js";
|
|
13
13
|
import { recognise } from "./recognition.js";
|
|
14
14
|
import { leafIdRun } from "./canonical.js";
|
|
15
|
-
import { corpusN, edgeAncestors, hubBound } from "./traverse.js";
|
|
15
|
+
import { corpusN, edgeAncestors, hubBound, sharedReachMemo, } from "./traverse.js";
|
|
16
16
|
import { cachedRead, junctionContainersFrom, junctionSeeds, junctionSynonyms, loadJunctionSynonymSides, walkCache, } from "./junction.js";
|
|
17
17
|
import { indexOf } from "../bytes.js";
|
|
18
18
|
import { rItem, rNode, traceDerivation } from "./trace.js";
|
|
@@ -76,6 +76,8 @@ export async function climbAttentionAll(ctx, query, k, mode = "inverse") {
|
|
|
76
76
|
}
|
|
77
77
|
const hit = byRead.get(modeKey);
|
|
78
78
|
if (hit !== undefined) {
|
|
79
|
+
if (ctx.meter)
|
|
80
|
+
ctx.meter.climbHits++;
|
|
79
81
|
// Cache-hit exit (spec §9): the abbreviated payload shape — only what
|
|
80
82
|
// is actually stored in the cached AttentionRead is reported. No
|
|
81
83
|
// candidate, reach, saturation, pooling or anchor detail is fabricated
|
|
@@ -101,6 +103,8 @@ export async function climbAttentionAll(ctx, query, k, mode = "inverse") {
|
|
|
101
103
|
}
|
|
102
104
|
// ── Pipeline ──────────────────────────────────────────────────────────────
|
|
103
105
|
export async function computeAttention(ctx, query, k, mode) {
|
|
106
|
+
if (ctx.meter)
|
|
107
|
+
ctx.meter.climbs++;
|
|
104
108
|
const regions = collectRegions(ctx, query);
|
|
105
109
|
const perceivedCount = regions.length;
|
|
106
110
|
// Recognised sites carry structural evidence that perceived sub-regions
|
|
@@ -117,6 +121,22 @@ export async function computeAttention(ctx, query, k, mode) {
|
|
|
117
121
|
v: gistOf(ctx, query.subarray(s.start, s.end)),
|
|
118
122
|
start: s.start,
|
|
119
123
|
end: s.end,
|
|
124
|
+
// NOT a chunk — a precondition, not a judgement about the evidence.
|
|
125
|
+
// `chunk` admits a region into the saturated-INTERVAL builder (see
|
|
126
|
+
// crossRegionVotes), which walks regions as a SEQUENCE and merges
|
|
127
|
+
// neighbouring saturated ones into runs. Its own contract requires the
|
|
128
|
+
// regions it reads to be DISJOINT and in byte order — true of
|
|
129
|
+
// leaf-parents, false of sites, which overlap each other and the chunks
|
|
130
|
+
// ("red", "circle" and "red circle" are all present at once).
|
|
131
|
+
//
|
|
132
|
+
// Admitting them was measured both ways and is unprincipled in each
|
|
133
|
+
// direction: a saturated site EXTENDS a run and masks votes that should
|
|
134
|
+
// have won (test/37 lost all three — roots became "red " and "hat"
|
|
135
|
+
// instead of "red circle" and "2"), while a non-saturated one BREAKS a
|
|
136
|
+
// run and unmasks votes that should have been dropped, which is the only
|
|
137
|
+
// reason it appeared to fix test/34. Either way the outcome turns on
|
|
138
|
+
// where an overlapping span happens to fall in the array — the same
|
|
139
|
+
// positional accident this work exists to remove.
|
|
120
140
|
chunk: false,
|
|
121
141
|
known: true, // a recognised site IS a stored form
|
|
122
142
|
});
|
|
@@ -140,15 +160,25 @@ export async function computeAttention(ctx, query, k, mode) {
|
|
|
140
160
|
const N = corpusN(ctx);
|
|
141
161
|
// One climb per distinct anchor for the WHOLE query: regions sharing a
|
|
142
162
|
// chunk, and canonicalChunkId's prefix probes, all hit this memo instead of
|
|
143
|
-
// re-reading the anchor's full edge fan-out from the store.
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
// re-reading the anchor's full edge fan-out from the store. The memo is
|
|
164
|
+
// the SHARED one (traverse.ts) — response-scoped for respond(),
|
|
165
|
+
// conversation-scoped across turns, and the same map confluence prices
|
|
166
|
+
// commonality against; it used to be a private per-climb Map, so a
|
|
167
|
+
// conversation re-climbed its own repeated regions from cold on every
|
|
168
|
+
// turn. A traced response still gets a fresh one — see sharedReachMemo.
|
|
169
|
+
const reachMemo = sharedReachMemo(ctx);
|
|
170
|
+
const rvs = ctx.meter
|
|
171
|
+
? await ctx.meter.time("climb.voteRegions", () => voteRegions(ctx, query, regions, k, mode, N, reachMemo, td))
|
|
172
|
+
: await voteRegions(ctx, query, regions, k, mode, N, reachMemo, td);
|
|
146
173
|
// ── Cross-region: DIRECT region-to-region interaction ─────────────────
|
|
147
174
|
// Two regions whose individual climbs land on DIFFERENT contexts leave
|
|
148
175
|
// their JOINT context — the learnt whole that contains BOTH — with no
|
|
149
176
|
// vote. crossRegionVotes recovers it by the bridge's content-addressed
|
|
150
177
|
// junction ascent (see the note above the function).
|
|
151
|
-
const
|
|
178
|
+
const crossArgs = () => crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td);
|
|
179
|
+
const cross = ctx.meter
|
|
180
|
+
? await ctx.meter.time("climb.crossRegion", crossArgs)
|
|
181
|
+
: await crossArgs();
|
|
152
182
|
// A vote SUPERSEDED by exact joint evidence (its bytes literally live
|
|
153
183
|
// inside the joint container, yet it climbed elsewhere — grid aliasing)
|
|
154
184
|
// is dropped, not down-weighted: the joint container explains it away.
|
|
@@ -204,7 +234,17 @@ export function collectRegions(ctx, query) {
|
|
|
204
234
|
foldTree(ctx, perceive(ctx, query), 0, (n, start, end, node) => {
|
|
205
235
|
if (n.kids === null)
|
|
206
236
|
return;
|
|
207
|
-
|
|
237
|
+
// The dominance filter is about WRAPPERS, not about size. A chunk is the
|
|
238
|
+
// smallest grouped unit — it wraps no other region — so it can never be the
|
|
239
|
+
// "broad, non-discriminative wrapper" this rule exists to exclude, however
|
|
240
|
+
// much of a short query it happens to cover. Testing it by span alone was
|
|
241
|
+
// safe only while chunks were exactly W bytes: content-defined segments run
|
|
242
|
+
// up to the keyring's seat count, so on a 15-byte query the 8-byte segment
|
|
243
|
+
// "is frigi" counted as dominant and was discarded, leaving CAST one point
|
|
244
|
+
// of attention where it needs two (test/29 D1/D2). Composites are still
|
|
245
|
+
// filtered exactly as before.
|
|
246
|
+
if (isChunk(n) || !dominates(end - start, query.length) ||
|
|
247
|
+
regions.length === 0) {
|
|
208
248
|
regions.push({
|
|
209
249
|
v: n.v,
|
|
210
250
|
start,
|
|
@@ -213,15 +253,40 @@ export function collectRegions(ctx, query) {
|
|
|
213
253
|
known: node !== null,
|
|
214
254
|
});
|
|
215
255
|
}
|
|
256
|
+
// MEASURED AND REFUTED — subdividing a long segment into W-scale tiles.
|
|
257
|
+
// A content segment runs from W−1 up to the keyring's seat count (2W) and
|
|
258
|
+
// folds FLAT, so its only sub-units are single bytes; the grid's regions
|
|
259
|
+
// were always exactly W. Offering each segment's W-byte tiles as extra
|
|
260
|
+
// regions (gists only, no stored nodes, anchored on the segment's own
|
|
261
|
+
// content-defined start so invariance is kept) does restore that finer
|
|
262
|
+
// grain: on `How is ice like steel?` the climb went from ONE ranked anchor
|
|
263
|
+
// to three, and test/33's own CAST-candidate spread was recovered.
|
|
264
|
+
//
|
|
265
|
+
// It is still wrong, and net worse (measured: test/29 went 9/2 to 7/4).
|
|
266
|
+
// canonicalWindows governs EXACT identity lookup, which recognition
|
|
267
|
+
// already probes at every offset — it says nothing about the grain of an
|
|
268
|
+
// approximate gist, so "the write side's unit scale" was two machineries
|
|
269
|
+
// conflated. What the tiles actually do is reintroduce a fixed stride
|
|
270
|
+
// inside the segment, and the extra votes reorder the climb: on
|
|
271
|
+
// `How is Shakespeare like Leonardo da Vinci?` the short name deposits
|
|
272
|
+
// outranked the exemplar sentences, claimed their aligned runs first, and
|
|
273
|
+
// left the sentences CAST needs with no free run at all (C2, C3). A
|
|
274
|
+
// region must come from the fold, not from a stride over it.
|
|
216
275
|
});
|
|
217
276
|
return regions;
|
|
218
277
|
}
|
|
219
278
|
export async function voteRegions(ctx, query, regions, k, mode, N, reachMemo, td) {
|
|
279
|
+
if (ctx.meter)
|
|
280
|
+
ctx.meter.climbRegions += regions.length;
|
|
220
281
|
const regionSaturated = new Array(regions.length).fill(false);
|
|
221
282
|
const regionVotes = [];
|
|
222
283
|
const regionVoter = ctx.trace ? regions.map(() => null) : [];
|
|
284
|
+
const W = ctx.space.maxGroup;
|
|
223
285
|
for (let ri = 0; ri < regions.length; ri++) {
|
|
224
|
-
|
|
286
|
+
// `v`/`start`/`end` are rebindable: a long approximate segment may vote
|
|
287
|
+
// with the sub-span that actually carries its evidence — see below.
|
|
288
|
+
let { v, start, end } = regions[ri];
|
|
289
|
+
const { chunk, known } = regions[ri];
|
|
225
290
|
// Trace-only bookkeeping for this region — allocated only under `td`
|
|
226
291
|
// (i.e. only when ctx.trace is set); see ConsensusRegionTrace/
|
|
227
292
|
// RegionOutcome (spec §4). `examinedIds` tracks distinct ANN hits
|
|
@@ -262,10 +327,10 @@ export async function voteRegions(ctx, query, regions, k, mode, N, reachMemo, td
|
|
|
262
327
|
// the resonate() call for most exact regions — the single largest
|
|
263
328
|
// remaining inference sink — with the anchor choice unchanged (the
|
|
264
329
|
// canonical branch already ignored hits[0]).
|
|
265
|
-
|
|
330
|
+
let canonicalId = chunk
|
|
266
331
|
? canonicalChunkId(ctx, query.subarray(start, end), N, reachMemo)
|
|
267
332
|
: null;
|
|
268
|
-
|
|
333
|
+
let canonicalUsable = canonicalId !== null &&
|
|
269
334
|
(ctx.store.hasParents(canonicalId) ||
|
|
270
335
|
ctx.store.hasContainers(canonicalId));
|
|
271
336
|
let hits = null;
|
|
@@ -276,6 +341,74 @@ export async function voteRegions(ctx, query, regions, k, mode, N, reachMemo, td
|
|
|
276
341
|
}
|
|
277
342
|
return hits;
|
|
278
343
|
};
|
|
344
|
+
// A DILUTED SEGMENT VOTES WITH THE SPAN THAT CARRIES ITS EVIDENCE.
|
|
345
|
+
//
|
|
346
|
+
// A content segment runs up to the keyring's seat count and folds FLAT, so
|
|
347
|
+
// its gist superposes every one of its bytes: an entity inside a longer
|
|
348
|
+
// segment is averaged together with whatever scaffolding shares the
|
|
349
|
+
// segment, and the resonance reads the average. Measured on
|
|
350
|
+
// `How is ice like steel?` against a store holding `Steel is hard`: the
|
|
351
|
+
// segment `ike stee` resonates to `Ice is c` at 0.297 — the WRONG deposit —
|
|
352
|
+
// with `Steel ` fourth at 0.123, while the sub-span `stee` resonates to
|
|
353
|
+
// `Steel ` at 0.627. The evidence is there; the whole-segment read cannot
|
|
354
|
+
// see it, and `Steel is hard` received no vote at all (test/29 C1).
|
|
355
|
+
//
|
|
356
|
+
// Entered only after the EXACT path has already failed — a chunk with a
|
|
357
|
+
// usable canonical identity has a content-addressed handle on its own bytes
|
|
358
|
+
// and needs no estimator at all — so this is honest degradation, not extra
|
|
359
|
+
// work on regions that already resolved. The candidates are the segment's
|
|
360
|
+
// two EDGE sub-spans at the write side's own unit scale (W) — the scale
|
|
361
|
+
// `canonicalWindows` interns, and the only one at which a sub-span could
|
|
362
|
+
// carry a stored identity; a segment of W or less has no interior at all.
|
|
363
|
+
// Edges because a content cut lands INSIDE a unit, so the remnant it split
|
|
364
|
+
// sits against the cut: `steel` is cut after `stee`. Offering every
|
|
365
|
+
// interior offset instead was measured and is worse — it re-anchors
|
|
366
|
+
// segments on spans no boundary ever separated, and broke three of
|
|
367
|
+
// test/17's vote-distribution and root-count assertions (428/1 → 424/5).
|
|
368
|
+
//
|
|
369
|
+
// Selection is by the SAME quantity the region's vote is weighted by —
|
|
370
|
+
// score² · idf — never by score alone: the scaffolding window `is i`
|
|
371
|
+
// resonates at 0.832, far above `stee`, and is worth nothing because its
|
|
372
|
+
// reach is the whole corpus. Nothing new is being measured here; the
|
|
373
|
+
// choice the code did not previously make is made with the criterion it
|
|
374
|
+
// already uses. The region's SPAN narrows with its gist, so breadth,
|
|
375
|
+
// clusters and cross-region pairing all see where the evidence really sits.
|
|
376
|
+
if (!canonicalUsable && chunk && !known && end - start > W) {
|
|
377
|
+
const weigh = (h) => {
|
|
378
|
+
const r = edgeAncestors(ctx, h.id, N, reachMemo);
|
|
379
|
+
if (r.saturated || r.roots.length === 0)
|
|
380
|
+
return null;
|
|
381
|
+
const idf = Math.log(N / Math.max(1, r.contextsReached));
|
|
382
|
+
if (idf <= 0)
|
|
383
|
+
return null;
|
|
384
|
+
return { w: h.score * h.score * idf, id: h.id };
|
|
385
|
+
};
|
|
386
|
+
// The whole-segment candidate reuses the ranking the region needs
|
|
387
|
+
// anyway, so only the two edge probes are new work.
|
|
388
|
+
const scoreOf = async (gist) => {
|
|
389
|
+
const h = await ctx.store.resonate(gist, 1);
|
|
390
|
+
return h.length === 0 ? null : weigh(h[0]);
|
|
391
|
+
};
|
|
392
|
+
const h0 = await ensureHits();
|
|
393
|
+
let best = h0.length > 0 ? weigh(h0[0]) : null;
|
|
394
|
+
let bestSpan = null;
|
|
395
|
+
for (const s0 of [start, end - W]) {
|
|
396
|
+
const sub = gistOf(ctx, query.subarray(s0, s0 + W));
|
|
397
|
+
const cand = await scoreOf(sub);
|
|
398
|
+
if (cand !== null && (best === null || cand.w > best.w)) {
|
|
399
|
+
best = cand;
|
|
400
|
+
bestSpan = [s0, s0 + W, sub];
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (bestSpan !== null) {
|
|
404
|
+
[start, end, v] = bestSpan;
|
|
405
|
+
hits = null; // the whole-segment ranking no longer describes this span
|
|
406
|
+
canonicalId = canonicalChunkId(ctx, query.subarray(start, end), N, reachMemo);
|
|
407
|
+
canonicalUsable = canonicalId !== null &&
|
|
408
|
+
(ctx.store.hasParents(canonicalId) ||
|
|
409
|
+
ctx.store.hasContainers(canonicalId));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
279
412
|
const canonicalFailed = chunk && canonicalId === null;
|
|
280
413
|
let voterId;
|
|
281
414
|
let score;
|
|
@@ -542,6 +675,9 @@ export function poolVotes(ctx, regionVotes, sat, N, td) {
|
|
|
542
675
|
saturationMaskedVotes: regionVotes.length - eligible.length,
|
|
543
676
|
};
|
|
544
677
|
}
|
|
678
|
+
// The one hub bound (traverse.ts) — N here IS corpusN, threaded down from
|
|
679
|
+
// computeAttention. Read once, not per rule application.
|
|
680
|
+
const bound = hubBound(ctx);
|
|
545
681
|
const key = (it) => it.kind === "region"
|
|
546
682
|
? `r${it.ri}`
|
|
547
683
|
: it.kind === "anchor"
|
|
@@ -572,13 +708,14 @@ export function poolVotes(ctx, regionVotes, sat, N, td) {
|
|
|
572
708
|
// region's vote across its FULL corpus-sized fan-in yields O(corpus)
|
|
573
709
|
// rule applications per region and near-zero per-target weight anyway.
|
|
574
710
|
// Cap the redistribution at the first √N contexts (insertion order,
|
|
575
|
-
// the same convention chooseNext caps by).
|
|
576
|
-
|
|
711
|
+
// the same convention chooseNext caps by). Hoisted out of the
|
|
712
|
+
// generator: `rules` is invoked once per popped item, and this used to
|
|
713
|
+
// re-derive the bound on every one of them.
|
|
577
714
|
for (const r of rv.roots) {
|
|
578
715
|
// CAPPED read: only the first hubBound targets are ever credited, so
|
|
579
716
|
// only they are read — a common continuation's full reverse fan-in
|
|
580
717
|
// is corpus-sized and is never materialised.
|
|
581
|
-
const pv = ctx.store.prevFirst(r,
|
|
718
|
+
const pv = ctx.store.prevFirst(r, bound);
|
|
582
719
|
const isAnswer = pv.length > 0 && !ctx.store.hasNext(r);
|
|
583
720
|
const targets = isAnswer ? pv : [r];
|
|
584
721
|
for (const t of targets) {
|
|
@@ -622,7 +759,15 @@ export function poolVotes(ctx, regionVotes, sat, N, td) {
|
|
|
622
759
|
const rv = regionVotes[p0.ri];
|
|
623
760
|
breadthSum += rv.absorbed ?? 1;
|
|
624
761
|
premises.push({ kind: "form", span: [rv.start, rv.end] });
|
|
625
|
-
|
|
762
|
+
// A vote knows where its own evidence sits: `parts` when it stands on
|
|
763
|
+
// several separate places (a joint binding), the merged span
|
|
764
|
+
// otherwise. See RegionVote.parts.
|
|
765
|
+
if (rv.parts !== undefined) {
|
|
766
|
+
for (const [s, e] of rv.parts)
|
|
767
|
+
spans.push([s, e]);
|
|
768
|
+
}
|
|
769
|
+
else
|
|
770
|
+
spans.push([rv.start, rv.end]);
|
|
626
771
|
}
|
|
627
772
|
regionSupport.set(pc.item.id, breadthSum);
|
|
628
773
|
regionSpans.set(pc.item.id, spans);
|
|
@@ -870,15 +1015,40 @@ function sameRoots(a, b) {
|
|
|
870
1015
|
}
|
|
871
1016
|
export function canonicalChunkId(ctx, regionBytes, N, reachMemo) {
|
|
872
1017
|
const len = Math.min(regionBytes.length, ctx.space.maxGroup);
|
|
1018
|
+
// WHICH window anchors a region is decided by reach, not by position. This
|
|
1019
|
+
// used to return at the FIRST offset that matched, which was indistinguishable
|
|
1020
|
+
// from correct while every region was exactly W bytes — there was only one
|
|
1021
|
+
// offset. A content-defined segment is longer, and its first window is
|
|
1022
|
+
// whatever happens to start it: for "is frigi" that is " is ", pure
|
|
1023
|
+
// scaffolding, which reaches every context, saturates, and makes the whole
|
|
1024
|
+
// region ABSTAIN. The region's own content ("frigi") never got a say, and
|
|
1025
|
+
// CAST lost a point of attention it needed (test/29 D1/D2).
|
|
1026
|
+
//
|
|
1027
|
+
// So scan every offset and prefer an anchor that still discriminates: not
|
|
1028
|
+
// saturated, and among those the one reaching the FEWEST contexts (§2.7,
|
|
1029
|
+
// corpus-global). Only when every window in the region saturates does the
|
|
1030
|
+
// old generalising choice stand — there is then no discriminative anchor to
|
|
1031
|
+
// find, and abstaining is the honest outcome.
|
|
1032
|
+
let discId = null;
|
|
1033
|
+
let discReached = Infinity;
|
|
1034
|
+
let fallback = null;
|
|
873
1035
|
for (let off = 0; off + len <= regionBytes.length; off++) {
|
|
874
1036
|
const ids = leafIdRun(ctx, regionBytes, off, off + len);
|
|
1037
|
+
// An unknown byte disqualifies THIS window, not the region. This used to
|
|
1038
|
+
// abandon the whole region on the first unseen byte, which was
|
|
1039
|
+
// indistinguishable from correct while regions were exactly W bytes — there
|
|
1040
|
+
// was one window, so failing it was failing the region. A content-defined
|
|
1041
|
+
// segment holds several windows, and a single unknown byte near its start
|
|
1042
|
+
// was silently costing the region its anchor entirely.
|
|
875
1043
|
if (ids === null)
|
|
876
|
-
|
|
1044
|
+
continue;
|
|
877
1045
|
const flatId = ctx.store.findBranch(ids);
|
|
878
1046
|
if (flatId === null)
|
|
879
1047
|
continue;
|
|
880
1048
|
if (len < 2)
|
|
881
1049
|
return flatId;
|
|
1050
|
+
// Within one window, the widest reach is still the right CANONICAL
|
|
1051
|
+
// identity — a chunk's anchor should be its most general stable form.
|
|
882
1052
|
let bestId = flatId;
|
|
883
1053
|
let bestReach = edgeAncestors(ctx, flatId, N, reachMemo);
|
|
884
1054
|
for (let k2 = 1; k2 < len; k2++) {
|
|
@@ -893,9 +1063,18 @@ export function canonicalChunkId(ctx, regionBytes, N, reachMemo) {
|
|
|
893
1063
|
bestReach = shortReach;
|
|
894
1064
|
}
|
|
895
1065
|
}
|
|
896
|
-
|
|
1066
|
+
if (fallback === null)
|
|
1067
|
+
fallback = bestId;
|
|
1068
|
+
if (!bestReach.saturated && bestReach.contextsReached < discReached) {
|
|
1069
|
+
discId = bestId;
|
|
1070
|
+
discReached = bestReach.contextsReached;
|
|
1071
|
+
// Nothing can discriminate better than reaching ONE context, so the scan
|
|
1072
|
+
// stops there rather than pricing the rest of the segment's windows.
|
|
1073
|
+
if (discReached <= 1)
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
897
1076
|
}
|
|
898
|
-
return
|
|
1077
|
+
return discId ?? fallback;
|
|
899
1078
|
}
|
|
900
1079
|
export function naturalBreak(votes) {
|
|
901
1080
|
if (votes.length <= 1)
|
|
@@ -1082,6 +1261,15 @@ function betterProposal(a, b) {
|
|
|
1082
1261
|
* ANN-query each, merge proposals by candidate id, and validate the winner
|
|
1083
1262
|
* through the SAME structural gates every other tier answers to (saturation,
|
|
1084
1263
|
* roots, IDF, contrastive margin). Returns null when nothing survives. */
|
|
1264
|
+
/** {@link structuralResonance}, charged to its own profiling phase — it is
|
|
1265
|
+
* the halo-mediated arm of the cross-region ladder and the one part of it
|
|
1266
|
+
* that resonates. */
|
|
1267
|
+
async function meteredStructuralResonance(...args) {
|
|
1268
|
+
const ctx = args[0];
|
|
1269
|
+
return ctx.meter
|
|
1270
|
+
? await ctx.meter.time("climb.structuralResonance", () => structuralResonance(...args))
|
|
1271
|
+
: await structuralResonance(...args);
|
|
1272
|
+
}
|
|
1085
1273
|
export async function structuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo,
|
|
1086
1274
|
/** Each side's OWN individual climb roots (from voteRegions), when it cast
|
|
1087
1275
|
* one — the self-evidence backstop structural-resonance needs and the
|
|
@@ -1246,7 +1434,19 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1246
1434
|
// one side is always individually discriminative.
|
|
1247
1435
|
//
|
|
1248
1436
|
// Only MAXIMAL spans compose: a span contained in another candidate is a
|
|
1249
|
-
// fragment of that candidate's evidence, never independent of it
|
|
1437
|
+
// fragment of that candidate's evidence, never independent of it — but
|
|
1438
|
+
// containment alone does not establish that relation. An APPROXIMATE
|
|
1439
|
+
// container (a fold segment whose gist merely resonated) does not hold the
|
|
1440
|
+
// evidence of an EXACT one (a recognised site, content-addressed): its
|
|
1441
|
+
// bytes straddle the site rather than explain it, so calling the site a
|
|
1442
|
+
// fragment of it discards the only exact reading of those bytes. Measured:
|
|
1443
|
+
// on `blue then square` the segment `blue t` swallowed the site `blue`,
|
|
1444
|
+
// leaving one candidate and no pair, while on `red then circle` the
|
|
1445
|
+
// segment happened to end at `red `'s edge and the same query shape
|
|
1446
|
+
// composed — the outcome turned on where a cut fell. This is the same
|
|
1447
|
+
// discipline the between-region gate below already states: an approximate
|
|
1448
|
+
// region climbing "somewhere" is ordinary noise, not evidence.
|
|
1449
|
+
//
|
|
1250
1450
|
// Shared across every cross-region probe in this climb: a sibling
|
|
1251
1451
|
// successfully reconstructed while probing one pair must not be read and
|
|
1252
1452
|
// perceived again while probing another pair in the same climb.
|
|
@@ -1271,7 +1471,8 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1271
1471
|
const cand = eligible.filter((x) => !eligible.some((y) => y !== x &&
|
|
1272
1472
|
regions[y].start <= regions[x].start &&
|
|
1273
1473
|
regions[x].end <= regions[y].end &&
|
|
1274
|
-
regions[y].end - regions[y].start > regions[x].end - regions[x].start
|
|
1474
|
+
regions[y].end - regions[y].start > regions[x].end - regions[x].start &&
|
|
1475
|
+
(regions[y].known || !regions[x].known)));
|
|
1275
1476
|
const none = { votes: [], superseded: new Set() };
|
|
1276
1477
|
if (td) {
|
|
1277
1478
|
td.crossRegionSummary = {
|
|
@@ -1499,7 +1700,7 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1499
1700
|
}
|
|
1500
1701
|
const ownRootsA = rvs.votes.find((v) => v.start === ra.start && v.end === ra.end)?.roots;
|
|
1501
1702
|
const ownRootsB = rvs.votes.find((v) => v.start === rb.start && v.end === rb.end)?.roots;
|
|
1502
|
-
structuralPick = await
|
|
1703
|
+
structuralPick = await meteredStructuralResonance(ctx, query, ra, rb, sides, siblingGistMemo, k, N, reachMemo, ownRootsA, ownRootsB, resonanceTrace);
|
|
1503
1704
|
}
|
|
1504
1705
|
if (structuralPick === null) {
|
|
1505
1706
|
pushProbe(reasons.length > 0 ? "resonance-ineligible" : "resonance-rejected");
|
|
@@ -1649,10 +1850,27 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1649
1850
|
spanStart = Math.min(spanStart, regions[ei].start);
|
|
1650
1851
|
spanEnd = Math.max(spanEnd, regions[ei].end);
|
|
1651
1852
|
}
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1853
|
+
// CONSUMPTION IS FOR CONTAINER-BACKED EVIDENCE ONLY. Consuming a
|
|
1854
|
+
// candidate says "its evidence is already composed at full joint
|
|
1855
|
+
// strength, re-pairing it would vote the same container twice" — a
|
|
1856
|
+
// claim only a real container can make. A structural-resonance pick
|
|
1857
|
+
// has none (see above: it is NOT a Junction), so consuming its
|
|
1858
|
+
// endpoints locks up candidates on the strength of an ANN guess and
|
|
1859
|
+
// stops genuine evidence from ever composing them. Measured: on
|
|
1860
|
+
// `greet reply-greet then red then circle` the pair
|
|
1861
|
+
// `reply-greet` ▸ `red` resonated to `red square` and consumed `red`,
|
|
1862
|
+
// after which `red` ▸ `circle` was never probed and the exact junction
|
|
1863
|
+
// `red circle` — a stored whole, sitting right there — went unfound.
|
|
1864
|
+
// This is spec §15's asymmetry (only exact DAG evidence may explain
|
|
1865
|
+
// ordinary votes away) applied to the other way a tier can silence
|
|
1866
|
+
// evidence. Both votes now stand and pooling decides between them,
|
|
1867
|
+
// which is what the mechanism market is for.
|
|
1868
|
+
if (structuralPick === null) {
|
|
1869
|
+
consumed.add(cand[a]);
|
|
1870
|
+
consumed.add(cand[b]);
|
|
1871
|
+
for (const ei of bestExtras)
|
|
1872
|
+
consumed.add(ei);
|
|
1873
|
+
}
|
|
1656
1874
|
// EXPLAINING AWAY — see the block comment above the function. Byte
|
|
1657
1875
|
// containment in the joint container is the relatedness test (the
|
|
1658
1876
|
// vote's bytes are literally part of the learnt whole), and FULL root
|
|
@@ -1700,6 +1918,16 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo, td) {
|
|
|
1700
1918
|
w,
|
|
1701
1919
|
wFocus: w,
|
|
1702
1920
|
absorbed: 1 + explainedAway,
|
|
1921
|
+
// The places this junction actually stands on — its two endpoints and
|
|
1922
|
+
// any N-ary extras, NOT the merged span [spanStart, spanEnd], which
|
|
1923
|
+
// swallows the gap and reads as one neighbourhood. See
|
|
1924
|
+
// RegionVote.parts.
|
|
1925
|
+
parts: [cand[a], cand[b], ...bestExtras]
|
|
1926
|
+
.map((ri) => [
|
|
1927
|
+
regions[ri].start,
|
|
1928
|
+
regions[ri].end,
|
|
1929
|
+
])
|
|
1930
|
+
.sort((x, y) => x[0] - y[0]),
|
|
1703
1931
|
});
|
|
1704
1932
|
pushProbe("accepted");
|
|
1705
1933
|
if (td) {
|
|
@@ -26,5 +26,14 @@ export interface BridgeHit {
|
|
|
26
26
|
export declare function dismissedKnownContent(ctx: MindContext, query: Uint8Array, spans: ReadonlyArray<readonly [number, number]>): boolean;
|
|
27
27
|
/** Recall's corroborated-substitution bridge — see the module comment.
|
|
28
28
|
* Returns the best bridged grounding proposal, or null. */
|
|
29
|
-
|
|
29
|
+
/** `proposed` is a THUNK, not a list: the bridge's own cheap gates (the
|
|
30
|
+
* two-quantum query floor and the O(|query|) stored-window anchor scan)
|
|
31
|
+
* decide whether ANY candidate can be aligned, and they need no proposals
|
|
32
|
+
* to do it. Resolving the caller's proposals eagerly meant recall paid its
|
|
33
|
+
* exhaustive whole-index resonance — the most expensive single act on the
|
|
34
|
+
* refusal path — for every query, including the ones whose windows the
|
|
35
|
+
* store has never seen and which the anchor scan rejects outright. Same
|
|
36
|
+
* investment discipline the mechanism floors follow (AGENTS §2.6): never
|
|
37
|
+
* compute a shared analysis just to discard it. */
|
|
38
|
+
export declare function substitutionBridge(ctx: MindContext, query: Uint8Array, proposed?: () => Promise<ReadonlyArray<number>>): Promise<BridgeHit | null>;
|
|
30
39
|
export {};
|