@hviana/sema 0.2.2 → 0.2.4
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/dist/src/mind/articulation.js +1 -1
- package/dist/src/mind/attention.d.ts +18 -2
- package/dist/src/mind/attention.js +88 -18
- package/dist/src/mind/bridge.d.ts +30 -0
- package/dist/src/mind/bridge.js +569 -0
- package/dist/src/mind/graph-search.d.ts +16 -1
- package/dist/src/mind/graph-search.js +34 -5
- package/dist/src/mind/match.d.ts +15 -2
- package/dist/src/mind/match.js +3 -8
- package/dist/src/mind/mechanisms/alu.js +8 -1
- package/dist/src/mind/mechanisms/cast.d.ts +54 -0
- package/dist/src/mind/mechanisms/cast.js +303 -48
- package/dist/src/mind/mechanisms/cover.js +24 -32
- package/dist/src/mind/mechanisms/extraction.js +75 -30
- package/dist/src/mind/mechanisms/recall.js +66 -0
- package/dist/src/mind/mind.d.ts +1 -0
- package/dist/src/mind/mind.js +6 -1
- package/dist/src/mind/pipeline.js +34 -2
- package/dist/src/mind/reasoning.d.ts +20 -1
- package/dist/src/mind/reasoning.js +84 -6
- package/dist/src/mind/recognition.js +157 -13
- package/dist/src/mind/traverse.js +16 -0
- package/dist/src/mind/types.d.ts +65 -2
- package/dist/src/mind/types.js +53 -7
- package/dist/src/store.d.ts +12 -3
- package/dist/src/store.js +9 -3
- package/package.json +1 -1
- package/src/mind/articulation.ts +1 -0
- package/src/mind/attention.ts +105 -17
- package/src/mind/bridge.ts +596 -0
- package/src/mind/graph-search.ts +59 -2
- package/src/mind/match.ts +19 -5
- package/src/mind/mechanisms/alu.ts +8 -1
- package/src/mind/mechanisms/cast.ts +336 -46
- package/src/mind/mechanisms/cover.ts +31 -36
- package/src/mind/mechanisms/extraction.ts +101 -40
- package/src/mind/mechanisms/recall.ts +79 -0
- package/src/mind/mind.ts +7 -1
- package/src/mind/pipeline.ts +37 -2
- package/src/mind/reasoning.ts +97 -5
- package/src/mind/recognition.ts +160 -12
- package/src/mind/traverse.ts +17 -0
- package/src/mind/types.ts +110 -6
- package/src/store.ts +19 -5
- package/test/35-attention-confidence.test.mjs +139 -0
- package/test/36-already-answered-fusion.test.mjs +128 -0
- package/test/37-cluster-dispersion-fusion.test.mjs +190 -0
- package/test/38-reason-restate-guard.test.mjs +94 -0
- package/test/39-cast-restate-guard.test.mjs +102 -0
- package/test/40-choosenext-scale-guard.test.mjs +75 -0
- package/test/41-seatofnode-direction.test.mjs +85 -0
- package/test/42-recognise-trace-idempotence.test.mjs +106 -0
- package/test/43-cast-analog-seat.test.mjs +244 -0
- package/test/44-recognise-edge-whitespace.test.mjs +63 -0
- package/test/45-liftanswer-restated-trim.test.mjs +60 -0
- package/test/46-recognise-multibyte-edge.test.mjs +85 -0
- package/test/47-cast-comparison-coverage.test.mjs +134 -0
- package/test/48-recognise-turn-connective.test.mjs +125 -0
- package/test/49-natural-units-synonym-bridge.test.mjs +175 -0
- package/test/50-cast-analog-consensus-floor.test.mjs +179 -0
|
@@ -83,7 +83,7 @@ export async function articulate(ctx, answer, query) {
|
|
|
83
83
|
s.end,
|
|
84
84
|
])),
|
|
85
85
|
]);
|
|
86
|
-
const solved = ctx.search.cover(answer.length, voicedSites, new Map(), ans.leaves, ans.splits, substitutions, undefined, undefined, ctx.trace ? (steps) => traceDerivation(ctx, steps) : undefined);
|
|
86
|
+
const solved = ctx.search.cover(answer.length, voicedSites, new Map(), ans.leaves, ans.splits, ans.starts, substitutions, undefined, undefined, ctx.trace ? (steps) => traceDerivation(ctx, steps) : undefined);
|
|
87
87
|
const segs = solved && solved.segs;
|
|
88
88
|
tArtCover?.done(segs === null
|
|
89
89
|
? []
|
|
@@ -5,8 +5,17 @@ import type { AncestorReach, Attention, AttentionRead, DFMode, MindContext, Regi
|
|
|
5
5
|
* attention — those that cleared commitVotes' significance floor. */
|
|
6
6
|
export declare function climbAttention(ctx: MindContext, query: Uint8Array, k: number, mode?: DFMode): Promise<Attention[]>;
|
|
7
7
|
/** Full read-out of one consensus climb: both the roots (dominant points of
|
|
8
|
-
* attention) and the entire ranked list. Cached via ctx.climbMemo
|
|
9
|
-
*
|
|
8
|
+
* attention) and the entire ranked list. Cached via ctx.climbMemo, ALWAYS —
|
|
9
|
+
* see {@link recognise} for why this memo (and recognise()'s own) must
|
|
10
|
+
* never be skipped while tracing: computeAttention's collectRegions walks
|
|
11
|
+
* the query's perceived tree via the same foldTree whose subtree-resolution
|
|
12
|
+
* fast path makes a second call on identical bytes non-idempotent once
|
|
13
|
+
* ctx._resolvedSubtrees is warm (which a multi-turn conversation's shared
|
|
14
|
+
* prefix subtrees guarantee by the second turn). A cache hit still emits
|
|
15
|
+
* a trace step — abbreviated, since the full per-sub-region voting detail
|
|
16
|
+
* {@link traceAttention} builds isn't preserved by the cached read-out —
|
|
17
|
+
* so a traced response is never silently blacked out for a repeated
|
|
18
|
+
* query. */
|
|
10
19
|
export declare function climbAttentionAll(ctx: MindContext, query: Uint8Array, k: number, mode?: DFMode): Promise<AttentionRead>;
|
|
11
20
|
export declare function computeAttention(ctx: MindContext, query: Uint8Array, k: number, mode: DFMode): Promise<AttentionRead>;
|
|
12
21
|
export declare function collectRegions(ctx: MindContext, query: Uint8Array): Region[];
|
|
@@ -39,6 +48,11 @@ export declare function poolVotes(ctx: MindContext, regionVotes: readonly Region
|
|
|
39
48
|
end: number;
|
|
40
49
|
w: number;
|
|
41
50
|
}>;
|
|
51
|
+
/** Per-anchor SCALE-INVARIANT support: Σ RegionVote.absorbed over the
|
|
52
|
+
* distinct contributing regions — see Attention.breadth. */
|
|
53
|
+
regionSupport: Map<number, number>;
|
|
54
|
+
/** Per-anchor contributing region spans — see Attention.clusters. */
|
|
55
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
42
56
|
steps: DerivationStep[];
|
|
43
57
|
};
|
|
44
58
|
export declare function commitVotes(ctx: MindContext, pooled: {
|
|
@@ -49,6 +63,8 @@ export declare function commitVotes(ctx: MindContext, pooled: {
|
|
|
49
63
|
end: number;
|
|
50
64
|
w: number;
|
|
51
65
|
}>;
|
|
66
|
+
regionSupport: Map<number, number>;
|
|
67
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
52
68
|
steps: DerivationStep[];
|
|
53
69
|
}, sat: SaturationInfo, regions: readonly Region[], regionVoter: ReadonlyArray<{
|
|
54
70
|
id: number;
|
|
@@ -15,7 +15,7 @@ import { leafIdRun } from "./canonical.js";
|
|
|
15
15
|
import { corpusN, edgeAncestors } from "./traverse.js";
|
|
16
16
|
import { cachedRead, junctionContainersFrom, junctionSeeds, junctionSynonyms, walkCache, } from "./junction.js";
|
|
17
17
|
import { indexOf } from "../bytes.js";
|
|
18
|
-
import { rNode, traceDerivation } from "./trace.js";
|
|
18
|
+
import { rItem, rNode, traceDerivation } from "./trace.js";
|
|
19
19
|
// ── Public entry points ───────────────────────────────────────────────────
|
|
20
20
|
/** Climb the query's perceived byte regions up the structural DAG via
|
|
21
21
|
* resonance, pool the evidence, and return only the ROOT points of
|
|
@@ -24,12 +24,21 @@ export async function climbAttention(ctx, query, k, mode = "inverse") {
|
|
|
24
24
|
return (await climbAttentionAll(ctx, query, k, mode)).roots;
|
|
25
25
|
}
|
|
26
26
|
/** Full read-out of one consensus climb: both the roots (dominant points of
|
|
27
|
-
* attention) and the entire ranked list. Cached via ctx.climbMemo
|
|
28
|
-
*
|
|
27
|
+
* attention) and the entire ranked list. Cached via ctx.climbMemo, ALWAYS —
|
|
28
|
+
* see {@link recognise} for why this memo (and recognise()'s own) must
|
|
29
|
+
* never be skipped while tracing: computeAttention's collectRegions walks
|
|
30
|
+
* the query's perceived tree via the same foldTree whose subtree-resolution
|
|
31
|
+
* fast path makes a second call on identical bytes non-idempotent once
|
|
32
|
+
* ctx._resolvedSubtrees is warm (which a multi-turn conversation's shared
|
|
33
|
+
* prefix subtrees guarantee by the second turn). A cache hit still emits
|
|
34
|
+
* a trace step — abbreviated, since the full per-sub-region voting detail
|
|
35
|
+
* {@link traceAttention} builds isn't preserved by the cached read-out —
|
|
36
|
+
* so a traced response is never silently blacked out for a repeated
|
|
37
|
+
* query. */
|
|
29
38
|
export async function climbAttentionAll(ctx, query, k, mode = "inverse") {
|
|
30
39
|
// Content-keyed memo — works for both single-turn respond() and multi-turn
|
|
31
|
-
// respondTurn().
|
|
32
|
-
if (ctx.climbMemo
|
|
40
|
+
// respondTurn().
|
|
41
|
+
if (ctx.climbMemo) {
|
|
33
42
|
const contentKey = latin1Key(query);
|
|
34
43
|
const modeKey = `${k}:${mode}`;
|
|
35
44
|
let byRead = ctx.climbMemo.get(contentKey);
|
|
@@ -37,8 +46,11 @@ export async function climbAttentionAll(ctx, query, k, mode = "inverse") {
|
|
|
37
46
|
ctx.climbMemo.set(contentKey, byRead = new Map());
|
|
38
47
|
}
|
|
39
48
|
const hit = byRead.get(modeKey);
|
|
40
|
-
if (hit !== undefined)
|
|
49
|
+
if (hit !== undefined) {
|
|
50
|
+
ctx.trace?.step("climbConsensus", [rItem(query, "query")], hit.roots.map((r) => rNode(ctx, r.anchor, "anchor", r.vote)), `(cached) consensus already computed for this query — ` +
|
|
51
|
+
`${hit.roots.length} point(s) of attention`);
|
|
41
52
|
return hit;
|
|
53
|
+
}
|
|
42
54
|
const read = await computeAttention(ctx, query, k, mode);
|
|
43
55
|
byRead.set(modeKey, read);
|
|
44
56
|
return read;
|
|
@@ -400,6 +412,8 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
400
412
|
const votes = new Map();
|
|
401
413
|
const votesIdf = new Map();
|
|
402
414
|
const support = new Map();
|
|
415
|
+
const regionSupport = new Map();
|
|
416
|
+
const regionSpans = new Map();
|
|
403
417
|
const steps = [];
|
|
404
418
|
let order = 0;
|
|
405
419
|
for (const pc of pool.values()) {
|
|
@@ -407,14 +421,20 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
407
421
|
votes.set(pc.item.id, pc.cost);
|
|
408
422
|
const premises = [];
|
|
409
423
|
const seenRi = new Set();
|
|
424
|
+
let breadthSum = 0;
|
|
425
|
+
const spans = [];
|
|
410
426
|
for (const c of pc.contributions) {
|
|
411
427
|
const p0 = c.premises[0].item;
|
|
412
428
|
if (p0.kind !== "region" || seenRi.has(p0.ri))
|
|
413
429
|
continue;
|
|
414
430
|
seenRi.add(p0.ri);
|
|
415
431
|
const rv = regionVotes[p0.ri];
|
|
432
|
+
breadthSum += rv.absorbed ?? 1;
|
|
416
433
|
premises.push({ kind: "form", span: [rv.start, rv.end] });
|
|
434
|
+
spans.push([rv.start, rv.end]);
|
|
417
435
|
}
|
|
436
|
+
regionSupport.set(pc.item.id, breadthSum);
|
|
437
|
+
regionSpans.set(pc.item.id, spans);
|
|
418
438
|
steps.push({
|
|
419
439
|
order: order++,
|
|
420
440
|
move: "pool-vote",
|
|
@@ -444,18 +464,59 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
444
464
|
}
|
|
445
465
|
}
|
|
446
466
|
}
|
|
447
|
-
return { votes, votesIdf, support, steps };
|
|
467
|
+
return { votes, votesIdf, support, regionSupport, regionSpans, steps };
|
|
468
|
+
}
|
|
469
|
+
/** The number of DISTINCT clusters a root's contributing regions form —
|
|
470
|
+
* see Attention.clusters. Two regions belong to the same cluster iff the
|
|
471
|
+
* gap between them is strictly less than one river-fold quantum W: at
|
|
472
|
+
* that distance there is no room for a genuinely separate, independently
|
|
473
|
+
* perceivable unit of content between them (the same "smallest meaningful
|
|
474
|
+
* distinction" quantum {@link reachThreshold}'s own doc invokes). A gap
|
|
475
|
+
* of a full quantum or more means real, separate structure could sit
|
|
476
|
+
* between the two spans, so they count as independent corroboration.
|
|
477
|
+
* Strict `<` (not `<=`): verified against gap 3.1's own "gender equality"
|
|
478
|
+
* root, whose two genuine clusters sit EXACTLY W bytes apart — `<= W`
|
|
479
|
+
* would wrongly merge them into one and break that pinned requirement. */
|
|
480
|
+
function countClusters(spans, W) {
|
|
481
|
+
if (spans.length === 0)
|
|
482
|
+
return 0;
|
|
483
|
+
const sorted = [...spans].sort((a, b) => a[0] - b[0]);
|
|
484
|
+
let clusters = 1;
|
|
485
|
+
let curEnd = sorted[0][1];
|
|
486
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
487
|
+
const [s, e] = sorted[i];
|
|
488
|
+
if (s - curEnd < W) {
|
|
489
|
+
curEnd = Math.max(curEnd, e);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
clusters++;
|
|
493
|
+
curEnd = e;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return clusters;
|
|
448
497
|
}
|
|
449
498
|
export function commitVotes(ctx, pooled, sat, regions, regionVoter, N) {
|
|
450
|
-
const { votes, votesIdf, support, steps } = pooled;
|
|
499
|
+
const { votes, votesIdf, support, regionSupport, regionSpans, steps } = pooled;
|
|
451
500
|
if (votes.size === 0) {
|
|
452
501
|
traceAttention(ctx, regions, regionVoter, [], steps);
|
|
453
502
|
return { roots: [], ranked: [] };
|
|
454
503
|
}
|
|
504
|
+
// SCALE-INVARIANT confidence — see Attention.breadth's doc. regions.length
|
|
505
|
+
// is the query's OWN full candidate count (most never vote at all), the
|
|
506
|
+
// same denominator the "N of M sub-regions voted" rationale text already
|
|
507
|
+
// reports; regionSupport is that same accounting read PER ANCHOR.
|
|
508
|
+
const totalRegions = Math.max(1, regions.length);
|
|
455
509
|
const ranked = [...votes.entries()]
|
|
456
510
|
.map(([anchor, vote]) => {
|
|
457
511
|
const s = support.get(anchor);
|
|
458
|
-
return {
|
|
512
|
+
return {
|
|
513
|
+
anchor,
|
|
514
|
+
vote,
|
|
515
|
+
start: s.start,
|
|
516
|
+
end: s.end,
|
|
517
|
+
breadth: (regionSupport.get(anchor) ?? 0) / totalRegions,
|
|
518
|
+
clusters: countClusters(regionSpans.get(anchor) ?? [], ctx.space.maxGroup),
|
|
519
|
+
};
|
|
459
520
|
})
|
|
460
521
|
.sort((a, b) => b.vote - a.vote);
|
|
461
522
|
const overlaps = (a, b) => a.start < b.end && b.start < a.end;
|
|
@@ -855,14 +916,6 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo) {
|
|
|
855
916
|
spanStart = Math.min(spanStart, regions[ei].start);
|
|
856
917
|
spanEnd = Math.max(spanEnd, regions[ei].end);
|
|
857
918
|
}
|
|
858
|
-
out.push({
|
|
859
|
-
start: spanStart,
|
|
860
|
-
end: spanEnd,
|
|
861
|
-
canonicalFailed: false, // content-addressed: never saturation-masked
|
|
862
|
-
roots: reach.roots,
|
|
863
|
-
w,
|
|
864
|
-
wFocus: w,
|
|
865
|
-
});
|
|
866
919
|
consumed.add(cand[a]);
|
|
867
920
|
consumed.add(cand[b]);
|
|
868
921
|
for (const ei of bestExtras)
|
|
@@ -872,15 +925,32 @@ async function crossRegionVotes(ctx, query, regions, rvs, k, N, reachMemo) {
|
|
|
872
925
|
// vote's bytes are literally part of the learnt whole), and FULL root
|
|
873
926
|
// disjointness is the disagreement test: a vote sharing even one root
|
|
874
927
|
// with the junction corroborates it and keeps its say elsewhere.
|
|
928
|
+
// Counted BEFORE pushing the junction's own vote below: each ORIGINAL
|
|
929
|
+
// region this ascent explains away is evidence the junction speaks
|
|
930
|
+
// for, not evidence lost — `absorbed` (RegionVote's breadth-accounting
|
|
931
|
+
// field) must credit the junction with all of it, not just the ONE
|
|
932
|
+
// pooled axiom it collapses to.
|
|
875
933
|
const containerBytes = cachedRead(ctx, cache, best.id, cap);
|
|
876
934
|
const jointRoots = new Set(reach.roots);
|
|
935
|
+
let explainedAway = 0;
|
|
877
936
|
for (const rv of rvs.votes) {
|
|
878
937
|
if (rv.roots.some((r) => jointRoots.has(r)))
|
|
879
938
|
continue;
|
|
880
939
|
const bytes = query.subarray(rv.start, rv.end);
|
|
881
|
-
if (indexOf(containerBytes, bytes, 0) >= 0)
|
|
940
|
+
if (indexOf(containerBytes, bytes, 0) >= 0 && !superseded.has(rv)) {
|
|
882
941
|
superseded.add(rv);
|
|
942
|
+
explainedAway++;
|
|
943
|
+
}
|
|
883
944
|
}
|
|
945
|
+
out.push({
|
|
946
|
+
start: spanStart,
|
|
947
|
+
end: spanEnd,
|
|
948
|
+
canonicalFailed: false, // content-addressed: never saturation-masked
|
|
949
|
+
roots: reach.roots,
|
|
950
|
+
w,
|
|
951
|
+
wFocus: w,
|
|
952
|
+
absorbed: 1 + explainedAway,
|
|
953
|
+
});
|
|
884
954
|
const label = [cand[a], cand[b], ...bestExtras]
|
|
885
955
|
.sort((x, y) => regions[x].start - regions[y].start)
|
|
886
956
|
.map((ri) => dec(query.subarray(regions[ri].start, regions[ri].end)))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { MindContext } from "./types.js";
|
|
2
|
+
/** One accepted substitution: query span [qs,qe) stands in for the
|
|
3
|
+
* candidate context's span — recorded for the rationale trace. */
|
|
4
|
+
interface Substitution {
|
|
5
|
+
qs: number;
|
|
6
|
+
qe: number;
|
|
7
|
+
cs: number;
|
|
8
|
+
ce: number;
|
|
9
|
+
}
|
|
10
|
+
/** A bridged grounding proposal: the trained context to ground, the query
|
|
11
|
+
* spans its alignment accounts for, and the substitutions that closed it. */
|
|
12
|
+
export interface BridgeHit {
|
|
13
|
+
id: number;
|
|
14
|
+
accounted: Array<[number, number]>;
|
|
15
|
+
subs: Substitution[];
|
|
16
|
+
}
|
|
17
|
+
/** True when some query byte-range left UNACCOUNTED by `spans` contains a
|
|
18
|
+
* STORED window — content the store has seen that the proposed reading
|
|
19
|
+
* simply ignores. The IGNORED-KNOWN principle: a span may be dismissed
|
|
20
|
+
* only when the store itself has never seen it; known content the
|
|
21
|
+
* alignment failed to account for is grounds for refusal, while genuinely
|
|
22
|
+
* novel spans (an untrained word, stray punctuation) remain tolerable.
|
|
23
|
+
* Shared by the substitution bridge's own acceptance and CAST's
|
|
24
|
+
* frame-tier comparison gate (cast.ts). Pure attestation — no
|
|
25
|
+
* similarity, no constants. */
|
|
26
|
+
export declare function dismissedKnownContent(ctx: MindContext, query: Uint8Array, spans: ReadonlyArray<readonly [number, number]>): boolean;
|
|
27
|
+
/** Recall's corroborated-substitution bridge — see the module comment.
|
|
28
|
+
* Returns the best bridged grounding proposal, or null. */
|
|
29
|
+
export declare function substitutionBridge(ctx: MindContext, query: Uint8Array, proposed?: ReadonlyArray<number>): Promise<BridgeHit | null>;
|
|
30
|
+
export {};
|