@hviana/sema 0.9.1 → 0.9.2
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/meter.d.ts +13 -0
- package/dist/src/meter.js +13 -0
- package/dist/src/mind/evidence.d.ts +24 -0
- package/dist/src/mind/evidence.js +90 -0
- package/dist/src/mind/mechanisms/cover.js +41 -3
- package/dist/src/mind/mechanisms/recall.js +10 -2
- package/dist/src/mind/mind.d.ts +6 -0
- package/dist/src/mind/mind.js +3 -0
- package/dist/src/mind/pipeline.js +46 -4
- package/dist/src/mind/reasoning.js +43 -8
- package/dist/src/mind/traverse.d.ts +42 -2
- package/dist/src/mind/traverse.js +282 -5
- package/dist/src/mind/types.d.ts +9 -0
- package/docs/INDEX.md +18 -17
- package/docs/INVARIANTS.md +1 -0
- package/docs/architecture/evidence.md +113 -0
- package/docs/architecture/exact-vs-approximate.md +10 -9
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/meter.ts +13 -0
- package/src/mind/evidence.ts +107 -0
- package/src/mind/mechanisms/cover.ts +58 -3
- package/src/mind/mechanisms/recall.ts +16 -2
- package/src/mind/mind.ts +4 -0
- package/src/mind/pipeline.ts +59 -4
- package/src/mind/reasoning.ts +54 -7
- package/src/mind/traverse.ts +318 -5
- package/src/mind/types.ts +6 -0
- package/test/154-the-question-names-the-step.test.mjs +281 -0
package/dist/src/meter.d.ts
CHANGED
|
@@ -197,6 +197,19 @@ export declare class Meter {
|
|
|
197
197
|
/** Times the reasoner pivoted on a span its answer contains and stepped
|
|
198
198
|
* across that fact. */
|
|
199
199
|
pivotSteps: number;
|
|
200
|
+
/** `chooseNext` picks the question NAMED — a continuation one of whose own
|
|
201
|
+
* establishing contexts the question (plus the node) wholly witnesses
|
|
202
|
+
* (traverse.ts, the exact tier). */
|
|
203
|
+
askedContinuations: number;
|
|
204
|
+
/** Predecessor rows that exact tier read, against its shared √N budget. */
|
|
205
|
+
askedPredecessorReads: number;
|
|
206
|
+
/** Times the tier abstained on a read it could not trust: the continuations
|
|
207
|
+
* came back at the √N cap, or its predecessor budget ran out before every
|
|
208
|
+
* continuation was asked about — the distributional ladder decided. */
|
|
209
|
+
askedReadsSaturated: number;
|
|
210
|
+
/** Cover sites dropped as FRAGMENTS whose several continuations the question
|
|
211
|
+
* names none of (mechanisms/cover.ts). */
|
|
212
|
+
unaskedFragments: number;
|
|
200
213
|
/** Canon probes REFUSED because the canon budget ran out — the one thing the
|
|
201
214
|
* budget does that nothing could see. The budget itself is derived
|
|
202
215
|
* (`bytes.length · chainReach(W)²`, recognition.ts), and the cheap exact route
|
package/dist/src/meter.js
CHANGED
|
@@ -207,6 +207,19 @@ export class Meter {
|
|
|
207
207
|
/** Times the reasoner pivoted on a span its answer contains and stepped
|
|
208
208
|
* across that fact. */
|
|
209
209
|
pivotSteps = 0;
|
|
210
|
+
/** `chooseNext` picks the question NAMED — a continuation one of whose own
|
|
211
|
+
* establishing contexts the question (plus the node) wholly witnesses
|
|
212
|
+
* (traverse.ts, the exact tier). */
|
|
213
|
+
askedContinuations = 0;
|
|
214
|
+
/** Predecessor rows that exact tier read, against its shared √N budget. */
|
|
215
|
+
askedPredecessorReads = 0;
|
|
216
|
+
/** Times the tier abstained on a read it could not trust: the continuations
|
|
217
|
+
* came back at the √N cap, or its predecessor budget ran out before every
|
|
218
|
+
* continuation was asked about — the distributional ladder decided. */
|
|
219
|
+
askedReadsSaturated = 0;
|
|
220
|
+
/** Cover sites dropped as FRAGMENTS whose several continuations the question
|
|
221
|
+
* names none of (mechanisms/cover.ts). */
|
|
222
|
+
unaskedFragments = 0;
|
|
210
223
|
/** Canon probes REFUSED because the canon budget ran out — the one thing the
|
|
211
224
|
* budget does that nothing could see. The budget itself is derived
|
|
212
225
|
* (`bytes.length · chainReach(W)²`, recognition.ts), and the cheap exact route
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Where each W-window of one source first occurs. Built once per source and
|
|
2
|
+
* reused across every form asked against it. */
|
|
3
|
+
export type WindowIndex = Map<string, number>;
|
|
4
|
+
export declare function windowIndex(bytes: Uint8Array, W: number): WindowIndex;
|
|
5
|
+
/** The windows of `index` (over `bytes`) that `spoken` does not hold — what
|
|
6
|
+
* of the question no product of the derivation has restated yet. The keys
|
|
7
|
+
* keep their positions in `bytes`, so a witnessing span still names the
|
|
8
|
+
* asker's bytes. */
|
|
9
|
+
export declare function unspoken(index: WindowIndex, spoken: ReadonlyArray<WindowIndex>): WindowIndex;
|
|
10
|
+
/** How a form is witnessed by a list of sources. */
|
|
11
|
+
export interface Witnessing {
|
|
12
|
+
/** Every byte of the form lies in a window some source holds. */
|
|
13
|
+
complete: boolean;
|
|
14
|
+
/** The windows SOURCE 0 alone supplied — windows no later source holds — as
|
|
15
|
+
* merged spans of source 0. With the question as source 0, this is what the
|
|
16
|
+
* asker said about the form that the derivation did not already have. */
|
|
17
|
+
spans: Array<[number, number]>;
|
|
18
|
+
/** Bytes of source 0 inside `spans`. */
|
|
19
|
+
bytes: number;
|
|
20
|
+
}
|
|
21
|
+
/** Witness `form` against `sources` (their window indexes, same order). A
|
|
22
|
+
* window is credited to the LAST source holding it — so source 0 is credited
|
|
23
|
+
* only with what nothing else at hand supplies. */
|
|
24
|
+
export declare function witness(form: Uint8Array, indexes: ReadonlyArray<WindowIndex>, W: number): Witnessing;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// evidence.ts — what of a stored form the material at hand WITNESSES.
|
|
2
|
+
//
|
|
3
|
+
// A stored form is WITNESSED by some material when every one of its bytes lies
|
|
4
|
+
// inside a W-window that occurs literally in that material — in any order, at
|
|
5
|
+
// any place. It is the order-free reading of correspondence (`alignRuns` is
|
|
6
|
+
// its run-producing sibling, `junctionContainersFrom(…, unordered)` its
|
|
7
|
+
// container-finding one): a learnt form is evidenced by bytes that hold all of
|
|
8
|
+
// its windows, whichever way the asker happened to arrange them.
|
|
9
|
+
//
|
|
10
|
+
// The material is a LIST of sources because what a derivation has at hand is
|
|
11
|
+
// more than the question: the node it stands on is material too. A trained
|
|
12
|
+
// question `Edmond T. Gréville place of death` is in neither the asker's
|
|
13
|
+
// `Where was the place of death of the director of film Beat Girl?` nor the
|
|
14
|
+
// fact `The director of Beat Girl is Edmond T. Gréville.` the first hop reached
|
|
15
|
+
// — and both together hold every byte of it. The witness records which source
|
|
16
|
+
// held each window, so a consumer can tell the question's share (what the asker
|
|
17
|
+
// SAID about the form) from what the derivation itself brought.
|
|
18
|
+
//
|
|
19
|
+
// Exact, deterministic and linear: one window index per source, one probe per
|
|
20
|
+
// window of the form. Below one window a byte agreement is chance (the floor
|
|
21
|
+
// identityBar, attestedQ and the site test all draw), so a form shorter than W
|
|
22
|
+
// is never witnessed.
|
|
23
|
+
//
|
|
24
|
+
// Layering: bytes only — importable from traverse.ts and everything above it.
|
|
25
|
+
import { latin1 } from "../bytes.js";
|
|
26
|
+
export function windowIndex(bytes, W) {
|
|
27
|
+
const index = new Map();
|
|
28
|
+
for (let o = 0; o + W <= bytes.length; o++) {
|
|
29
|
+
const key = latin1(bytes.subarray(o, o + W));
|
|
30
|
+
if (!index.has(key))
|
|
31
|
+
index.set(key, o);
|
|
32
|
+
}
|
|
33
|
+
return index;
|
|
34
|
+
}
|
|
35
|
+
/** The windows of `index` (over `bytes`) that `spoken` does not hold — what
|
|
36
|
+
* of the question no product of the derivation has restated yet. The keys
|
|
37
|
+
* keep their positions in `bytes`, so a witnessing span still names the
|
|
38
|
+
* asker's bytes. */
|
|
39
|
+
export function unspoken(index, spoken) {
|
|
40
|
+
const out = new Map();
|
|
41
|
+
for (const [key, at] of index) {
|
|
42
|
+
if (!spoken.some((s) => s.has(key)))
|
|
43
|
+
out.set(key, at);
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
/** Witness `form` against `sources` (their window indexes, same order). A
|
|
48
|
+
* window is credited to the LAST source holding it — so source 0 is credited
|
|
49
|
+
* only with what nothing else at hand supplies. */
|
|
50
|
+
export function witness(form, indexes, W) {
|
|
51
|
+
const none = { complete: false, spans: [], bytes: 0 };
|
|
52
|
+
if (form.length < W || indexes.length === 0)
|
|
53
|
+
return none;
|
|
54
|
+
const covered = new Uint8Array(form.length);
|
|
55
|
+
const own = [];
|
|
56
|
+
for (let o = 0; o + W <= form.length; o++) {
|
|
57
|
+
const key = latin1(form.subarray(o, o + W));
|
|
58
|
+
let at = -1;
|
|
59
|
+
let from = -1;
|
|
60
|
+
for (let s = indexes.length - 1; s >= 0; s--) {
|
|
61
|
+
const p = indexes[s].get(key);
|
|
62
|
+
if (p !== undefined) {
|
|
63
|
+
at = p;
|
|
64
|
+
from = s;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (from < 0)
|
|
69
|
+
continue;
|
|
70
|
+
covered.fill(1, o, o + W);
|
|
71
|
+
if (from === 0)
|
|
72
|
+
own.push([at, at + W]);
|
|
73
|
+
}
|
|
74
|
+
for (let i = 0; i < form.length; i++)
|
|
75
|
+
if (!covered[i])
|
|
76
|
+
return none;
|
|
77
|
+
own.sort((a, b) => a[0] - b[0]);
|
|
78
|
+
const spans = [];
|
|
79
|
+
for (const [s, e] of own) {
|
|
80
|
+
const last = spans[spans.length - 1];
|
|
81
|
+
if (last !== undefined && s <= last[1])
|
|
82
|
+
last[1] = Math.max(last[1], e);
|
|
83
|
+
else
|
|
84
|
+
spans.push([s, e]);
|
|
85
|
+
}
|
|
86
|
+
let bytes = 0;
|
|
87
|
+
for (const [s, e] of spans)
|
|
88
|
+
bytes += e - s;
|
|
89
|
+
return { complete: true, spans, bytes };
|
|
90
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// near-zero-cost incumbent that prunes the other mechanisms through the
|
|
10
10
|
// ordinary admissible-floor check, with no extension special-case anywhere.
|
|
11
11
|
import { read, resolve } from "../primitives.js";
|
|
12
|
-
import { guidedFirst, hubBound } from "../traverse.js";
|
|
12
|
+
import { guidedFirst, hubBound, namedContinuations, scaffoldSpans, } from "../traverse.js";
|
|
13
13
|
import { conceptHop } from "../match.js";
|
|
14
14
|
import { bridge } from "../resonance.js";
|
|
15
15
|
import { liftAnswer, liftedScaffolding, segRestatesQuery } from "../types.js";
|
|
@@ -179,7 +179,7 @@ export const coverMechanism = {
|
|
|
179
179
|
const { rec, computed } = pre;
|
|
180
180
|
// Masking: computed spans are authoritative. Remove recognised sites
|
|
181
181
|
// that overlap any computed span before building the cover search.
|
|
182
|
-
|
|
182
|
+
let sites = computed.length === 0
|
|
183
183
|
? rec.sites
|
|
184
184
|
: rec.sites.filter((s) => !computed.some((u) => s.start < u.j && u.i < s.end));
|
|
185
185
|
if (computed.length > 0 && sites.length < rec.sites.length) {
|
|
@@ -191,6 +191,35 @@ export const coverMechanism = {
|
|
|
191
191
|
s.end,
|
|
192
192
|
])), "a computation always wins: recognised forms overlapping a computed span are dropped");
|
|
193
193
|
}
|
|
194
|
+
// A FRAGMENT ANSWERS OTHER QUESTIONS. A recognised form that sits inside
|
|
195
|
+
// other forms (it has structural parents or containers) holds continuations
|
|
196
|
+
// because the forms it is a piece of were asked — suffix inheritance gives
|
|
197
|
+
// `f death` the answer of every `… place of death` question. Choosing one of
|
|
198
|
+
// several such continuations by popularity voices some other question's
|
|
199
|
+
// answer, and the cover used to account the fragment's bytes as explained by
|
|
200
|
+
// it. A fragment with several continuations leads somewhere FOR THIS
|
|
201
|
+
// QUESTION only when the question names one (traverse.ts, the exact tier).
|
|
202
|
+
// A form that is (nearly) the whole question is not a piece of it: the
|
|
203
|
+
// question says nothing beyond it, so its continuations answer THIS question.
|
|
204
|
+
const asked = ctx._edgeAsked;
|
|
205
|
+
const W0 = ctx.space.maxGroup;
|
|
206
|
+
const leading = asked === null
|
|
207
|
+
? sites
|
|
208
|
+
: sites.filter((s) => query.length - (s.end - s.start) < W0 ||
|
|
209
|
+
!(ctx.store.hasParents(s.payload) ||
|
|
210
|
+
ctx.store.hasContainers(s.payload)) ||
|
|
211
|
+
ctx.store.nextFirst(s.payload, 2).length < 2 ||
|
|
212
|
+
namedContinuations(ctx, s.payload, asked) !== null);
|
|
213
|
+
if (leading.length < sites.length) {
|
|
214
|
+
if (ctx.meter) {
|
|
215
|
+
ctx.meter.unaskedFragments += sites.length - leading.length;
|
|
216
|
+
}
|
|
217
|
+
ctx.trace?.step("unaskedFragments", sites.filter((s) => !leading.includes(s)).map((s) => rItem(query.subarray(s.start, s.end), "fragment", s.payload, [
|
|
218
|
+
s.start,
|
|
219
|
+
s.end,
|
|
220
|
+
])), [], "a piece of other forms whose continuations the question names none of — it answers other questions");
|
|
221
|
+
sites = leading;
|
|
222
|
+
}
|
|
194
223
|
if (sites.length === 0 && computed.length === 0)
|
|
195
224
|
return [];
|
|
196
225
|
const connectors = ctx.meter
|
|
@@ -278,8 +307,17 @@ export const coverMechanism = {
|
|
|
278
307
|
// restated span contributes nothing to the composed answer, so it must
|
|
279
308
|
// not be priced as if it did (PASS-carried bytes are priced already;
|
|
280
309
|
// the diagnostic label reflects the same distinction).
|
|
310
|
+
//
|
|
311
|
+
// …and a span made of nothing but corpus-global scaffolding names nothing:
|
|
312
|
+
// every window of it is a piece of more than √N stored forms, so the form
|
|
313
|
+
// recognised there — the song `What`, in the trained store — is one of
|
|
314
|
+
// thousands it could be. Voicing that form's fact explains no byte the
|
|
315
|
+
// asker owes: measured, `What country is Jerry Bock a citizen of?` was won
|
|
316
|
+
// by `The performer of What is Melinda Marx.` glued onto the right fact.
|
|
317
|
+
const scaffold = scaffoldSpans(ctx, query);
|
|
281
318
|
const accounted = segs
|
|
282
|
-
.filter((s) => s.rec && !segRestatesQuery(s, query, query.length, W)
|
|
319
|
+
.filter((s) => s.rec && !segRestatesQuery(s, query, query.length, W) &&
|
|
320
|
+
!scaffold.some(([a, b]) => a <= s.i && s.j <= b))
|
|
283
321
|
.map((s) => [s.i, s.j]);
|
|
284
322
|
return [{
|
|
285
323
|
bytes: composed,
|
|
@@ -7,7 +7,7 @@ import { cosine } from "../../vec.js";
|
|
|
7
7
|
import { consensusFloor, dominates, identityBar, reachThreshold, significanceBar, } from "../../geometry.js";
|
|
8
8
|
import { gistOf, read, resolve } from "../primitives.js";
|
|
9
9
|
import { indexOf } from "../../bytes.js";
|
|
10
|
-
import { allWindowsAreScaffolding, corpusN, hubBound } from "../traverse.js";
|
|
10
|
+
import { allWindowsAreScaffolding, askedEvidence, corpusN, guidedFirst, hubBound, } from "../traverse.js";
|
|
11
11
|
import { follow, project, reverseContext, voicesDisplacedFiller, } from "../match.js";
|
|
12
12
|
import { CONCEPT, STEP } from "../graph-search.js";
|
|
13
13
|
import { restates as lawRestates } from "../derivation.js";
|
|
@@ -102,7 +102,15 @@ export async function recallByResonance(ctx, query, pre) {
|
|
|
102
102
|
// conversation reads as if it were the next thing to say.
|
|
103
103
|
if (g !== null && g.length > 0 &&
|
|
104
104
|
!lawRestates(query, g, 0, { proper: true })) {
|
|
105
|
-
|
|
105
|
+
// EVIDENCE TRAVELS: when the question NAMED the continuation followed
|
|
106
|
+
// (traverse.ts, the exact tier — `Who is the father of Frederick II?`
|
|
107
|
+
// witnesses the father fact's own question `Frederick II father`), the
|
|
108
|
+
// spans that named it are explained too, not only the argument.
|
|
109
|
+
const hop = guidedFirst(ctx, arg.payload);
|
|
110
|
+
const named = hop === undefined
|
|
111
|
+
? []
|
|
112
|
+
: askedEvidence(ctx, arg.payload, hop);
|
|
113
|
+
return ground(g, "argument binding — the query's sole edge-source constituent, continuation followed", [[arg.start, arg.end], ...named], STEP);
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
}
|
package/dist/src/mind/mind.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export interface Conversation {
|
|
|
47
47
|
readonly id: number;
|
|
48
48
|
}
|
|
49
49
|
import type { AttentionRead, MindContext, Recognition } from "./types.js";
|
|
50
|
+
import type { WindowIndex } from "./evidence.js";
|
|
50
51
|
export type { AnchorRejectionReason, ClimbConsensusData, ConsensusAnchorTrace, ConsensusReachTrace, ConsensusRegionTrace, CrossRegionTier, JunctionVoteTrace, RegionOutcome, } from "./attention.js";
|
|
51
52
|
export type { AncestorReach, SaturationReason, SaturationStop, } from "./types.js";
|
|
52
53
|
import { type CostReport, Meter } from "../meter.js";
|
|
@@ -165,6 +166,11 @@ export declare class Mind implements MindContext {
|
|
|
165
166
|
* first-edge behaviour) and the reverse projection uses it for
|
|
166
167
|
* reverse-recall disambiguation via `chooseAmong`. */
|
|
167
168
|
_edgeGuide: Vec | null;
|
|
169
|
+
/** See {@link MindContext._edgeAsked}. */
|
|
170
|
+
_edgeAsked: {
|
|
171
|
+
bytes: Uint8Array;
|
|
172
|
+
index: WindowIndex;
|
|
173
|
+
} | null;
|
|
168
174
|
/** Per-response memo of {@link chooseNext} picks — ensures every mechanism
|
|
169
175
|
* of a single response follows the SAME continuation for each ambiguous
|
|
170
176
|
* context node. */
|
package/dist/src/mind/mind.js
CHANGED
|
@@ -104,6 +104,8 @@ export class Mind {
|
|
|
104
104
|
* first-edge behaviour) and the reverse projection uses it for
|
|
105
105
|
* reverse-recall disambiguation via `chooseAmong`. */
|
|
106
106
|
_edgeGuide = null;
|
|
107
|
+
/** See {@link MindContext._edgeAsked}. */
|
|
108
|
+
_edgeAsked = null;
|
|
107
109
|
/** Per-response memo of {@link chooseNext} picks — ensures every mechanism
|
|
108
110
|
* of a single response follows the SAME continuation for each ambiguous
|
|
109
111
|
* context node. */
|
|
@@ -334,6 +336,7 @@ export class Mind {
|
|
|
334
336
|
this.canon = null;
|
|
335
337
|
this.canonMemo = null;
|
|
336
338
|
this._edgeGuide = null;
|
|
339
|
+
this._edgeAsked = null;
|
|
337
340
|
this._edgeChoice.clear();
|
|
338
341
|
}
|
|
339
342
|
/** Shared response core — the one path from bytes to voiced answer.
|
|
@@ -15,7 +15,9 @@ import { fusionLayer, walkLayer } from "./reasoning.js";
|
|
|
15
15
|
import { closed, closeOver, remainderOf, unaccountedBytes, unexplainedSpans, windowOf, } from "./derivation.js";
|
|
16
16
|
import { rItem } from "./trace.js";
|
|
17
17
|
import { unexplainedLabel } from "./rationale.js";
|
|
18
|
-
import { hubBound } from "./traverse.js";
|
|
18
|
+
import { hubBound, offsetCanon, scaffoldExtents } from "./traverse.js";
|
|
19
|
+
import { windowIndex, witness } from "./evidence.js";
|
|
20
|
+
import { indexOf } from "../bytes.js";
|
|
19
21
|
import { Precomputed, } from "./pipeline-mechanism.js";
|
|
20
22
|
import { coverMechanism } from "./mechanisms/cover.js";
|
|
21
23
|
import { castMechanism } from "./mechanisms/cast.js";
|
|
@@ -83,6 +85,13 @@ export async function think(ctx, query, mechs) {
|
|
|
83
85
|
if (query.length === 0)
|
|
84
86
|
return null;
|
|
85
87
|
ctx._edgeGuide = gistOf(ctx, query);
|
|
88
|
+
{
|
|
89
|
+
const asked = offsetCanon(ctx, query);
|
|
90
|
+
ctx._edgeAsked = {
|
|
91
|
+
bytes: asked,
|
|
92
|
+
index: windowIndex(asked, ctx.space.maxGroup),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
86
95
|
ctx._edgeChoice.clear();
|
|
87
96
|
const t = ctx.trace?.enter("think", [rItem(query, "query")]);
|
|
88
97
|
const done = (answer, note) => {
|
|
@@ -468,7 +477,17 @@ export async function think(ctx, query, mechs) {
|
|
|
468
477
|
...pre.computed.map((u) => [u.i, u.j]),
|
|
469
478
|
];
|
|
470
479
|
const explained = priced.filter(([a, b]) => windowOf([a, b], answer, query, ctx.space.maxGroup) !== null);
|
|
471
|
-
|
|
480
|
+
// THE DERIVATION IS BORN OWING ITS DISCRIMINATIVE MATERIAL. The bytes a
|
|
481
|
+
// corpus-global scaffolding window reaches (traverse.ts, `scaffoldExtents`)
|
|
482
|
+
// are nobody's debt — otherwise a later step could claim to pay them by
|
|
483
|
+
// restating ` is `, which every fact holds, and the law (which measures
|
|
484
|
+
// carrying by any window of what is owed) would admit it; the substitution
|
|
485
|
+
// bridge reads gaps the same way (`explainedSpan`). PRICING is untouched:
|
|
486
|
+
// the ladder still charges every unexplained byte, because for a question
|
|
487
|
+
// made of nothing but scaffolding (`How are you today?`) covering those bytes
|
|
488
|
+
// IS the evidence.
|
|
489
|
+
const scaffold = scaffoldExtents(ctx, query);
|
|
490
|
+
const paid = remainderOf(query.length, [...explained, ...scaffold], ctx.space.maxGroup);
|
|
472
491
|
// WHAT THE CONSTRUCTION WITHHOLDS, at or above one quantum: the difference between
|
|
473
492
|
// the remainder paid in full and the remainder paid by carrying. Both readings
|
|
474
493
|
// are the law's, so the floor is applied once and in one place — and the
|
|
@@ -488,8 +507,23 @@ export async function think(ctx, query, mechs) {
|
|
|
488
507
|
};
|
|
489
508
|
const uncovered = state.remainder;
|
|
490
509
|
// ── Post-grounding, gated by the declaration and the remainder ────────
|
|
510
|
+
// WHAT THE GROUNDING SPOKE FOR, when it did not declare it: the forms inside
|
|
511
|
+
// the answer that the ASKER already holds. An answer is the asker's material
|
|
512
|
+
// plus what the corpus added — the fact's own value — and only the former was
|
|
513
|
+
// spoken for: re-entering it walks back to the question. The latter is what a
|
|
514
|
+
// chain continues THROUGH. Consuming every form recognised in the answer
|
|
515
|
+
// consumed that too, so a chain could start only where recognition happened
|
|
516
|
+
// to miss the next entity — measured on 133 held-out 2Wiki compositional
|
|
517
|
+
// questions, 3 pivot steps in all once interior recognition named the entity
|
|
518
|
+
// inside every fact. Witnessed exactly, as `chooseNext`'s exact tier reads the
|
|
519
|
+
// question (evidence.ts); a form below one window cannot be witnessed, and is
|
|
520
|
+
// consumed as before.
|
|
521
|
+
const asked = ctx._edgeAsked;
|
|
491
522
|
const preConsumed = declaredUsed ??
|
|
492
|
-
new Set(recognise(ctx, answer).sites
|
|
523
|
+
new Set(recognise(ctx, answer).sites
|
|
524
|
+
.filter((s) => asked === null || s.end - s.start < ctx.space.maxGroup ||
|
|
525
|
+
witness(offsetCanon(ctx, answer.subarray(s.start, s.end)), [asked.index], ctx.space.maxGroup).complete)
|
|
526
|
+
.map((s) => s.payload));
|
|
493
527
|
// A grounding that DECLARED itself complete is not extended: the answer is
|
|
494
528
|
// already a trained form's own continuation, reached through an identity
|
|
495
529
|
// claim about the query, so a multi-hop pivot could only chain past the
|
|
@@ -518,7 +552,15 @@ export async function think(ctx, query, mechs) {
|
|
|
518
552
|
// `preConsumed` is derived by re-recognising the answer — "everything in
|
|
519
553
|
// it", not "what it voiced" — and a containment rule over that would
|
|
520
554
|
// suppress every pivot the answer legitimately contains.
|
|
521
|
-
|
|
555
|
+
//
|
|
556
|
+
// …and a continuation the ANSWER ITSELF holds was voiced, not withheld. A
|
|
557
|
+
// substitution that answers with its anchor's own continuation (`The director
|
|
558
|
+
// of Beat Girl is Edmond T. Gréville.`) declared that anchor used, so reading
|
|
559
|
+
// its continuations as withheld refused every pivot inside the answer — the
|
|
560
|
+
// chain could never step past the entity the first hop introduced.
|
|
561
|
+
const voiced = declaredUsed === undefined ? [] : [...declaredUsed].flatMap((id) => ctx.store.nextFirst(id, hubBound(ctx))
|
|
562
|
+
.map((n) => read(ctx, n))
|
|
563
|
+
.filter((v) => indexOf(answer, v, 0) < 0));
|
|
522
564
|
// WHAT THIS BRANCH READ, published where it was read. Post-grounding decides
|
|
523
565
|
// by the DECLARATION (`decided.used`, which becomes `voiced`), by what the
|
|
524
566
|
// recognition already consumed (`preConsumed`) and by the derivation's own
|
|
@@ -6,10 +6,11 @@ import { rItem, rNode } from "./trace.js";
|
|
|
6
6
|
import { bytesEqual, indexOf, latin1 } from "../bytes.js";
|
|
7
7
|
import { read, resolve } from "./primitives.js";
|
|
8
8
|
import { countClusters } from "./attention.js";
|
|
9
|
-
import { hubBound } from "./traverse.js";
|
|
9
|
+
import { guidedFirst, hubBound, namedContinuations, offsetCanon, } from "./traverse.js";
|
|
10
|
+
import { unspoken, windowIndex } from "./evidence.js";
|
|
10
11
|
import { containsSpan, follow, haloSiblings, project } from "./match.js";
|
|
11
12
|
import { joinWithBridge, pivotInto } from "./resonance.js";
|
|
12
|
-
import { closeOver, restates, unaccountedBytes, } from "./derivation.js";
|
|
13
|
+
import { closed, closeOver, restates, unaccountedBytes, } from "./derivation.js";
|
|
13
14
|
import { STEP } from "./graph-search.js";
|
|
14
15
|
/** What one ADMITTED transition did to the question, published on the meter:
|
|
15
16
|
* the bytes its witnesses CARRIED and the remainder the move DRAINED. The two
|
|
@@ -69,6 +70,11 @@ export function walkLayer(ctx, query, preConsumed, pre, voiced = []) {
|
|
|
69
70
|
// fire — the same visibility trade chooseNext documents.
|
|
70
71
|
const bound = hubBound(ctx);
|
|
71
72
|
const consumed = new Set();
|
|
73
|
+
/** The windows each product of this derivation holds — what of the question
|
|
74
|
+
* the derivation has already restated, so a later step is NAMED only by
|
|
75
|
+
* question material none of them said. */
|
|
76
|
+
const spoken = [];
|
|
77
|
+
const speak = (product) => spoken.push(windowIndex(offsetCanon(ctx, product), ctx.space.maxGroup));
|
|
72
78
|
/** `prev` lets a caller hand in an already-read reverse-edge list — hop 0
|
|
73
79
|
* reuses the guard's, below, instead of re-reading it. */
|
|
74
80
|
const consumeNode = (id, prev) => {
|
|
@@ -89,6 +95,7 @@ export function walkLayer(ctx, query, preConsumed, pre, voiced = []) {
|
|
|
89
95
|
const begin = async (d0) => {
|
|
90
96
|
const answer = d0.product;
|
|
91
97
|
startedFrom = answer;
|
|
98
|
+
speak(answer);
|
|
92
99
|
// Echo guard: a query that is ITSELF a learnt continuation (some context's
|
|
93
100
|
// answer) is being asked back at the system — hopping forward from it would
|
|
94
101
|
// chain through the very fact that produced it and echo the conversation
|
|
@@ -328,21 +335,49 @@ export function walkLayer(ctx, query, preConsumed, pre, voiced = []) {
|
|
|
328
335
|
ctx.trace?.step("pivotCandidateRefused", [rItem(cur, "answer")], [], `${why} — refused`);
|
|
329
336
|
return null;
|
|
330
337
|
}
|
|
338
|
+
// THE STEP THE QUESTION ASKS FOR. The hop `follow` took is NAMED when one
|
|
339
|
+
// of its establishing contexts is witnessed by what of the question no
|
|
340
|
+
// product has restated yet, plus the pivot itself (traverse.ts,
|
|
341
|
+
// `namedContinuations`): `Where was the place of death of the director of
|
|
342
|
+
// film Beat Girl?` names `Edmond T. Gréville place of death` once the first
|
|
343
|
+
// hop has restated `director` and `Beat Girl` — and `Who is the father of
|
|
344
|
+
// Frederick II?` names nothing past `Peter III of Aragon`, because `father`
|
|
345
|
+
// was restated by the hop that reached him. A named step MOVES to structure
|
|
346
|
+
// the question asked for, so it is admitted on that ground; an unnamed one
|
|
347
|
+
// must carry the question's remainder as before, and from a CLOSED
|
|
348
|
+
// derivation — nothing left owed — it is not offered at all: the question
|
|
349
|
+
// asks for no further step, and the law would otherwise admit any.
|
|
350
|
+
const asked = ctx._edgeAsked;
|
|
351
|
+
let named = false;
|
|
352
|
+
if (asked !== null) {
|
|
353
|
+
const unsaid = {
|
|
354
|
+
bytes: asked.bytes,
|
|
355
|
+
index: unspoken(asked.index, spoken),
|
|
356
|
+
};
|
|
357
|
+
const names = namedContinuations(ctx, pivot, unsaid);
|
|
358
|
+
const hop = guidedFirst(ctx, pivot);
|
|
359
|
+
named = names !== null && hop !== undefined && names.includes(hop);
|
|
360
|
+
}
|
|
361
|
+
if (!named && !producerOwnsShape && closed(d)) {
|
|
362
|
+
ctx.trace?.step("pivotUnasked", [rItem(cur, "answer"), rNode(ctx, pivot, "pivot")], [rItem(fc, "withheld")], "the derivation owes nothing and the question names no further step — not offered");
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
331
365
|
pending = { kind: "pivot", cur, pivot, fc };
|
|
332
|
-
// Offered with the identity species
|
|
333
|
-
// speaks for
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
// test.
|
|
366
|
+
// Offered with the identity species when the grounding declared what it
|
|
367
|
+
// speaks for, or when the question names the step; otherwise the law
|
|
368
|
+
// requires this step to carry question material the grounding left
|
|
369
|
+
// unaccounted, which is the drift the extension tests pin — refused by the
|
|
370
|
+
// law's own measure, not by a private window test.
|
|
337
371
|
return {
|
|
338
372
|
product: fc,
|
|
339
373
|
contains: true,
|
|
340
|
-
reaches: producerOwnsShape,
|
|
374
|
+
reaches: producerOwnsShape || named,
|
|
341
375
|
cost: STEP,
|
|
342
376
|
};
|
|
343
377
|
};
|
|
344
378
|
const onTaken = (before, after, witnesses) => {
|
|
345
379
|
meterTransition(ctx, before, after, witnesses);
|
|
380
|
+
speak(after.product);
|
|
346
381
|
const p = pending;
|
|
347
382
|
pending = null;
|
|
348
383
|
if (p === null)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Vec } from "../vec.js";
|
|
2
2
|
import type { AncestorReach, MindContext } from "./types.js";
|
|
3
|
+
import { type WindowIndex } from "./evidence.js";
|
|
3
4
|
/** The reach memo this ask should use — see the note above.
|
|
4
5
|
*
|
|
5
6
|
* A TRACED response always gets a fresh, empty one. `AncestorReach`'s
|
|
@@ -140,8 +141,10 @@ export declare function argmaxCosine<T>(query: Vec, items: Iterable<T>, vecOf: (
|
|
|
140
141
|
* formRules all share. undefined when the node has no continuation. */
|
|
141
142
|
export declare function guidedFirst(ctx: MindContext, id: number): number | undefined;
|
|
142
143
|
export declare function guidedNext(ctx: MindContext, node: number): number | undefined;
|
|
143
|
-
/** Disambiguate among a node's learnt continuations by
|
|
144
|
-
*
|
|
144
|
+
/** Disambiguate among a node's learnt continuations: first by the question's
|
|
145
|
+
* own witness of an establishing context (the exact tier, see
|
|
146
|
+
* {@link askedContinuations}), then by distributional support. NOTE the
|
|
147
|
+
* `guide` contract: its VALUE is deliberately unused —
|
|
145
148
|
* only its PRESENCE gates disambiguation (a null guide means no query is in
|
|
146
149
|
* flight, so structural walkers keep plain first-edge behaviour). The
|
|
147
150
|
* gist-cosine of short answer candidates against a query guide is dominated
|
|
@@ -153,6 +156,26 @@ export declare function guidedNext(ctx: MindContext, node: number): number | und
|
|
|
153
156
|
* therefore scores by guide cosine. The two directions consult different
|
|
154
157
|
* halves of the evidence on purpose. */
|
|
155
158
|
export declare function chooseNext(ctx: MindContext, id: number, guide?: Vec | null): number | undefined;
|
|
159
|
+
/** The response canonicalizer's reading of `bytes` when it keeps every offset
|
|
160
|
+
* — so a window found in the canonical bytes sits at the same place in the
|
|
161
|
+
* asker's — else the bytes themselves. Text canon is offset-preserving on
|
|
162
|
+
* ASCII without interior whitespace runs; where it is not, the raw bytes are
|
|
163
|
+
* read and a case-variant window simply does not match. */
|
|
164
|
+
export declare function offsetCanon(ctx: MindContext, bytes: Uint8Array): Uint8Array;
|
|
165
|
+
/** The continuations of `id` that `asked` NAMES (see {@link
|
|
166
|
+
* askedContinuations}) — for a caller holding material other than the whole
|
|
167
|
+
* question: the multi-hop walk asks with what of the question no product has
|
|
168
|
+
* restated yet. null when none is named. */
|
|
169
|
+
export declare function namedContinuations(ctx: MindContext, id: number, asked: {
|
|
170
|
+
bytes: Uint8Array;
|
|
171
|
+
index: WindowIndex;
|
|
172
|
+
}): number[] | null;
|
|
173
|
+
/** The question spans that NAMED `pick` among `id`'s continuations — the
|
|
174
|
+
* evidence a projection through that pick stands on, so a mechanism can
|
|
175
|
+
* account for what the question said about it (mechanism-market.md:
|
|
176
|
+
* evidence travels). Empty when the question names no continuation of `id`
|
|
177
|
+
* or names others. */
|
|
178
|
+
export declare function askedEvidence(ctx: MindContext, id: number, pick: number): Array<[number, number]>;
|
|
156
179
|
/** The perceived gist of a candidate node, through the session gist cache.
|
|
157
180
|
* Re-gisting a candidate is a full river fold of its bytes — the measured
|
|
158
181
|
* recall bottleneck (a hub context offers up to √N continuations, EACH
|
|
@@ -198,6 +221,23 @@ export declare function chooseAmong(ctx: MindContext, candidates: readonly numbe
|
|
|
198
221
|
* NOT scaffolding-only — it has no evidence either way, and its callers already
|
|
199
222
|
* refuse it on their own terms. */
|
|
200
223
|
export declare function allWindowsAreScaffolding(ctx: MindContext, query: Uint8Array): boolean;
|
|
224
|
+
/** Per offset of `bytes`: 1 when the W-window there is a stored form contained
|
|
225
|
+
* in more than √N places (corpus-global scaffolding; see the floor below),
|
|
226
|
+
* else 0. Memoised per
|
|
227
|
+
* byte array for the life of the store's read-only response. */
|
|
228
|
+
export declare function hubWindows(ctx: MindContext, bytes: Uint8Array): Uint8Array;
|
|
229
|
+
/** The query's SCAFFOLDING CORE, as spans: the bytes every W-window over which
|
|
230
|
+
* is a hub (see {@link hubWindows}) — what is nothing but frame, where
|
|
231
|
+
* {@link scaffoldExtents} is what a frame window reaches. */
|
|
232
|
+
export declare function scaffoldSpans(ctx: MindContext, query: Uint8Array): Array<[number, number]>;
|
|
233
|
+
/** The EXTENTS of the query's SCAFFOLDING windows, merged: every byte some
|
|
234
|
+
* W-window reaches that is a stored form contained in more than √N places —
|
|
235
|
+
* corpus-global commonality (commonality.md), the same "hub" reading as
|
|
236
|
+
* {@link allWindowsAreScaffolding} and the bridge's `explainedSpan`. A window
|
|
237
|
+
* the store never saw is NOT scaffolding. The extent, not the core, is what
|
|
238
|
+
* a coverage test needs: a span that still holds one hub window can be
|
|
239
|
+
* "carried" by any fact that holds that window. */
|
|
240
|
+
export declare function scaffoldExtents(ctx: MindContext, query: Uint8Array): Array<[number, number]>;
|
|
201
241
|
/** Trained forms the query may OPEN, proposed from the write side's own
|
|
202
242
|
* leaf-id window index — the supply of last resort for prefix completion.
|
|
203
243
|
*
|