@hviana/sema 0.9.2 → 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.
Files changed (40) 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 +17 -17
  20. package/docs/INVARIANTS.md +1 -1
  21. package/docs/architecture/evidence.md +172 -29
  22. package/jsr.json +1 -1
  23. package/package.json +1 -1
  24. package/src/meter.ts +6 -0
  25. package/src/mind/evidence.ts +22 -4
  26. package/src/mind/mechanisms/cast.ts +77 -3
  27. package/src/mind/mechanisms/cover.ts +6 -22
  28. package/src/mind/mechanisms/recall.ts +107 -9
  29. package/src/mind/mechanisms/reference.ts +24 -1
  30. package/src/mind/mind.ts +3 -1
  31. package/src/mind/pipeline-mechanism.ts +15 -1
  32. package/src/mind/pipeline.ts +5 -4
  33. package/src/mind/reasoning.ts +33 -15
  34. package/src/mind/resonance.ts +3 -2
  35. package/src/mind/traverse.ts +338 -6
  36. package/src/mind/types.ts +6 -2
  37. package/test/154-the-question-names-the-step.test.mjs +88 -1
  38. package/test/155-the-relation-read-off-another-instance.test.mjs +376 -0
  39. package/test/29-counterfactual.test.mjs +21 -11
  40. package/test/76-reference-binding.test.mjs +32 -0
@@ -2,8 +2,11 @@
2
2
 
3
3
  > **Law:** a stored form is identified by the material at hand when every one of
4
4
  > its bytes lies in a W-window that material holds — in any order, at any place,
5
- > and wherever each piece of the material came from. A step the question did not
6
- > name has to be paid for by material the question still owes.
5
+ > and wherever each piece of the material came from. A form witnessed in every
6
+ > byte but one contiguous span of content is ANOTHER INSTANCE of the same
7
+ > question: it says what the question's relation is, never what it asks about. A
8
+ > step the question did not name has to be paid for by material the question
9
+ > still owes.
7
10
 
8
11
  ## The operation — `src/mind/evidence.ts`
9
12
 
@@ -13,7 +16,8 @@
13
16
  (which finds containers). It is exact, deterministic and linear: one index per
14
17
  source and one probe per window of the form. A window is credited to the LAST
15
18
  source that holds it, so source 0 (the question) is credited only with what
16
- nothing else at hand supplies. A form shorter than W is never witnessed.
19
+ nothing else at hand supplies. A form shorter than W is never witnessed. The
20
+ form's own unwitnessed bytes come back as its `residue`.
17
21
 
18
22
  ## Where the material comes from
19
23
 
@@ -35,15 +39,119 @@ question nor the first hop's fact, only by both. Measured over 5,236 held-out
35
39
  2WikiMultihopQA compositional questions, such a context is wholly witnessed by
36
40
  the question alone 69 times, and by the question plus the first hop 2,153 times.
37
41
 
42
+ An establishing context is a DEPOSITED context: a predecessor with structural
43
+ parents or containers is a span interned inside bigger forms, and it inherits
44
+ their edges. Witnessing such a fragment named every fact it is a piece of (the
45
+ fragment `born?` named nine strangers' birthplaces on the 2Wiki fixture with
46
+ one-hop questions), so it never counts — the same structural predicate
47
+ `pivotInto` reads.
48
+
49
+ ## Another instance of the question — `coInstanceFiller`, `byCoInstance`
50
+
51
+ The question rarely spells the relation the way the corpus does.
52
+ `When was the
53
+ director of film Jinpa born?` reaches `Pema Tseden`, whose fact is
54
+ established by `Pema Tseden date of birth`: no window joins `born` to
55
+ `date of birth`, so nothing is witnessed. What joins them is another instance of
56
+ the question.
57
+
58
+ A **co-instance** is a stored context that shares the question's FRAME, its
59
+ opening and its close byte for byte under the response's equivalence, around ONE
60
+ different filler, and whose filler is a thing the corpus knows: a stored context
61
+ with continuations of its own. `Where was Peter Jackson born?`, read against
62
+ `Where was the director of film Beat Girl born?`, shares `Where was` and `born?`
63
+ and leaves `Peter Jackson`. Three conditions make the reading exact, and each
64
+ was measured necessary:
65
+
66
+ - **Order.** A frame is not a bag of windows. Read order-free,
67
+ `Lyon is a city in France` passes for an instance of
68
+ `what if the capital of France were Lyon?`, which NAMES Lyon, and a
69
+ coincidental window inside a filler splits it.
70
+ - **The filler is an entity.**
71
+ `Explain how photosynthesis converts sunlight
72
+ into chemical energy.` shares
73
+ a frame with `Explain how photosynthesis
74
+ works.`, but its slot holds a
75
+ description of the frame's own subject, and it answers the question. The
76
+ filler is the longest stored context opening where the slot opens (up to one
77
+ window earlier: the `T` of `Taika` can sit in the question's `as t`).
78
+ - **The frame is unsaid.** Every frame window must be held by the material, so
79
+ on the walk a frame a product already said cannot name a second step.
80
+ `Who is the father of …?` names the second hop of
81
+ `Who is the father of the director of film Beat Girl?` and not the
82
+ grandfather. Scaffolding windows are exempt, because they are nobody's
83
+ evidence (`is` in `Which country Leo Mittler is from?`).
84
+
85
+ The co-instance's continuation is established by other contexts too
86
+ (`Peter Jackson place of birth`), and the one holding the filler spells the
87
+ relation the corpus's way: a RELATION FRAME, `` · `place of birth`. A frame
88
+ counts only where two co-instances spell it alike. One alignment agrees with
89
+ nothing, which is the bar `reference` holds a frame to (`MIN_INSTANCES`). The
90
+ exact tier's second reading (`byCoInstance`, run only when no establishing
91
+ context is witnessed outright) puts the node the derivation stands on in each
92
+ frame and looks the result up by content: `Edmond T. Gréville place of birth`
93
+ exists, so its continuation is named. Neither the equivalence nor the frame is
94
+ stored as a unit, and nothing is approximate.
95
+
96
+ **The proposals are the consensus climb's.** The climb already scores the stored
97
+ forms the question's regions reach, and the co-instances are among its points.
98
+ Its scored anchors are published on the question when it runs, and the tier
99
+ reads the `chainReach(W)` most corroborated of them. It climbs nothing of its
100
+ own. A first version climbed every question window itself and cost the 116-query
101
+ battery +16% climb visits for zero namings. Two consequences follow, both
102
+ pinned:
103
+
104
+ - A pick made before the climb read less evidence than one made after, so the
105
+ response's pick memo is cleared when the points arrive. Traced and untraced
106
+ responses agree.
107
+ - Recall's argument binding, which runs before the climb, asks for it first when
108
+ the argument has several continuations and the question names none outright.
109
+ That is exactly where the choice would otherwise be blind.
110
+
111
+ A question the corpus holds verbatim is its own instance and reads no frames.
112
+ Frames are read once per question (and once per walk material), and every node
113
+ pays only the exact lookups.
114
+
115
+ The same reading refuses the co-instance as an ANSWER, because its own
116
+ continuation speaks of its own filler. Recall's consensus-anchor tier does not
117
+ ground it: `Where was the performer of song God (John Lennon Song) born?`
118
+ elected `Where was Nicki Minaj (Nicki Minaj Song) born?`. Fusion does not fuse
119
+ it as a further topic. A CAST comparison does not take it as its dominant: it
120
+ set `Where was Shakira (Shakira Song) born?` against `John Lennon` and voiced
121
+ Shakira's birthplace.
122
+
123
+ ## Arguments the question holds under the response's equivalence
124
+
125
+ Recognition matches bytes and the query fold's own boundaries. 2Wiki title-cases
126
+ its questions (`… of film Man At Bath work at?` for the stored `Man at Bath`),
127
+ and a title inside a question lines up with none of the fold's cuts. When
128
+ recall's argument binding finds no recognised argument, the stored forms the
129
+ consensus climb reaches become candidates if the question holds them under the
130
+ response's equivalence (`canonHeldPoints`: canonical containment,
131
+ offset-preserving, so the span is the question's own). The approximate climb
132
+ proposes and exact containment decides. This is read after the clean-resonance
133
+ tier, so a near-identical question pays no climb for it. The canonical-form
134
+ index it relies on is the one the trainer builds after training
135
+ (`buildCanonIndex`, progress.ts).
136
+
137
+ A fragment that answers other questions is no argument and no independent piece
138
+ of the question either. It is set aside BEFORE the binding looks for one maximal
139
+ argument, so `director` no longer cancels `Man at Bath`. The same predicate
140
+ gates CAST's redirection: the substitute `ong)?`, the tail of every
141
+ `… (… Song)?` question, voiced a stranger's birthplace.
142
+
38
143
  ## Its consumers
39
144
 
40
- | Where | What it decides |
41
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
42
- | `chooseNext` (traverse.ts) | **The exact tier.** It names the continuation one of whose establishing contexts (other than the node) is witnessed by the question plus the node, with the question supplying at least one window the node does not. It ranks first among the readings; the distributional ladder decides only when nothing is named, or among continuations named equally. |
43
- | `askedEvidence` (traverse.ts) | The question spans that named a pick. A mechanism projecting through the pick accounts for them, because evidence travels (mechanism-market.md). Recall's argument binding uses this. |
44
- | `preConsumed` (pipeline.ts) | When a grounding does not declare `used`, what it spoke for is the forms inside its answer that the question already holds. The entity the answer added stays pivotable. |
45
- | The walk (reasoning.ts) | A pivot is NAMED when one of its continuation's establishing contexts is witnessed by what of the question no product has said yet, plus the pivot. A named pivot MOVES. An unnamed one is offered only while the derivation still owes something, and the law then decides by carrying. |
46
- | Cover sites (mechanisms/cover.ts) | A FRAGMENT is a form that sits inside other forms, has several continuations, and leaves at least one window of the question beyond it. It answers other questions, so it leads somewhere for this question only when the question names one of its continuations. |
145
+ | Where | What it decides |
146
+ | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | `chooseNext` (traverse.ts) | **The exact tier.** It names the continuation one of whose establishing contexts (other than the node) is witnessed by the question plus the node, with the question supplying at least one window the node does not. It ranks first among the readings; the distributional ladder decides only when nothing is named, or among continuations named equally. |
148
+ | `askedEvidence` (traverse.ts) | The question spans that named a pick. A mechanism projecting through the pick accounts for them, because evidence travels (mechanism-market.md). Recall's argument binding uses this. |
149
+ | `preConsumed` (pipeline.ts) | When a grounding does not declare `used`, what it spoke for is the forms inside its answer that the question already holds. The entity the answer added stays pivotable. |
150
+ | The walk (reasoning.ts) | A pivot is NAMED when one of its continuation's establishing contexts is witnessed by what of the question no product has said yet, plus the pivot. A named pivot MOVES. An unnamed one is offered only while the derivation still owes something, and the law then decides by carrying. No grounding owns the next step: a CAST grounding used to move through any term inside its answer, unasked (`Who is the director of The Jerk?` walked on to Carl Reiner's citizenship). |
151
+ | `answersOtherQuestions` (traverse.ts) — cover sites and recall's argument binding | A FRAGMENT is a form that sits inside other forms, has several continuations, and leaves at least one window of the question beyond it. It answers other questions, so it leads somewhere for this question only when the question names one of its continuations. Recall's binding read the same fragment (`director`) and voiced the most-poured stranger's fact. |
152
+ | `byCoInstance` (traverse.ts) | The exact tier's second reading: the relation read off another instance of the question, transferred to the node by an exact substitution. |
153
+ | Recall's consensus anchor, fusion roots | A co-instance of the question is never voiced as its answer, nor fused as a further topic. |
154
+ | CAST comparison (mechanisms/cast.ts) | A comparison voices two structures, so the question must evidence the analog with a window of its own: neither inside the dominant's runs nor scaffolding. `father of Frederick II?` evidenced `Peter III of Aragon father` only with `father` and `of`, and the comparison glued that bare question onto the answer. |
47
155
 
48
156
  A cover span made of nothing but scaffolding (every window a hub,
49
157
  `scaffoldSpans`) is not accounted. The form recognised there, such as the song
@@ -85,24 +193,44 @@ memoized per node per question.
85
193
 
86
194
  ## Measured
87
195
 
88
- | Measure | Before | After |
89
- | -------------------------------------------------------------------------------------- | ------ | ------ |
90
- | 2Wiki held-out fixture (300 rows, deposited as `wiki2.ts` does), compositional correct | 13/133 | 47/133 |
91
- | Same fixture, pivot steps | 3 | 90+ |
92
- | Same fixture, inference correct | 8/37 | 6/37 |
93
-
94
- The inference drop is real. Two hops of `father` from a question that says
95
- `father` once, as in `paternal grandfather`, used to be reached by
96
- over-extension and are no longer. The store holds no evidence that `grandfather`
97
- composes `father` twice.
98
-
99
- On the 31.7M-node store's 116-query battery, two answers became correct
100
- (`What country is Jerry Bock a citizen of?` and
101
- `What is the country of citizenship of Frederick II?`), two lost a junk
102
- composition, three changed between wrong answers, and no correct answer was
103
- lost. CPU was 150 s against two baseline runs of 139 s and 166 s, inside the
104
- noise. The deterministic read counters rose about 20% (`bytesRead`,
105
- `nodeRecords`), with ANN queries unchanged.
196
+ 2Wiki held-out fixture: the evidence triples of 300 validation rows, deposited
197
+ as `wiki2.ts` does, with the canonical-form index built as the trainer builds
198
+ it, and asked the rows' own composed questions. Same evidence "plus instances":
199
+ 261 one-hop questions about OTHER entities, built from other validation rows by
200
+ replacing the first hop's phrase with its referent
201
+ (`Where was the director of film X born?` → `Where was Óskar Jónasson born?`)
202
+ and answered with the second hop's fact. No test entity has one.
203
+
204
+ | Compositional correct (of 133) | Witnessing only (655b192) | Final |
205
+ | ------------------------------ | ------------------------- | ----- |
206
+ | Fixture | 52 | 56 |
207
+ | Plus instances | 41 | 89 |
208
+
209
+ The first hop is now right on 114 and 109 of the 133. Of the first hops still
210
+ wrong, most name the entity differently from the corpus (`Clara Novello` for
211
+ `Clara Anastasia Novello`). That is an alias, which no byte reading recovers.
212
+
213
+ Removing CAST's unasked step cost six right answers on the fixture without
214
+ instances: second hops that were right paraphrases taken without evidence
215
+ (`work at`, `is from`, `When was … born`). The same licence produced the Carl
216
+ Reiner extension on the trained store. Without an instance, nothing names those
217
+ relations, and the chain stops at the first hop. The answers gained plus
218
+ instances are those relations: `born` → place of birth, `Why did … die` → cause
219
+ of death, `study`/`graduate from` → educated at, `work at` → employer, `is from`
220
+ → country of citizenship.
221
+
222
+ The inference count stays low. Two hops of `father` from a question that says
223
+ `father` once, as in `paternal grandfather`, are not composed: the store holds
224
+ no evidence that `grandfather` composes `father` twice.
225
+
226
+ On the 31.7M-node store's 116-query battery, two dialogue answers changed
227
+ (neither was correct before). The deterministic read counters rose about 4%
228
+ (`bytesRead`, `ancestorVisits`, `edgeProbes`), with ANN queries up 1%. CPU on
229
+ this workstation varies by ±15% between back-to-back runs of one build, and
230
+ paired runs read 163 s against 152 s and 171 s, then 223 s against 203 s under
231
+ outside load. The co-instance tier read 190 forms over the battery and named
232
+ nothing there: on that store a frame's windows are scaffolding, and the one-hop
233
+ questions it would need are not in the corpus.
106
234
 
107
235
  ## Pins
108
236
 
@@ -110,4 +238,19 @@ noise. The deterministic read counters rose about 20% (`bytesRead`,
110
238
  most-poured one. The second hop is named by the question plus the introduced
111
239
  entity, whatever grounded the first hop. A question that names no further step
112
240
  is not extended. A fragment voices none of its continuations unless the
113
- question names one. Each assertion was verified by mutation.
241
+ question names one, in the cover and in recall's argument binding. A
242
+ comparison needs two things named. An argument held only under the response's
243
+ equivalence binds. Each assertion was verified by mutation.
244
+ - `test/155` — the relation read off another instance of the frame; absent
245
+ without two instances that agree; refused for a partly shared frame; never
246
+ voiced as the answer; a frame a product already said names no further step; a
247
+ description in the slot is no other instance; traced and untraced responses
248
+ agree; fusion does not fuse a co-instance, nor does a comparison take one as
249
+ its dominant. Verified by mutation.
250
+ - `test/76` — a fact the corpus files under an instance's filler is no carriage:
251
+ `reference` does not construct one for a new referent.
252
+ - `test/29` C3 — a further hop inside a comparison's seat waits to be asked.
253
+ - Unpinned, measured only at fixture scale. Excluding fragments from
254
+ establishing contexts is worth 16 answers on the fixture with one-hop
255
+ questions. Refusing a fragment as CAST's redirection substitute is worth four.
256
+ Fragments with inherited edges appear only at that scale.
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://jsr.io/schema/config-file.v1.json",
3
3
  "name": "@hviana/sema",
4
- "version": "0.9.2",
4
+ "version": "0.9.3",
5
5
  "exports": "./src/index.ts"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hviana/sema",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "Sema: a non-parametric, instance-based reasoning system.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/meter.ts CHANGED
@@ -275,6 +275,12 @@ export class Meter {
275
275
  * came back at the √N cap, or its predecessor budget ran out before every
276
276
  * continuation was asked about — the distributional ladder decided. */
277
277
  askedReadsSaturated = 0;
278
+ /** Picks named by a CO-INSTANCE of the question — another instance of its
279
+ * frame whose continuation carries the relation over to this node by an
280
+ * exact substitution (traverse.ts, `byCoInstance`). */
281
+ coInstanceNamings = 0;
282
+ /** Proposed co-instances that tier read and witnessed. */
283
+ coInstanceReads = 0;
278
284
  /** Cover sites dropped as FRAGMENTS whose several continuations the question
279
285
  * names none of (mechanisms/cover.ts). */
280
286
  unaskedFragments = 0;
@@ -63,6 +63,12 @@ export interface Witnessing {
63
63
  spans: Array<[number, number]>;
64
64
  /** Bytes of source 0 inside `spans`. */
65
65
  bytes: number;
66
+ /** The form's own bytes no source witnesses, as merged spans of the FORM —
67
+ * empty exactly when `complete`. ONE residue span is the shape of a
68
+ * co-instance: the same frame around a different filler (`When was Peter
69
+ * Jackson born?` read against `When was the director of film Jinpa
70
+ * born?` leaves `Peter Jackson`). */
71
+ residue: Array<[number, number]>;
66
72
  }
67
73
 
68
74
  /** Witness `form` against `sources` (their window indexes, same order). A
@@ -73,8 +79,14 @@ export function witness(
73
79
  indexes: ReadonlyArray<WindowIndex>,
74
80
  W: number,
75
81
  ): Witnessing {
76
- const none: Witnessing = { complete: false, spans: [], bytes: 0 };
77
- if (form.length < W || indexes.length === 0) return none;
82
+ if (form.length < W || indexes.length === 0) {
83
+ return {
84
+ complete: false,
85
+ spans: [],
86
+ bytes: 0,
87
+ residue: form.length > 0 ? [[0, form.length]] : [],
88
+ };
89
+ }
78
90
  const covered = new Uint8Array(form.length);
79
91
  const own: Array<[number, number]> = [];
80
92
  for (let o = 0; o + W <= form.length; o++) {
@@ -93,7 +105,13 @@ export function witness(
93
105
  covered.fill(1, o, o + W);
94
106
  if (from === 0) own.push([at, at + W]);
95
107
  }
96
- for (let i = 0; i < form.length; i++) if (!covered[i]) return none;
108
+ const residue: Array<[number, number]> = [];
109
+ for (let i = 0; i < form.length; i++) {
110
+ if (covered[i]) continue;
111
+ const last = residue[residue.length - 1];
112
+ if (last !== undefined && last[1] === i) last[1] = i + 1;
113
+ else residue.push([i, i + 1]);
114
+ }
97
115
  own.sort((a, b) => a[0] - b[0]);
98
116
  const spans: Array<[number, number]> = [];
99
117
  for (const [s, e] of own) {
@@ -103,5 +121,5 @@ export function witness(
103
121
  }
104
122
  let bytes = 0;
105
123
  for (const [s, e] of spans) bytes += e - s;
106
- return { complete: true, spans, bytes };
124
+ return { complete: residue.length === 0, spans, bytes, residue };
107
125
  }
@@ -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;