@hviana/sema 0.9.1 → 0.9.3
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 +19 -0
- package/dist/src/meter.js +19 -0
- package/dist/src/mind/evidence.d.ts +30 -0
- package/dist/src/mind/evidence.js +102 -0
- package/dist/src/mind/mechanisms/cast.d.ts +1 -1
- package/dist/src/mind/mechanisms/cast.js +73 -12
- package/dist/src/mind/mechanisms/cover.js +25 -3
- package/dist/src/mind/mechanisms/recall.js +93 -9
- package/dist/src/mind/mechanisms/reference.js +25 -0
- package/dist/src/mind/mind.d.ts +7 -0
- package/dist/src/mind/mind.js +3 -0
- package/dist/src/mind/pipeline-mechanism.js +15 -1
- package/dist/src/mind/pipeline.js +51 -8
- package/dist/src/mind/reasoning.js +65 -18
- package/dist/src/mind/resonance.d.ts +3 -2
- package/dist/src/mind/resonance.js +3 -2
- package/dist/src/mind/traverse.d.ts +94 -2
- package/dist/src/mind/traverse.js +611 -7
- package/dist/src/mind/types.d.ts +12 -0
- package/docs/INDEX.md +18 -17
- package/docs/INVARIANTS.md +1 -0
- package/docs/architecture/evidence.md +256 -0
- package/docs/architecture/exact-vs-approximate.md +10 -9
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/meter.ts +19 -0
- package/src/mind/evidence.ts +125 -0
- package/src/mind/mechanisms/cast.ts +77 -3
- package/src/mind/mechanisms/cover.ts +42 -3
- package/src/mind/mechanisms/recall.ts +123 -11
- package/src/mind/mechanisms/reference.ts +24 -1
- package/src/mind/mind.ts +6 -0
- package/src/mind/pipeline-mechanism.ts +15 -1
- package/src/mind/pipeline.ts +64 -8
- package/src/mind/reasoning.ts +82 -17
- package/src/mind/resonance.ts +3 -2
- package/src/mind/traverse.ts +652 -7
- package/src/mind/types.ts +10 -0
- package/test/154-the-question-names-the-step.test.mjs +368 -0
- package/test/155-the-relation-read-off-another-instance.test.mjs +376 -0
- package/test/29-counterfactual.test.mjs +21 -11
- package/test/76-reference-binding.test.mjs +32 -0
|
@@ -15,10 +15,14 @@ import type { MindContext } from "../types.js";
|
|
|
15
15
|
import type { Vec } from "../../vec.js";
|
|
16
16
|
import { read } from "../primitives.js";
|
|
17
17
|
import {
|
|
18
|
+
answersOtherQuestions,
|
|
18
19
|
argmaxBy,
|
|
20
|
+
coInstanceFiller,
|
|
19
21
|
corpusN,
|
|
20
22
|
edgeAncestors,
|
|
21
23
|
hubBound,
|
|
24
|
+
hubWindows,
|
|
25
|
+
offsetCanon,
|
|
22
26
|
sharedReachMemo,
|
|
23
27
|
} from "../traverse.js";
|
|
24
28
|
import {
|
|
@@ -31,7 +35,7 @@ import {
|
|
|
31
35
|
} from "../match.js";
|
|
32
36
|
import { joinWithBridge } from "../resonance.js";
|
|
33
37
|
import { CONCEPT, STEP } from "../graph-search.js";
|
|
34
|
-
import { indexOf } from "../../bytes.js";
|
|
38
|
+
import { indexOf, latin1 } from "../../bytes.js";
|
|
35
39
|
import { consensusFloor, dominates } from "../../geometry.js";
|
|
36
40
|
import { restates, unexplainedSpans } from "../derivation.js";
|
|
37
41
|
import { rItem, rNode } from "../trace.js";
|
|
@@ -116,7 +120,7 @@ export interface CastResult {
|
|
|
116
120
|
* painted by Leonardo da Vinci.") must be seated by that establishing
|
|
117
121
|
* sentence, NOT by its own biography fact — voicing the bio leaks exactly
|
|
118
122
|
* what a comparison must keep out, and loses the embedded "Mona Lisa"
|
|
119
|
-
* term C3
|
|
123
|
+
* term C3's further-hop candidate lives in.
|
|
120
124
|
*
|
|
121
125
|
* The distinguishing signal is content-addressed, not a count: a genuine
|
|
122
126
|
* establishing predecessor's bytes CONTAIN id's own bytes — it names or
|
|
@@ -693,9 +697,22 @@ export async function counterfactualTransfer(
|
|
|
693
697
|
// its own fact — so the same bar applies. The displaced structure is only
|
|
694
698
|
// recognised as the slot being overridden and is never voiced, so it is
|
|
695
699
|
// deliberately not gated here.
|
|
700
|
+
// …and the substitute must lead somewhere FOR THIS QUESTION: a fragment
|
|
701
|
+
// whose continuations the question names none of answers other questions
|
|
702
|
+
// (traverse.ts, `answersOtherQuestions`). `ong)?`, the tail of every
|
|
703
|
+
// `… (… Song)?` question, was "named" by `What is the place of birth of the
|
|
704
|
+
// performer of song Heaven (Namie Amuro Song)?`, and redirection voiced
|
|
705
|
+
// its most-poured stranger's birthplace.
|
|
706
|
+
const stranger = last !== undefined &&
|
|
707
|
+
answersOtherQuestions(
|
|
708
|
+
ctx,
|
|
709
|
+
last.point.anchor,
|
|
710
|
+
query.length,
|
|
711
|
+
last.run.qe - last.run.qs,
|
|
712
|
+
);
|
|
696
713
|
if (
|
|
697
714
|
last !== undefined && last.point !== dominant && displaced &&
|
|
698
|
-
voiceable(last.point)
|
|
715
|
+
voiceable(last.point) && !stranger
|
|
699
716
|
) {
|
|
700
717
|
const g = await project(ctx, last.point.anchor, qv);
|
|
701
718
|
if (g !== null) {
|
|
@@ -1084,6 +1101,41 @@ export async function counterfactualTransfer(
|
|
|
1084
1101
|
: [];
|
|
1085
1102
|
const cmpGaps = unexplainedSpans(query.length, cmpAccounted);
|
|
1086
1103
|
const cmpMaxGap = cmpGaps.reduce((n, [s, e]) => Math.max(n, e - s), 0);
|
|
1104
|
+
// TWO THINGS NAMED. A comparison voices two structures, so the question
|
|
1105
|
+
// must evidence the second one with material of its own: a W-window of the
|
|
1106
|
+
// question that the analog holds — on its aligned runs, or anywhere in its
|
|
1107
|
+
// own form under the response's equivalence (the witness reading,
|
|
1108
|
+
// evidence.md) — and that is neither inside the dominant's runs nor corpus
|
|
1109
|
+
// scaffolding (`hubWindows`, the reading of "what the question owes").
|
|
1110
|
+
// `father of Frederick II?` reached `Peter III of Aragon father` through
|
|
1111
|
+
// ` father`, which the dominant `Frederick II father` already holds, and
|
|
1112
|
+
// ` of `, which every fact holds — one structure named, and the comparison
|
|
1113
|
+
// glued the analog's bare question onto the answer (`…is Peter III of
|
|
1114
|
+
// Aragon.Peter III of Aragon father`). `How is ice like steel?` names
|
|
1115
|
+
// `Ice is cold` with `ice `, a window no byte-exact run aligns (the case
|
|
1116
|
+
// differs) and the dominant `Steel is hard` lacks.
|
|
1117
|
+
const analogOwnsEvidence = (): boolean => {
|
|
1118
|
+
if (bestAnalog === null) return false;
|
|
1119
|
+
const W = ctx.space.maxGroup;
|
|
1120
|
+
const hub = hubWindows(ctx, query);
|
|
1121
|
+
const mine = runSpans(dominant);
|
|
1122
|
+
const owns = (o: number): boolean =>
|
|
1123
|
+
!hub[o] && !mine.some(([ms, me]) => o >= ms && o + W <= me);
|
|
1124
|
+
for (const [s, e] of runSpans(bestAnalog.point ?? bestAnalog.src)) {
|
|
1125
|
+
for (let o = s; o + W <= e; o++) if (owns(o)) return true;
|
|
1126
|
+
}
|
|
1127
|
+
const asked = ctx._edgeAsked;
|
|
1128
|
+
if (asked === null) return false;
|
|
1129
|
+
const form = offsetCanon(
|
|
1130
|
+
ctx,
|
|
1131
|
+
read(ctx, bestAnalog.anchor, asked.bytes.length * W),
|
|
1132
|
+
);
|
|
1133
|
+
for (let o = 0; o + W <= form.length; o++) {
|
|
1134
|
+
const at = asked.index.get(latin1(form.subarray(o, o + W)));
|
|
1135
|
+
if (at !== undefined && owns(at)) return true;
|
|
1136
|
+
}
|
|
1137
|
+
return false;
|
|
1138
|
+
};
|
|
1087
1139
|
// An analog that is not itself a directly ALIGNED point (point !== null —
|
|
1088
1140
|
// its own runs are query bytes, the query NAMED it) was only reached
|
|
1089
1141
|
// through a continuation hop or the structural-hub fallback. Voicing
|
|
@@ -1208,9 +1260,24 @@ export async function counterfactualTransfer(
|
|
|
1208
1260
|
// supply were never the ones that test is about.
|
|
1209
1261
|
const cmpDismisses = !bestHalo &&
|
|
1210
1262
|
dismissedKnownContent(ctx, query, cmpAccounted);
|
|
1263
|
+
// …and the dominant must be something the question is ABOUT. A co-instance
|
|
1264
|
+
// of the question (traverse.ts, `coInstanceFiller`) is its frame around
|
|
1265
|
+
// another filler, and its seat is that filler's own answer: `Where was the
|
|
1266
|
+
// performer of song God (Lennon Song) born?` compared `Where was Shakira
|
|
1267
|
+
// (Shakira Song) born?` with `John Lennon` and voiced Shakira's birthplace.
|
|
1268
|
+
const asked = ctx._edgeAsked;
|
|
1269
|
+
const dominantOtherInstance = asked !== null &&
|
|
1270
|
+
coInstanceFiller(
|
|
1271
|
+
ctx,
|
|
1272
|
+
read(ctx, dominant.anchor, 2 * query.length + 1),
|
|
1273
|
+
[asked.index],
|
|
1274
|
+
asked.bytes,
|
|
1275
|
+
) !== null;
|
|
1211
1276
|
if (
|
|
1212
1277
|
bestAnalog !== null &&
|
|
1213
1278
|
(bestHalo || analogNamed || rootTrusted) &&
|
|
1279
|
+
analogOwnsEvidence() &&
|
|
1280
|
+
!dominantOtherInstance &&
|
|
1214
1281
|
!cmpDismisses &&
|
|
1215
1282
|
queryScale(dominant.ctx.length) &&
|
|
1216
1283
|
roots.length <= 1 &&
|
|
@@ -1346,6 +1413,13 @@ export async function counterfactualTransfer(
|
|
|
1346
1413
|
? `the best analog carries no halo-tier company evidence, was never ` +
|
|
1347
1414
|
`named by the query, and no committed root's consensus vote ` +
|
|
1348
1415
|
`clears the floor, so comparison refuses to voice it`
|
|
1416
|
+
: dominantOtherInstance
|
|
1417
|
+
? `the dominant is another instance of the question's frame — its ` +
|
|
1418
|
+
`seat is another filler's answer, not what the question asks about`
|
|
1419
|
+
: !analogOwnsEvidence()
|
|
1420
|
+
? `the question evidences the analog only with windows the dominant ` +
|
|
1421
|
+
`already holds or the corpus' scaffolding — it names one structure, ` +
|
|
1422
|
+
`not two, so there is nothing to compare`
|
|
1349
1423
|
: cmpDismisses
|
|
1350
1424
|
? `a frame-tier analog under an untrusted root dismisses stored ` +
|
|
1351
1425
|
`query content its alignment never accounted for — comparison ` +
|
|
@@ -18,7 +18,12 @@ import type {
|
|
|
18
18
|
Site,
|
|
19
19
|
} from "../graph-search.js";
|
|
20
20
|
import { read, resolve } from "../primitives.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
answersOtherQuestions,
|
|
23
|
+
guidedFirst,
|
|
24
|
+
hubBound,
|
|
25
|
+
scaffoldSpans,
|
|
26
|
+
} from "../traverse.js";
|
|
22
27
|
import { conceptHop } from "../match.js";
|
|
23
28
|
import { bridge } from "../resonance.js";
|
|
24
29
|
import { liftAnswer, liftedScaffolding, segRestatesQuery } from "../types.js";
|
|
@@ -229,7 +234,7 @@ export const coverMechanism: PipelineMechanism = {
|
|
|
229
234
|
|
|
230
235
|
// Masking: computed spans are authoritative. Remove recognised sites
|
|
231
236
|
// that overlap any computed span before building the cover search.
|
|
232
|
-
|
|
237
|
+
let sites = computed.length === 0
|
|
233
238
|
? rec.sites
|
|
234
239
|
: rec.sites.filter((s) =>
|
|
235
240
|
!computed.some((u) => s.start < u.j && u.i < s.end)
|
|
@@ -254,6 +259,29 @@ export const coverMechanism: PipelineMechanism = {
|
|
|
254
259
|
);
|
|
255
260
|
}
|
|
256
261
|
|
|
262
|
+
// A FRAGMENT ANSWERS OTHER QUESTIONS (traverse.ts) — and the cover used to
|
|
263
|
+
// account the fragment's bytes as explained by the stranger's answer.
|
|
264
|
+
const leading = sites.filter((s) =>
|
|
265
|
+
!answersOtherQuestions(ctx, s.payload, query.length, s.end - s.start)
|
|
266
|
+
);
|
|
267
|
+
if (leading.length < sites.length) {
|
|
268
|
+
if (ctx.meter) {
|
|
269
|
+
ctx.meter.unaskedFragments += sites.length - leading.length;
|
|
270
|
+
}
|
|
271
|
+
ctx.trace?.step(
|
|
272
|
+
"unaskedFragments",
|
|
273
|
+
sites.filter((s) => !leading.includes(s)).map((s) =>
|
|
274
|
+
rItem(query.subarray(s.start, s.end), "fragment", s.payload, [
|
|
275
|
+
s.start,
|
|
276
|
+
s.end,
|
|
277
|
+
])
|
|
278
|
+
),
|
|
279
|
+
[],
|
|
280
|
+
"a piece of other forms whose continuations the question names none of — it answers other questions",
|
|
281
|
+
);
|
|
282
|
+
sites = leading;
|
|
283
|
+
}
|
|
284
|
+
|
|
257
285
|
if (sites.length === 0 && computed.length === 0) return [];
|
|
258
286
|
|
|
259
287
|
const connectors = ctx.meter
|
|
@@ -382,8 +410,19 @@ export const coverMechanism: PipelineMechanism = {
|
|
|
382
410
|
// restated span contributes nothing to the composed answer, so it must
|
|
383
411
|
// not be priced as if it did (PASS-carried bytes are priced already;
|
|
384
412
|
// the diagnostic label reflects the same distinction).
|
|
413
|
+
//
|
|
414
|
+
// …and a span made of nothing but corpus-global scaffolding names nothing:
|
|
415
|
+
// every window of it is a piece of more than √N stored forms, so the form
|
|
416
|
+
// recognised there — the song `What`, in the trained store — is one of
|
|
417
|
+
// thousands it could be. Voicing that form's fact explains no byte the
|
|
418
|
+
// asker owes: measured, `What country is Jerry Bock a citizen of?` was won
|
|
419
|
+
// by `The performer of What is Melinda Marx.` glued onto the right fact.
|
|
420
|
+
const scaffold = scaffoldSpans(ctx, query);
|
|
385
421
|
const accounted: Array<[number, number]> = segs
|
|
386
|
-
.filter((s) =>
|
|
422
|
+
.filter((s) =>
|
|
423
|
+
s.rec && !segRestatesQuery(s, query, query.length, W) &&
|
|
424
|
+
!scaffold.some(([a, b]) => a <= s.i && s.j <= b)
|
|
425
|
+
)
|
|
387
426
|
.map((s) => [s.i, s.j]);
|
|
388
427
|
|
|
389
428
|
return [{
|
|
@@ -15,7 +15,17 @@ import {
|
|
|
15
15
|
import type { MindContext } from "../types.js";
|
|
16
16
|
import { gistOf, read, resolve } from "../primitives.js";
|
|
17
17
|
import { indexOf } from "../../bytes.js";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
allWindowsAreScaffolding,
|
|
20
|
+
answersOtherQuestions,
|
|
21
|
+
askedEvidence,
|
|
22
|
+
canonHeldPoints,
|
|
23
|
+
coInstanceFiller,
|
|
24
|
+
corpusN,
|
|
25
|
+
guidedFirst,
|
|
26
|
+
hubBound,
|
|
27
|
+
namedContinuations,
|
|
28
|
+
} from "../traverse.js";
|
|
19
29
|
import {
|
|
20
30
|
follow,
|
|
21
31
|
project,
|
|
@@ -102,13 +112,13 @@ export async function recallByResonance(
|
|
|
102
112
|
// constituent bar is the same two-quanta (2W) reading confluence binds
|
|
103
113
|
// under, nested recognitions collapse to their MAXIMAL span, and two
|
|
104
114
|
// distinct maximal arguments mean the query asks about neither alone.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
// The argument binding, given its candidate arguments (`args`) and the
|
|
116
|
+
// recognised fragments that answer other questions (`strangerIds`).
|
|
117
|
+
const W2 = 2 * ctx.space.maxGroup;
|
|
118
|
+
const bindArgument = async (
|
|
119
|
+
args: Array<{ start: number; end: number; payload: number }>,
|
|
120
|
+
strangerIds: ReadonlySet<number>,
|
|
121
|
+
) => {
|
|
112
122
|
// Maximal spans by one sorted sweep (starts ascending, ties longest
|
|
113
123
|
// first): every earlier span starts at or before s, so s is contained
|
|
114
124
|
// exactly when the running max end already covers it. O(m log m) — a
|
|
@@ -134,13 +144,25 @@ export async function recallByResonance(
|
|
|
134
144
|
// binding to the argument's continuation would answer past content
|
|
135
145
|
// the query itself already carries forward. Derived from the same W2
|
|
136
146
|
// bar the argument itself is held to, never a separate tuned number.
|
|
147
|
+
// A fragment that answers other questions is not such a piece.
|
|
137
148
|
const hasSubstantialOutside = maximal.length === 1 &&
|
|
138
149
|
pre.rec.sites.some((s) =>
|
|
139
|
-
s.end - s.start >= W2 &&
|
|
150
|
+
s.end - s.start >= W2 && !strangerIds.has(s.payload) &&
|
|
140
151
|
(s.end <= maximal[0].start || s.start >= maximal[0].end)
|
|
141
152
|
);
|
|
142
153
|
if (maximal.length === 1 && !hasSubstantialOutside) {
|
|
143
154
|
const arg = maximal[0];
|
|
155
|
+
// An argument whose several continuations the question names none of
|
|
156
|
+
// outright would be followed by popularity. Another instance of the
|
|
157
|
+
// question may name one (traverse.ts, `byCoInstance`), and its
|
|
158
|
+
// proposals are the consensus climb's points — so the climb is asked
|
|
159
|
+
// for first, exactly where the choice would otherwise be blind.
|
|
160
|
+
const asked = ctx._edgeAsked;
|
|
161
|
+
if (
|
|
162
|
+
asked !== null && asked.points === undefined &&
|
|
163
|
+
ctx.store.nextFirst(arg.payload, 2).length >= 2 &&
|
|
164
|
+
namedContinuations(ctx, arg.payload, asked) === null
|
|
165
|
+
) await pre.attention();
|
|
144
166
|
const g = await follow(ctx, arg.payload, queryGist);
|
|
145
167
|
// The same "no restated fragment" guard tier 2 applies below (§ "the
|
|
146
168
|
// anchor cleared the consensus floor..."): a followed continuation
|
|
@@ -154,14 +176,69 @@ export async function recallByResonance(
|
|
|
154
176
|
g !== null && g.length > 0 &&
|
|
155
177
|
!lawRestates(query, g, 0, { proper: true })
|
|
156
178
|
) {
|
|
179
|
+
// EVIDENCE TRAVELS: when the question NAMED the continuation followed
|
|
180
|
+
// (traverse.ts, the exact tier — `Who is the father of Frederick II?`
|
|
181
|
+
// witnesses the father fact's own question `Frederick II father`), the
|
|
182
|
+
// spans that named it are explained too, not only the argument.
|
|
183
|
+
const hop = guidedFirst(ctx, arg.payload);
|
|
184
|
+
const named = hop === undefined
|
|
185
|
+
? []
|
|
186
|
+
: askedEvidence(ctx, arg.payload, hop);
|
|
157
187
|
return ground(
|
|
158
188
|
g,
|
|
159
189
|
"argument binding — the query's sole edge-source constituent, continuation followed",
|
|
160
|
-
[[arg.start, arg.end]],
|
|
190
|
+
[[arg.start, arg.end], ...named],
|
|
161
191
|
STEP,
|
|
162
192
|
);
|
|
163
193
|
}
|
|
164
194
|
}
|
|
195
|
+
return null;
|
|
196
|
+
};
|
|
197
|
+
let canonArgumentPending = false;
|
|
198
|
+
let strangers: ReadonlySet<number> = new Set();
|
|
199
|
+
if (qId === null) {
|
|
200
|
+
const recognised = pre.rec.sites.filter((s) =>
|
|
201
|
+
s.end - s.start >= W2 &&
|
|
202
|
+
s.end - s.start < query.length &&
|
|
203
|
+
ctx.store.hasNext(s.payload)
|
|
204
|
+
);
|
|
205
|
+
// An argument must lead somewhere FOR THIS QUESTION: a fragment whose
|
|
206
|
+
// continuations the question names none of answers other questions
|
|
207
|
+
// (traverse.ts) — `director`, inside `When was the director of film Jinpa
|
|
208
|
+
// born?`, bound the most-poured of fifty-five directors. Such a fragment
|
|
209
|
+
// is no argument, and no independent piece of the query either.
|
|
210
|
+
const strangerIds = new Set<number>();
|
|
211
|
+
for (const s of recognised) {
|
|
212
|
+
if (
|
|
213
|
+
answersOtherQuestions(ctx, s.payload, query.length, s.end - s.start)
|
|
214
|
+
) strangerIds.add(s.payload);
|
|
215
|
+
}
|
|
216
|
+
const args = recognised.filter((s) => !strangerIds.has(s.payload));
|
|
217
|
+
if (args.length === 0 && strangerIds.size > 0) {
|
|
218
|
+
if (ctx.meter) ctx.meter.unaskedFragments += strangerIds.size;
|
|
219
|
+
ctx.trace?.step(
|
|
220
|
+
"unaskedFragments",
|
|
221
|
+
recognised.filter((s) => strangerIds.has(s.payload)).map((s) =>
|
|
222
|
+
rItem(query.subarray(s.start, s.end), "fragment", s.payload, [
|
|
223
|
+
s.start,
|
|
224
|
+
s.end,
|
|
225
|
+
])
|
|
226
|
+
),
|
|
227
|
+
[],
|
|
228
|
+
"the only arguments are pieces of other forms whose continuations the question names none of — they answer other questions",
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
const bound = await bindArgument(args, strangerIds);
|
|
232
|
+
if (bound !== null) return bound;
|
|
233
|
+
// NO ARGUMENT BY BYTES IS NOT NO ARGUMENT. Recognition matches bytes, so
|
|
234
|
+
// `Man At Bath` (2Wiki title-cases its questions) is no site of the stored
|
|
235
|
+
// `Man at Bath`. When nothing recognised can bind, the points the
|
|
236
|
+
// consensus climb reaches that the question holds under the response's
|
|
237
|
+
// equivalence are arguments too (traverse.ts, `canonHeldPoints`) — read
|
|
238
|
+
// after the clean-resonance tier, which answers a near-identical question
|
|
239
|
+
// without any climb.
|
|
240
|
+
canonArgumentPending = ctx.canon !== null && args.length === 0;
|
|
241
|
+
strangers = strangerIds;
|
|
165
242
|
}
|
|
166
243
|
|
|
167
244
|
// The response's ONE top-k read (Precomputed.resonance) — the same list the
|
|
@@ -258,6 +335,20 @@ export async function recallByResonance(
|
|
|
258
335
|
Math.sqrt(otherLen / Math.max(1, query.length)),
|
|
259
336
|
);
|
|
260
337
|
|
|
338
|
+
// The argument the question holds only under the response's equivalence
|
|
339
|
+
// (above). Not gated on the whole-query resonance: a question whose only
|
|
340
|
+
// argument is a case variant (`… film Man At Bath work at?`) resonates
|
|
341
|
+
// below the significance bar as a whole.
|
|
342
|
+
if (canonArgumentPending) {
|
|
343
|
+
await pre.attention();
|
|
344
|
+
const held = canonHeldPoints(ctx, W2).filter((s) =>
|
|
345
|
+
ctx.store.hasNext(s.payload) &&
|
|
346
|
+
!answersOtherQuestions(ctx, s.payload, query.length, s.end - s.start)
|
|
347
|
+
);
|
|
348
|
+
const bound = await bindArgument(held, strangers);
|
|
349
|
+
if (bound !== null) return bound;
|
|
350
|
+
}
|
|
351
|
+
|
|
261
352
|
// 2. Scaffolding-dominated.
|
|
262
353
|
if (top.score >= sig) {
|
|
263
354
|
// The committed points of attention ARE the shared climb's roots (same
|
|
@@ -389,7 +480,28 @@ export async function recallByResonance(
|
|
|
389
480
|
forest[0].anchor,
|
|
390
481
|
query.length * ctx.space.maxGroup + 1,
|
|
391
482
|
);
|
|
392
|
-
|
|
483
|
+
// …and the same refusal read from the anchor's side: an anchor the query
|
|
484
|
+
// witnesses in every byte but one filler of its own is ANOTHER INSTANCE
|
|
485
|
+
// of the question (traverse.ts, `coInstanceFiller`). The query-side
|
|
486
|
+
// reading above needs the shared frame to dominate the QUERY, which a
|
|
487
|
+
// long slot defeats: `Where was the performer of song God (John Lennon
|
|
488
|
+
// Song) born?` elected `Where was Nicki Minaj (Nicki Minaj Song) born?`
|
|
489
|
+
// and answered Nicki Minaj's birthplace.
|
|
490
|
+
const asked = ctx._edgeAsked;
|
|
491
|
+
const co = asked === null
|
|
492
|
+
? null
|
|
493
|
+
: coInstanceFiller(ctx, anchorBytes, [asked.index], asked.bytes);
|
|
494
|
+
if (co !== null) {
|
|
495
|
+
ctx.trace?.step(
|
|
496
|
+
"coInstanceAnchor",
|
|
497
|
+
[rItem(query, "query"), rNode(ctx, forest[0].anchor, "anchor")],
|
|
498
|
+
[rItem(anchorBytes.subarray(co.span[0], co.span[1]), "filler")],
|
|
499
|
+
"refused — the anchor is another instance of the question's frame, " +
|
|
500
|
+
"and its continuation speaks of its own filler",
|
|
501
|
+
);
|
|
502
|
+
} else if (
|
|
503
|
+
g !== null && voicesDisplacedFiller(ctx, query, anchorBytes, g)
|
|
504
|
+
) {
|
|
393
505
|
ctx.trace?.step(
|
|
394
506
|
"displacedFiller",
|
|
395
507
|
[rItem(query, "query"), rNode(ctx, forest[0].anchor, "anchor")],
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
import type { MindContext } from "../types.js";
|
|
38
38
|
import type { FrameInstance } from "../match.js";
|
|
39
39
|
import { carriesFillers, distinct, follow, substituteAll } from "../match.js";
|
|
40
|
+
import { resolve } from "../primitives.js";
|
|
41
|
+
import { hubBound } from "../traverse.js";
|
|
40
42
|
import { dominates } from "../../geometry.js";
|
|
41
43
|
import { bytesEqual } from "../../bytes.js";
|
|
42
44
|
import { restates } from "../derivation.js";
|
|
@@ -186,7 +188,6 @@ export async function bindReference(
|
|
|
186
188
|
if (!distinct(referents)) {
|
|
187
189
|
return fail("two slots name the same bytes — the binding is ambiguous");
|
|
188
190
|
}
|
|
189
|
-
|
|
190
191
|
// ── THE LICENCE ────────────────────────────────────────────────────────
|
|
191
192
|
// Every instance must agree, against the first, that its continuation is its
|
|
192
193
|
// own fillers carried through one fixed form. Unanimity, exactly as the
|
|
@@ -199,11 +200,33 @@ export async function bindReference(
|
|
|
199
200
|
// discard them. Each goes through the shared projection, so an ambiguous
|
|
200
201
|
// instance is disambiguated exactly as it would be anywhere else.
|
|
201
202
|
const leadsNowhere = "an instance of the frame leads nowhere";
|
|
203
|
+
// A FACT FILED UNDER ITS FILLER IS NOT A CARRIAGE. When an instance's
|
|
204
|
+
// filler is itself a stored context leading to that instance's answer, the
|
|
205
|
+
// answer is something the corpus knows ABOUT that filler (`The place of
|
|
206
|
+
// birth of Peter Jackson is Wellington.` is a continuation of `Peter
|
|
207
|
+
// Jackson`), not a form any occupant takes — and two such facts can agree
|
|
208
|
+
// by chance (two people born in Wellington). `Run gcc hello.c` is filed
|
|
209
|
+
// under the question alone.
|
|
210
|
+
const filedUnderFiller = (inst: FrameInstance, cont: Uint8Array): boolean => {
|
|
211
|
+
const c = resolve(ctx, cont);
|
|
212
|
+
if (c === null) return false;
|
|
213
|
+
return inst.slots.some((s) => {
|
|
214
|
+
const f = resolve(ctx, s.filler);
|
|
215
|
+
return f !== null &&
|
|
216
|
+
ctx.store.nextFirst(f, hubBound(ctx)).includes(c);
|
|
217
|
+
});
|
|
218
|
+
};
|
|
202
219
|
const first = await follow(ctx, frame[0].id, pre.guide);
|
|
203
220
|
if (first === null || first.length === 0) return fail(leadsNowhere);
|
|
221
|
+
if (filedUnderFiller(frame[0], first)) {
|
|
222
|
+
return fail("the frame's answer is a fact filed under its filler");
|
|
223
|
+
}
|
|
204
224
|
for (let i = 1; i < frame.length; i++) {
|
|
205
225
|
const cont = await follow(ctx, frame[i].id, pre.guide);
|
|
206
226
|
if (cont === null || cont.length === 0) return fail(leadsNowhere);
|
|
227
|
+
if (filedUnderFiller(frame[i], cont)) {
|
|
228
|
+
return fail("the frame's answer is a fact filed under its filler");
|
|
229
|
+
}
|
|
207
230
|
if (
|
|
208
231
|
!carriesFillers(first, fillersOf(frame[0]), cont, fillersOf(frame[i]))
|
|
209
232
|
) {
|
package/src/mind/mind.ts
CHANGED
|
@@ -141,6 +141,7 @@ import {
|
|
|
141
141
|
leadsSomewhere,
|
|
142
142
|
} from "./traverse.js";
|
|
143
143
|
import { invalidateJunctionCache } from "./junction.js";
|
|
144
|
+
import type { WindowIndex } from "./evidence.js";
|
|
144
145
|
import { follow } from "./match.js";
|
|
145
146
|
import { recognise, segment } from "./recognition.js";
|
|
146
147
|
import { meaningOf } from "./resonance.js";
|
|
@@ -333,6 +334,10 @@ export class Mind implements MindContext {
|
|
|
333
334
|
* first-edge behaviour) and the reverse projection uses it for
|
|
334
335
|
* reverse-recall disambiguation via `chooseAmong`. */
|
|
335
336
|
_edgeGuide: Vec | null = null;
|
|
337
|
+
/** See {@link MindContext._edgeAsked}. */
|
|
338
|
+
_edgeAsked:
|
|
339
|
+
| { bytes: Uint8Array; index: WindowIndex; points?: readonly number[] }
|
|
340
|
+
| null = null;
|
|
336
341
|
/** Per-response memo of {@link chooseNext} picks — ensures every mechanism
|
|
337
342
|
* of a single response follows the SAME continuation for each ambiguous
|
|
338
343
|
* context node. */
|
|
@@ -647,6 +652,7 @@ export class Mind implements MindContext {
|
|
|
647
652
|
this.canon = null;
|
|
648
653
|
this.canonMemo = null;
|
|
649
654
|
this._edgeGuide = null;
|
|
655
|
+
this._edgeAsked = null;
|
|
650
656
|
this._edgeChoice.clear();
|
|
651
657
|
}
|
|
652
658
|
|
|
@@ -225,7 +225,21 @@ export class Precomputed {
|
|
|
225
225
|
return this._attention ??= this.shared(
|
|
226
226
|
"attention",
|
|
227
227
|
() => climbAttentionAll(this.ctx, this.query, this.k),
|
|
228
|
-
)
|
|
228
|
+
).then((read) => {
|
|
229
|
+
// The climb's scored anchors are what the exact tier reads co-instances
|
|
230
|
+
// of the question from (traverse.ts, `relationFrames`): the
|
|
231
|
+
// approximate climb proposes, witnessing decides.
|
|
232
|
+
// A pick made before the points existed read less evidence than one
|
|
233
|
+
// made after, so the response's pick memo starts over (traverse.ts,
|
|
234
|
+
// guidedNext: a pick is a function of the store, the guide AND the
|
|
235
|
+
// points — traced and untraced responses must agree).
|
|
236
|
+
const asked = this.ctx._edgeAsked;
|
|
237
|
+
if (asked !== null && asked.points === undefined) {
|
|
238
|
+
asked.points = read.ranked.map((a) => a.anchor);
|
|
239
|
+
this.ctx._edgeChoice.clear();
|
|
240
|
+
}
|
|
241
|
+
return read;
|
|
242
|
+
});
|
|
229
243
|
}
|
|
230
244
|
|
|
231
245
|
private _weave?: Promise<WeaveInfo>;
|
package/src/mind/pipeline.ts
CHANGED
|
@@ -27,7 +27,9 @@ import {
|
|
|
27
27
|
} from "./derivation.js";
|
|
28
28
|
import { rItem } from "./trace.js";
|
|
29
29
|
import { unexplainedLabel } from "./rationale.js";
|
|
30
|
-
import { hubBound } from "./traverse.js";
|
|
30
|
+
import { hubBound, offsetCanon, scaffoldExtents } from "./traverse.js";
|
|
31
|
+
import { windowIndex, witness } from "./evidence.js";
|
|
32
|
+
import { indexOf } from "../bytes.js";
|
|
31
33
|
import {
|
|
32
34
|
type MechanismResult,
|
|
33
35
|
type PipelineMechanism,
|
|
@@ -189,6 +191,13 @@ export async function think(
|
|
|
189
191
|
if (query.length === 0) return null;
|
|
190
192
|
|
|
191
193
|
ctx._edgeGuide = gistOf(ctx, query);
|
|
194
|
+
{
|
|
195
|
+
const asked = offsetCanon(ctx, query);
|
|
196
|
+
ctx._edgeAsked = {
|
|
197
|
+
bytes: asked,
|
|
198
|
+
index: windowIndex(asked, ctx.space.maxGroup),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
192
201
|
ctx._edgeChoice.clear();
|
|
193
202
|
|
|
194
203
|
const t = ctx.trace?.enter("think", [rItem(query, "query")]);
|
|
@@ -690,7 +699,21 @@ export async function think(
|
|
|
690
699
|
const explained = priced.filter(([a, b]) =>
|
|
691
700
|
windowOf([a, b], answer, query, ctx.space.maxGroup) !== null
|
|
692
701
|
);
|
|
693
|
-
|
|
702
|
+
// THE DERIVATION IS BORN OWING ITS DISCRIMINATIVE MATERIAL. The bytes a
|
|
703
|
+
// corpus-global scaffolding window reaches (traverse.ts, `scaffoldExtents`)
|
|
704
|
+
// are nobody's debt — otherwise a later step could claim to pay them by
|
|
705
|
+
// restating ` is `, which every fact holds, and the law (which measures
|
|
706
|
+
// carrying by any window of what is owed) would admit it; the substitution
|
|
707
|
+
// bridge reads gaps the same way (`explainedSpan`). PRICING is untouched:
|
|
708
|
+
// the ladder still charges every unexplained byte, because for a question
|
|
709
|
+
// made of nothing but scaffolding (`How are you today?`) covering those bytes
|
|
710
|
+
// IS the evidence.
|
|
711
|
+
const scaffold = scaffoldExtents(ctx, query);
|
|
712
|
+
const paid = remainderOf(
|
|
713
|
+
query.length,
|
|
714
|
+
[...explained, ...scaffold],
|
|
715
|
+
ctx.space.maxGroup,
|
|
716
|
+
);
|
|
694
717
|
// WHAT THE CONSTRUCTION WITHHOLDS, at or above one quantum: the difference between
|
|
695
718
|
// the remainder paid in full and the remainder paid by carrying. Both readings
|
|
696
719
|
// are the law's, so the floor is applied once and in one place — and the
|
|
@@ -711,8 +734,31 @@ export async function think(
|
|
|
711
734
|
const uncovered = state.remainder;
|
|
712
735
|
|
|
713
736
|
// ── Post-grounding, gated by the declaration and the remainder ────────
|
|
737
|
+
// WHAT THE GROUNDING SPOKE FOR, when it did not declare it: the forms inside
|
|
738
|
+
// the answer that the ASKER already holds. An answer is the asker's material
|
|
739
|
+
// plus what the corpus added — the fact's own value — and only the former was
|
|
740
|
+
// spoken for: re-entering it walks back to the question. The latter is what a
|
|
741
|
+
// chain continues THROUGH. Consuming every form recognised in the answer
|
|
742
|
+
// consumed that too, so a chain could start only where recognition happened
|
|
743
|
+
// to miss the next entity — measured on 133 held-out 2Wiki compositional
|
|
744
|
+
// questions, 3 pivot steps in all once interior recognition named the entity
|
|
745
|
+
// inside every fact. Witnessed exactly, as `chooseNext`'s exact tier reads the
|
|
746
|
+
// question (evidence.ts); a form below one window cannot be witnessed, and is
|
|
747
|
+
// consumed as before.
|
|
748
|
+
const asked = ctx._edgeAsked;
|
|
714
749
|
const preConsumed = declaredUsed ??
|
|
715
|
-
new Set(
|
|
750
|
+
new Set(
|
|
751
|
+
recognise(ctx, answer).sites
|
|
752
|
+
.filter((s) =>
|
|
753
|
+
asked === null || s.end - s.start < ctx.space.maxGroup ||
|
|
754
|
+
witness(
|
|
755
|
+
offsetCanon(ctx, answer.subarray(s.start, s.end)),
|
|
756
|
+
[asked.index],
|
|
757
|
+
ctx.space.maxGroup,
|
|
758
|
+
).complete
|
|
759
|
+
)
|
|
760
|
+
.map((s) => s.payload),
|
|
761
|
+
);
|
|
716
762
|
// A grounding that DECLARED itself complete is not extended: the answer is
|
|
717
763
|
// already a trained form's own continuation, reached through an identity
|
|
718
764
|
// claim about the query, so a multi-hop pivot could only chain past the
|
|
@@ -727,13 +773,14 @@ export async function think(
|
|
|
727
773
|
// Reading the used anchors' OWN bytes here says something stronger and
|
|
728
774
|
// wrong: that nothing INSIDE what was voiced may be pivoted through. A
|
|
729
775
|
// comparison's seat sentence legitimately contains further terms with
|
|
730
|
-
// their own unrelated facts
|
|
731
|
-
//
|
|
732
|
-
//
|
|
776
|
+
// their own unrelated facts — `Mona Lisa`, inside the voiced seat `The Mona
|
|
777
|
+
// Lisa was painted by Leonardo da Vinci.`, leads on to `Mona Lisa hangs in
|
|
778
|
+
// the Louvre`, which is about neither analog (test/29 C3: a candidate the
|
|
779
|
+
// walk takes only when the question names it).
|
|
733
780
|
// The withheld content is the used anchors' CONTINUATIONS, so that is what
|
|
734
781
|
// the containment rule reads: `speare` is contained in `Shakespeare wrote
|
|
735
782
|
// 39 plays` and stays refused, while `Mona Lisa` appears in no withheld
|
|
736
|
-
// continuation and
|
|
783
|
+
// continuation and stays a candidate.
|
|
737
784
|
//
|
|
738
785
|
// Only a mechanism carrying its own `used` set (cast/join) gets this: there
|
|
739
786
|
// `preConsumed` is a deliberate, short list of the anchors the answer
|
|
@@ -741,8 +788,17 @@ export async function think(
|
|
|
741
788
|
// `preConsumed` is derived by re-recognising the answer — "everything in
|
|
742
789
|
// it", not "what it voiced" — and a containment rule over that would
|
|
743
790
|
// suppress every pivot the answer legitimately contains.
|
|
791
|
+
//
|
|
792
|
+
// …and a continuation the ANSWER ITSELF holds was voiced, not withheld. A
|
|
793
|
+
// substitution that answers with its anchor's own continuation (`The director
|
|
794
|
+
// of Beat Girl is Edmond T. Gréville.`) declared that anchor used, so reading
|
|
795
|
+
// its continuations as withheld refused every pivot inside the answer — the
|
|
796
|
+
// chain could never step past the entity the first hop introduced.
|
|
744
797
|
const voiced = declaredUsed === undefined ? [] : [...declaredUsed].flatMap(
|
|
745
|
-
(id) =>
|
|
798
|
+
(id) =>
|
|
799
|
+
ctx.store.nextFirst(id, hubBound(ctx))
|
|
800
|
+
.map((n) => read(ctx, n))
|
|
801
|
+
.filter((v) => indexOf(answer, v, 0) < 0),
|
|
746
802
|
);
|
|
747
803
|
// WHAT THIS BRANCH READ, published where it was read. Post-grounding decides
|
|
748
804
|
// by the DECLARATION (`decided.used`, which becomes `voiced`), by what the
|