@hviana/sema 0.2.3 → 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/attention.d.ts +14 -2
- package/dist/src/mind/attention.js +54 -8
- package/dist/src/mind/bridge.d.ts +30 -0
- package/dist/src/mind/bridge.js +569 -0
- package/dist/src/mind/match.d.ts +15 -2
- package/dist/src/mind/match.js +3 -8
- package/dist/src/mind/mechanisms/cast.d.ts +54 -0
- package/dist/src/mind/mechanisms/cast.js +268 -37
- package/dist/src/mind/mechanisms/cover.js +16 -31
- package/dist/src/mind/mechanisms/recall.js +66 -0
- package/dist/src/mind/reasoning.d.ts +11 -0
- package/dist/src/mind/reasoning.js +58 -2
- package/dist/src/mind/recognition.js +127 -7
- package/dist/src/mind/traverse.js +16 -15
- package/dist/src/mind/types.d.ts +39 -2
- package/dist/src/mind/types.js +38 -7
- package/dist/src/store.d.ts +12 -3
- package/dist/src/store.js +9 -3
- package/package.json +1 -1
- package/src/mind/attention.ts +65 -7
- package/src/mind/bridge.ts +596 -0
- package/src/mind/match.ts +19 -5
- package/src/mind/mechanisms/cast.ts +290 -38
- package/src/mind/mechanisms/cover.ts +23 -36
- package/src/mind/mechanisms/recall.ts +79 -0
- package/src/mind/reasoning.ts +71 -2
- package/src/mind/recognition.ts +132 -7
- package/src/mind/traverse.ts +16 -17
- package/src/mind/types.ts +70 -6
- package/src/store.ts +19 -5
- 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
|
@@ -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[];
|
|
@@ -42,6 +51,8 @@ export declare function poolVotes(ctx: MindContext, regionVotes: readonly Region
|
|
|
42
51
|
/** Per-anchor SCALE-INVARIANT support: Σ RegionVote.absorbed over the
|
|
43
52
|
* distinct contributing regions — see Attention.breadth. */
|
|
44
53
|
regionSupport: Map<number, number>;
|
|
54
|
+
/** Per-anchor contributing region spans — see Attention.clusters. */
|
|
55
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
45
56
|
steps: DerivationStep[];
|
|
46
57
|
};
|
|
47
58
|
export declare function commitVotes(ctx: MindContext, pooled: {
|
|
@@ -53,6 +64,7 @@ export declare function commitVotes(ctx: MindContext, pooled: {
|
|
|
53
64
|
w: number;
|
|
54
65
|
}>;
|
|
55
66
|
regionSupport: Map<number, number>;
|
|
67
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
56
68
|
steps: DerivationStep[];
|
|
57
69
|
}, sat: SaturationInfo, regions: readonly Region[], regionVoter: ReadonlyArray<{
|
|
58
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;
|
|
@@ -401,6 +413,7 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
401
413
|
const votesIdf = new Map();
|
|
402
414
|
const support = new Map();
|
|
403
415
|
const regionSupport = new Map();
|
|
416
|
+
const regionSpans = new Map();
|
|
404
417
|
const steps = [];
|
|
405
418
|
let order = 0;
|
|
406
419
|
for (const pc of pool.values()) {
|
|
@@ -409,6 +422,7 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
409
422
|
const premises = [];
|
|
410
423
|
const seenRi = new Set();
|
|
411
424
|
let breadthSum = 0;
|
|
425
|
+
const spans = [];
|
|
412
426
|
for (const c of pc.contributions) {
|
|
413
427
|
const p0 = c.premises[0].item;
|
|
414
428
|
if (p0.kind !== "region" || seenRi.has(p0.ri))
|
|
@@ -417,8 +431,10 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
417
431
|
const rv = regionVotes[p0.ri];
|
|
418
432
|
breadthSum += rv.absorbed ?? 1;
|
|
419
433
|
premises.push({ kind: "form", span: [rv.start, rv.end] });
|
|
434
|
+
spans.push([rv.start, rv.end]);
|
|
420
435
|
}
|
|
421
436
|
regionSupport.set(pc.item.id, breadthSum);
|
|
437
|
+
regionSpans.set(pc.item.id, spans);
|
|
422
438
|
steps.push({
|
|
423
439
|
order: order++,
|
|
424
440
|
move: "pool-vote",
|
|
@@ -448,10 +464,39 @@ export function poolVotes(ctx, regionVotes, sat, N) {
|
|
|
448
464
|
}
|
|
449
465
|
}
|
|
450
466
|
}
|
|
451
|
-
return { votes, votesIdf, support, regionSupport, 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;
|
|
452
497
|
}
|
|
453
498
|
export function commitVotes(ctx, pooled, sat, regions, regionVoter, N) {
|
|
454
|
-
const { votes, votesIdf, support, regionSupport, steps } = pooled;
|
|
499
|
+
const { votes, votesIdf, support, regionSupport, regionSpans, steps } = pooled;
|
|
455
500
|
if (votes.size === 0) {
|
|
456
501
|
traceAttention(ctx, regions, regionVoter, [], steps);
|
|
457
502
|
return { roots: [], ranked: [] };
|
|
@@ -470,6 +515,7 @@ export function commitVotes(ctx, pooled, sat, regions, regionVoter, N) {
|
|
|
470
515
|
start: s.start,
|
|
471
516
|
end: s.end,
|
|
472
517
|
breadth: (regionSupport.get(anchor) ?? 0) / totalRegions,
|
|
518
|
+
clusters: countClusters(regionSpans.get(anchor) ?? [], ctx.space.maxGroup),
|
|
473
519
|
};
|
|
474
520
|
})
|
|
475
521
|
.sort((a, b) => b.vote - a.vote);
|
|
@@ -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 {};
|