@hviana/sema 0.9.2 → 0.9.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.
Files changed (41) hide show
  1. package/dist/src/meter.d.ts +6 -0
  2. package/dist/src/meter.js +6 -0
  3. package/dist/src/mind/evidence.d.ts +6 -0
  4. package/dist/src/mind/evidence.js +19 -7
  5. package/dist/src/mind/mechanisms/cast.d.ts +1 -1
  6. package/dist/src/mind/mechanisms/cast.js +73 -12
  7. package/dist/src/mind/mechanisms/cover.js +4 -20
  8. package/dist/src/mind/mechanisms/recall.js +84 -8
  9. package/dist/src/mind/mechanisms/reference.js +25 -0
  10. package/dist/src/mind/mind.d.ts +1 -0
  11. package/dist/src/mind/pipeline-mechanism.js +15 -1
  12. package/dist/src/mind/pipeline.js +5 -4
  13. package/dist/src/mind/reasoning.js +28 -16
  14. package/dist/src/mind/resonance.d.ts +3 -2
  15. package/dist/src/mind/resonance.js +3 -2
  16. package/dist/src/mind/traverse.d.ts +52 -0
  17. package/dist/src/mind/traverse.js +334 -7
  18. package/dist/src/mind/types.d.ts +4 -1
  19. package/docs/INDEX.md +21 -17
  20. package/docs/INVARIANTS.md +1 -1
  21. package/docs/PHILOSOPHY.md +317 -0
  22. package/docs/architecture/evidence.md +172 -29
  23. package/jsr.json +1 -1
  24. package/package.json +1 -1
  25. package/src/meter.ts +6 -0
  26. package/src/mind/evidence.ts +22 -4
  27. package/src/mind/mechanisms/cast.ts +77 -3
  28. package/src/mind/mechanisms/cover.ts +6 -22
  29. package/src/mind/mechanisms/recall.ts +107 -9
  30. package/src/mind/mechanisms/reference.ts +24 -1
  31. package/src/mind/mind.ts +3 -1
  32. package/src/mind/pipeline-mechanism.ts +15 -1
  33. package/src/mind/pipeline.ts +5 -4
  34. package/src/mind/reasoning.ts +33 -15
  35. package/src/mind/resonance.ts +3 -2
  36. package/src/mind/traverse.ts +338 -6
  37. package/src/mind/types.ts +6 -2
  38. package/test/154-the-question-names-the-step.test.mjs +88 -1
  39. package/test/155-the-relation-read-off-another-instance.test.mjs +376 -0
  40. package/test/29-counterfactual.test.mjs +21 -11
  41. 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 relies on for a further hop.
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 ` +
@@ -19,9 +19,9 @@ import type {
19
19
  } from "../graph-search.js";
20
20
  import { read, resolve } from "../primitives.js";
21
21
  import {
22
+ answersOtherQuestions,
22
23
  guidedFirst,
23
24
  hubBound,
24
- namedContinuations,
25
25
  scaffoldSpans,
26
26
  } from "../traverse.js";
27
27
  import { conceptHop } from "../match.js";
@@ -259,27 +259,11 @@ export const coverMechanism: PipelineMechanism = {
259
259
  );
260
260
  }
261
261
 
262
- // A FRAGMENT ANSWERS OTHER QUESTIONS. A recognised form that sits inside
263
- // other forms (it has structural parents or containers) holds continuations
264
- // because the forms it is a piece of were asked — suffix inheritance gives
265
- // `f death` the answer of every `… place of death` question. Choosing one of
266
- // several such continuations by popularity voices some other question's
267
- // answer, and the cover used to account the fragment's bytes as explained by
268
- // it. A fragment with several continuations leads somewhere FOR THIS
269
- // QUESTION only when the question names one (traverse.ts, the exact tier).
270
- // A form that is (nearly) the whole question is not a piece of it: the
271
- // question says nothing beyond it, so its continuations answer THIS question.
272
- const asked = ctx._edgeAsked;
273
- const W0 = ctx.space.maxGroup;
274
- const leading = asked === null
275
- ? sites
276
- : sites.filter((s) =>
277
- query.length - (s.end - s.start) < W0 ||
278
- !(ctx.store.hasParents(s.payload) ||
279
- ctx.store.hasContainers(s.payload)) ||
280
- ctx.store.nextFirst(s.payload, 2).length < 2 ||
281
- namedContinuations(ctx, s.payload, asked) !== null
282
- );
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
+ );
283
267
  if (leading.length < sites.length) {
284
268
  if (ctx.meter) {
285
269
  ctx.meter.unaskedFragments += sites.length - leading.length;
@@ -17,10 +17,14 @@ import { gistOf, read, resolve } from "../primitives.js";
17
17
  import { indexOf } from "../../bytes.js";
18
18
  import {
19
19
  allWindowsAreScaffolding,
20
+ answersOtherQuestions,
20
21
  askedEvidence,
22
+ canonHeldPoints,
23
+ coInstanceFiller,
21
24
  corpusN,
22
25
  guidedFirst,
23
26
  hubBound,
27
+ namedContinuations,
24
28
  } from "../traverse.js";
25
29
  import {
26
30
  follow,
@@ -108,13 +112,13 @@ export async function recallByResonance(
108
112
  // constituent bar is the same two-quanta (2W) reading confluence binds
109
113
  // under, nested recognitions collapse to their MAXIMAL span, and two
110
114
  // distinct maximal arguments mean the query asks about neither alone.
111
- if (qId === null) {
112
- const W2 = 2 * ctx.space.maxGroup;
113
- const args = pre.rec.sites.filter((s) =>
114
- s.end - s.start >= W2 &&
115
- s.end - s.start < query.length &&
116
- ctx.store.hasNext(s.payload)
117
- );
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
+ ) => {
118
122
  // Maximal spans by one sorted sweep (starts ascending, ties longest
119
123
  // first): every earlier span starts at or before s, so s is contained
120
124
  // exactly when the running max end already covers it. O(m log m) — a
@@ -140,13 +144,25 @@ export async function recallByResonance(
140
144
  // binding to the argument's continuation would answer past content
141
145
  // the query itself already carries forward. Derived from the same W2
142
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.
143
148
  const hasSubstantialOutside = maximal.length === 1 &&
144
149
  pre.rec.sites.some((s) =>
145
- s.end - s.start >= W2 &&
150
+ s.end - s.start >= W2 && !strangerIds.has(s.payload) &&
146
151
  (s.end <= maximal[0].start || s.start >= maximal[0].end)
147
152
  );
148
153
  if (maximal.length === 1 && !hasSubstantialOutside) {
149
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();
150
166
  const g = await follow(ctx, arg.payload, queryGist);
151
167
  // The same "no restated fragment" guard tier 2 applies below (§ "the
152
168
  // anchor cleared the consensus floor..."): a followed continuation
@@ -176,6 +192,53 @@ export async function recallByResonance(
176
192
  );
177
193
  }
178
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;
179
242
  }
180
243
 
181
244
  // The response's ONE top-k read (Precomputed.resonance) — the same list the
@@ -272,6 +335,20 @@ export async function recallByResonance(
272
335
  Math.sqrt(otherLen / Math.max(1, query.length)),
273
336
  );
274
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
+
275
352
  // 2. Scaffolding-dominated.
276
353
  if (top.score >= sig) {
277
354
  // The committed points of attention ARE the shared climb's roots (same
@@ -403,7 +480,28 @@ export async function recallByResonance(
403
480
  forest[0].anchor,
404
481
  query.length * ctx.space.maxGroup + 1,
405
482
  );
406
- if (g !== null && voicesDisplacedFiller(ctx, query, anchorBytes, g)) {
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
+ ) {
407
505
  ctx.trace?.step(
408
506
  "displacedFiller",
409
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
@@ -335,7 +335,9 @@ export class Mind implements MindContext {
335
335
  * reverse-recall disambiguation via `chooseAmong`. */
336
336
  _edgeGuide: Vec | null = null;
337
337
  /** See {@link MindContext._edgeAsked}. */
338
- _edgeAsked: { bytes: Uint8Array; index: WindowIndex } | null = null;
338
+ _edgeAsked:
339
+ | { bytes: Uint8Array; index: WindowIndex; points?: readonly number[] }
340
+ | null = null;
339
341
  /** Per-response memo of {@link chooseNext} picks — ensures every mechanism
340
342
  * of a single response follows the SAME continuation for each ambiguous
341
343
  * context node. */
@@ -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>;
@@ -773,13 +773,14 @@ export async function think(
773
773
  // Reading the used anchors' OWN bytes here says something stronger and
774
774
  // wrong: that nothing INSIDE what was voiced may be pivoted through. A
775
775
  // comparison's seat sentence legitimately contains further terms with
776
- // their own unrelated facts, and C3 pins exactly that — `Mona Lisa`, inside
777
- // the voiced seat `The Mona Lisa was painted by Leonardo da Vinci.`, leads
778
- // on to `Mona Lisa hangs in the Louvre`, which is about neither analog.
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).
779
780
  // The withheld content is the used anchors' CONTINUATIONS, so that is what
780
781
  // the containment rule reads: `speare` is contained in `Shakespeare wrote
781
782
  // 39 plays` and stays refused, while `Mona Lisa` appears in no withheld
782
- // continuation and the genuine further hop fires.
783
+ // continuation and stays a candidate.
783
784
  //
784
785
  // Only a mechanism carrying its own `used` set (cast/join) gets this: there
785
786
  // `preConsumed` is a deliberate, short list of the anchors the answer
@@ -9,6 +9,7 @@ import type { Attention, MindContext } from "./types.js";
9
9
  import { read, resolve } from "./primitives.js";
10
10
  import { countClusters } from "./attention.js";
11
11
  import {
12
+ coInstanceFiller,
12
13
  guidedFirst,
13
14
  hubBound,
14
15
  namedContinuations,
@@ -255,16 +256,12 @@ export function walkLayer(
255
256
  // 30 s); and raising it from 12 to 200 changed neither the answer nor
256
257
  // `pivotSteps` on the chain fixtures.
257
258
  const qv = pre.guide; // the response-wide guide IS the query's gist
258
- // WHOSE EXTENSION IS THIS? `voiced` is what the mechanism WITHHELD (the
259
- // pipeline sends the used anchors' CONTINUATIONS, not their bytes), so a
260
- // non-empty `voiced` means exactly what that note says: the grounding came
261
- // from a mechanism that carries its own short `used` set (cast/join) and
262
- // therefore OWNS the shape of its answer. The further terms inside such a
263
- // seat are legitimately followable (test/29 C3's `Mona Lisa` lives inside the
264
- // voiced seat and leads on to a fact about neither analog), which the law
265
- // expresses as the identity species of progress — `moves` — declared by the
266
- // reporter and never inferred from the mechanism's name.
267
- const producerOwnsShape = voiced.length > 0;
259
+ // NO PRODUCER OWNS THE NEXT STEP. A grounding that declared what it voiced
260
+ // (cast/join) used to MOVE through any further term inside its answer,
261
+ // unasked — `Who is the director of The Jerk?` grounded by CAST walked on to
262
+ // `The country of citizenship of Carl Reiner is American.` What it voiced
263
+ // still bounds what may be pivoted through (`voiced`, pivotInto); whether a
264
+ // step is taken is the naming rule below, the same for every mechanism.
268
265
  let hop = 0;
269
266
  let t: ReturnType<Rationale["enter"]> | undefined;
270
267
  // WHAT THE OFFERED STEP WOULD BE. The law decides, so the accepted step is
@@ -439,7 +436,7 @@ export function walkLayer(
439
436
  const hop = guidedFirst(ctx, pivot);
440
437
  named = names !== null && hop !== undefined && names.includes(hop);
441
438
  }
442
- if (!named && !producerOwnsShape && closed(d)) {
439
+ if (!named && closed(d)) {
443
440
  ctx.trace?.step(
444
441
  "pivotUnasked",
445
442
  [rItem(cur, "answer"), rNode(ctx, pivot, "pivot")],
@@ -449,15 +446,14 @@ export function walkLayer(
449
446
  return null;
450
447
  }
451
448
  pending = { kind: "pivot", cur, pivot, fc };
452
- // Offered with the identity species when the grounding declared what it
453
- // speaks for, or when the question names the step; otherwise the law
454
- // requires this step to carry question material the grounding left
449
+ // Offered with the identity species when the question names the step;
450
+ // otherwise the law requires this step to carry question material the grounding left
455
451
  // unaccounted, which is the drift the extension tests pin — refused by the
456
452
  // law's own measure, not by a private window test.
457
453
  return {
458
454
  product: fc,
459
455
  contains: true,
460
- reaches: producerOwnsShape || named,
456
+ reaches: named,
461
457
  cost: STEP,
462
458
  };
463
459
  };
@@ -833,6 +829,28 @@ export function fusionLayer(
833
829
  // again would only restate it. Deliberately NOT a magnitude measure:
834
830
  // it fires on exact content-addressed recurrence, not on how strongly
835
831
  // the root resonates.
832
+ // ANOTHER INSTANCE IS NOT ANOTHER TOPIC. A root the question witnesses
833
+ // in every byte but one contiguous span is the question's own frame
834
+ // around a different filler (evidence.ts, `coInstanceFiller`): the climb
835
+ // committed `Where was Peter Jackson born?` as a second point of
836
+ // `Where was the director of film Beat Girl born?` on the frame windows
837
+ // alone, and fusing it voiced Peter Jackson's birthplace beside the
838
+ // answer. Such a root says what the question's relation IS (traverse.ts,
839
+ // `byCoInstance`), never what it asks about.
840
+ const asked = ctx._edgeAsked;
841
+ if (asked !== null) {
842
+ const form = read(ctx, root.anchor, 2 * query.length);
843
+ const co = coInstanceFiller(ctx, form, [asked.index], asked.bytes);
844
+ if (co !== null) {
845
+ ctx.trace?.step(
846
+ "coInstanceRoot",
847
+ [rNode(ctx, root.anchor, "point", root.vote)],
848
+ [rItem(form.subarray(co.span[0], co.span[1]), "filler")],
849
+ "the question witnesses this point in every byte but one filler of its own — another instance of the question's frame, not a further topic",
850
+ );
851
+ continue;
852
+ }
853
+ }
836
854
  const cont = await follow(ctx, root.anchor, qv);
837
855
  if (
838
856
  cont !== null && cont.length > 0 &&
@@ -307,8 +307,9 @@ export async function joinWithBridge(
307
307
  * Shakespeare" (id 676) and the pivot hopped through "speare" (id 606, not
308
308
  * in `consumed`) straight into that analog's own biography, which is exactly
309
309
  * what the comparison had refused to voice. The rule is CONTAINMENT, not
310
- * overlap, so C3's genuine further hop — "Mona Lisa", a term inside the seat
311
- * sentence but part of NEITHER analog — still fires. */
310
+ * overlap, so C3's further term — "Mona Lisa", inside the seat sentence but
311
+ * part of NEITHER analog — stays a candidate; whether the walk steps through
312
+ * it is the naming rule's decision (reasoning.ts, evidence.md). */
312
313
  export async function pivotInto(
313
314
  ctx: MindContext,
314
315
  answer: Uint8Array,