@hviana/sema 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/AGENTS.md +7 -7
  2. package/dist/src/alu/src/index.d.ts +1 -1
  3. package/dist/src/alu/src/index.js +1 -1
  4. package/dist/src/alu/src/parser.js +2 -6
  5. package/dist/src/alu/src/resonance.d.ts +13 -0
  6. package/dist/src/alu/src/resonance.js +41 -0
  7. package/dist/src/alu/test/alu.test.js +39 -0
  8. package/dist/src/bytes.d.ts +6 -2
  9. package/dist/src/bytes.js +10 -4
  10. package/dist/src/canon.js +44 -0
  11. package/dist/src/geometry.d.ts +19 -1
  12. package/dist/src/geometry.js +125 -141
  13. package/dist/src/meter.d.ts +33 -0
  14. package/dist/src/meter.js +34 -1
  15. package/dist/src/mind/articulation.js +14 -1
  16. package/dist/src/mind/attention.d.ts +12 -0
  17. package/dist/src/mind/attention.js +44 -16
  18. package/dist/src/mind/bridge.js +3 -3
  19. package/dist/src/mind/derivation.d.ts +40 -0
  20. package/dist/src/mind/derivation.js +34 -0
  21. package/dist/src/mind/evidence.d.ts +24 -0
  22. package/dist/src/mind/evidence.js +90 -0
  23. package/dist/src/mind/graph-search.d.ts +89 -15
  24. package/dist/src/mind/graph-search.js +345 -174
  25. package/dist/src/mind/learning.js +1 -1
  26. package/dist/src/mind/mechanisms/cover.d.ts +19 -3
  27. package/dist/src/mind/mechanisms/cover.js +142 -61
  28. package/dist/src/mind/mechanisms/recall.js +10 -3
  29. package/dist/src/mind/mind.d.ts +6 -0
  30. package/dist/src/mind/mind.js +5 -2
  31. package/dist/src/mind/pipeline.d.ts +5 -1
  32. package/dist/src/mind/pipeline.js +220 -90
  33. package/dist/src/mind/primitives.d.ts +25 -5
  34. package/dist/src/mind/primitives.js +107 -44
  35. package/dist/src/mind/reasoning.d.ts +18 -4
  36. package/dist/src/mind/reasoning.js +487 -328
  37. package/dist/src/mind/recognition.js +29 -13
  38. package/dist/src/mind/resonance.js +1 -11
  39. package/dist/src/mind/traverse.d.ts +45 -5
  40. package/dist/src/mind/traverse.js +285 -8
  41. package/dist/src/mind/types.d.ts +16 -1
  42. package/dist/src/store-sqlite.d.ts +25 -0
  43. package/dist/src/store-sqlite.js +89 -1
  44. package/dist/src/store.d.ts +48 -4
  45. package/dist/src/store.js +86 -6
  46. package/docs/INDEX.md +20 -19
  47. package/docs/INVARIANTS.md +17 -16
  48. package/docs/architecture/bounded-reads.md +1 -1
  49. package/docs/architecture/caches.md +5 -4
  50. package/docs/architecture/closure.md +45 -5
  51. package/docs/architecture/cost-model.md +16 -0
  52. package/docs/architecture/evidence.md +113 -0
  53. package/docs/architecture/exact-vs-approximate.md +10 -9
  54. package/docs/architecture/factored-machinery.md +14 -13
  55. package/docs/architecture/fold-contract.md +51 -1
  56. package/docs/architecture/mechanism-market.md +21 -0
  57. package/docs/architecture/memoization.md +3 -3
  58. package/docs/architecture/meter.md +2 -1
  59. package/docs/architecture/saturation.md +12 -0
  60. package/docs/architecture/store.md +25 -2
  61. package/docs/failures/tempting-but-wrong.md +13 -2
  62. package/docs/harness/gates.md +12 -10
  63. package/docs/mechanisms/cover.md +23 -6
  64. package/jsr.json +1 -1
  65. package/package.json +1 -1
  66. package/src/alu/README.md +10 -2
  67. package/src/alu/src/index.ts +1 -0
  68. package/src/alu/src/parser.ts +6 -6
  69. package/src/alu/src/resonance.ts +42 -0
  70. package/src/alu/test/alu.test.ts +40 -0
  71. package/src/bytes.ts +13 -3
  72. package/src/canon.ts +40 -0
  73. package/src/geometry.ts +183 -154
  74. package/src/meter.ts +34 -1
  75. package/src/mind/articulation.ts +14 -2
  76. package/src/mind/attention.ts +47 -25
  77. package/src/mind/bridge.ts +3 -3
  78. package/src/mind/derivation.ts +77 -0
  79. package/src/mind/evidence.ts +107 -0
  80. package/src/mind/graph-search.ts +449 -221
  81. package/src/mind/learning.ts +1 -7
  82. package/src/mind/match.ts +1 -2
  83. package/src/mind/mechanisms/cast.ts +1 -2
  84. package/src/mind/mechanisms/cover.ts +207 -87
  85. package/src/mind/mechanisms/extraction.ts +1 -2
  86. package/src/mind/mechanisms/prefix-completion.ts +1 -1
  87. package/src/mind/mechanisms/recall.ts +17 -5
  88. package/src/mind/mechanisms/reference.ts +1 -1
  89. package/src/mind/mind.ts +9 -30
  90. package/src/mind/pipeline.ts +263 -104
  91. package/src/mind/primitives.ts +119 -43
  92. package/src/mind/reasoning.ts +611 -419
  93. package/src/mind/recognition.ts +24 -9
  94. package/src/mind/resonance.ts +2 -16
  95. package/src/mind/trace.ts +1 -1
  96. package/src/mind/traverse.ts +321 -8
  97. package/src/mind/types.ts +15 -11
  98. package/src/store-sqlite.ts +92 -1
  99. package/src/store.ts +113 -7
  100. package/test/105-derive-through-reports-its-refusal.test.mjs +8 -5
  101. package/test/106-the-join-fires.test.mjs +21 -0
  102. package/test/111-the-cover-assembly-is-counted.test.mjs +8 -5
  103. package/test/128-the-leads-somewhere-pair-agrees.test.mjs +18 -12
  104. package/test/136-the-two-named-limits.test.mjs +3 -2
  105. package/test/137-the-law-lives-once-and-below.test.mjs +21 -0
  106. package/test/148-exact-shortcuts-agree.test.mjs +188 -0
  107. package/test/149-the-closure-engine.test.mjs +138 -0
  108. package/test/150-the-join-is-output-sensitive.test.mjs +66 -0
  109. package/test/151-the-cover-pays-for-what-it-reaches.test.mjs +142 -0
  110. package/test/152-the-read-side-names-as-the-write-side.test.mjs +146 -0
  111. package/test/153-a-cheaper-bound-is-looked-at-first.test.mjs +155 -0
  112. package/test/154-the-question-names-the-step.test.mjs +281 -0
  113. package/test/24-generalization.test.mjs +32 -0
  114. package/test/36-bloom.test.mjs +53 -0
  115. package/test/37-cluster-dispersion-fusion.test.mjs +75 -0
  116. package/test/48-recognise-turn-connective.test.mjs +3 -2
  117. package/test/55-cost-meter.test.mjs +4 -4
  118. package/test/90-connector-read-cap.test.mjs +7 -7
@@ -7,13 +7,7 @@ import { addInto, normalize, Vec, zeros } from "../vec.js";
7
7
  import { bindSeat, companySignature, isChunk, Sema } from "../sema.js";
8
8
  import type { Input, MindContext } from "./types.js";
9
9
  import { changedNodes } from "./types.js";
10
- import {
11
- inputBytes,
12
- latin1Key,
13
- perceive,
14
- perceiveDeposit,
15
- resolve,
16
- } from "./primitives.js";
10
+ import { inputBytes, perceiveDeposit, resolve } from "./primitives.js";
17
11
  import { canonicalWindows, leafIdPrefix } from "./canonical.js";
18
12
  import { rItem, rNode } from "./trace.js";
19
13
  import { hubBound } from "./traverse.js";
package/src/mind/match.ts CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  } from "../geometry.js";
41
41
  import { bytesEqual, indexOf, latin1 } from "../bytes.js";
42
42
  import type { MindContext } from "./types.js";
43
- import { chainReach, leafIdRun } from "./canonical.js";
43
+ import { leafIdRun } from "./canonical.js";
44
44
  import { foldTree, gistOf, perceive, read, resolve } from "./primitives.js";
45
45
  import {
46
46
  argmaxCosine,
@@ -54,7 +54,6 @@ import {
54
54
  sharedReachMemo,
55
55
  } from "./traverse.js";
56
56
  import { recognise, segment } from "./recognition.js";
57
- import { rItem } from "./trace.js";
58
57
  import type { Site } from "./graph-search.js";
59
58
 
60
59
  // ═══════════════════════════════════════════════════════════════════════════
@@ -31,9 +31,8 @@ import {
31
31
  } from "../match.js";
32
32
  import { joinWithBridge } from "../resonance.js";
33
33
  import { CONCEPT, STEP } from "../graph-search.js";
34
- import { concat2, indexOf } from "../../bytes.js";
34
+ import { indexOf } from "../../bytes.js";
35
35
  import { consensusFloor, dominates } from "../../geometry.js";
36
- import { decodeText } from "../rationale.js";
37
36
  import { restates, unexplainedSpans } from "../derivation.js";
38
37
  import { rItem, rNode } from "../trace.js";
39
38
  import { dismissedKnownContent } from "../bridge.js";
@@ -10,55 +10,91 @@
10
10
  // ordinary admissible-floor check, with no extension special-case anywhere.
11
11
 
12
12
  import type { MindContext } from "../types.js";
13
- import type { ComputedResult, Site } from "../graph-search.js";
13
+ import type {
14
+ ComputedResult,
15
+ ConceptLicence,
16
+ ConnectorLicence,
17
+ DerivationStep,
18
+ Site,
19
+ } from "../graph-search.js";
14
20
  import { read, resolve } from "../primitives.js";
15
- import { guidedFirst, hubBound } from "../traverse.js";
21
+ import {
22
+ guidedFirst,
23
+ hubBound,
24
+ namedContinuations,
25
+ scaffoldSpans,
26
+ } from "../traverse.js";
16
27
  import { conceptHop } from "../match.js";
17
28
  import { bridge } from "../resonance.js";
18
29
  import { liftAnswer, liftedScaffolding, segRestatesQuery } from "../types.js";
19
30
  import { decodeText } from "../rationale.js";
20
31
  import { insideAnsweredTurn, restates } from "../derivation.js";
21
- import { indexOf } from "../../bytes.js";
22
32
  import type { RationaleItem } from "../rationale.js";
23
33
  import { rItem, rNode, traceDerivation } from "../trace.js";
24
34
  import type { PipelineMechanism } from "../pipeline-mechanism.js";
25
35
 
26
36
  // ── Concept / connector pre-resolution ──────────────────────────────────────
27
37
 
28
- export async function resolveConcepts(
38
+ /** The concept hops the cover may take, OFFERED up front and looked up only
39
+ * when the search asks (see {@link Licence}): every recognised form with no
40
+ * continuation of its own may borrow a halo sibling's. */
41
+ export interface CoverConcepts extends ConceptLicence {
42
+ /** Look up the asked forms' concept targets not yet granted. */
43
+ grant(nodes: Iterable<number>): Promise<void>;
44
+ }
45
+
46
+ export function offerConcepts(
29
47
  ctx: MindContext,
30
- sites: Site[],
31
- ): Promise<Map<number, number>> {
32
- const target = new Map<number, number>();
33
- const visited = new Set<number>();
48
+ sites: ReadonlyArray<Site>,
49
+ ): CoverConcepts {
50
+ const offered = new Set<number>();
34
51
  for (const { payload: n } of sites) {
35
- if (visited.has(n)) continue;
36
- visited.add(n);
37
- if (ctx.store.hasNext(n)) continue;
38
- const hop = await conceptHop(ctx, n);
39
- if (hop !== null) target.set(n, hop);
40
- }
41
- if (target.size > 0) {
42
- ctx.trace?.step(
43
- "resolveConcepts",
44
- [...target.keys()].map((n) => rNode(ctx, n, "edgeless-form")),
45
- [...target.values()].map((h) => rNode(ctx, h, "concept-sibling")),
46
- "borrow a synonym's continuation edge for each edge-less form (a concept/halo hop)",
47
- );
52
+ if (!offered.has(n) && !ctx.store.hasNext(n)) offered.add(n);
48
53
  }
49
- return target;
54
+ const granted = new Map<number, number | null>();
55
+ return {
56
+ offered,
57
+ granted,
58
+ asked: new Set(),
59
+ async grant(nodes) {
60
+ const found: Array<[number, number]> = [];
61
+ for (const n of nodes) {
62
+ if (granted.has(n)) continue;
63
+ const hop = await conceptHop(ctx, n);
64
+ granted.set(n, hop);
65
+ if (hop !== null) found.push([n, hop]);
66
+ }
67
+ if (found.length > 0) {
68
+ ctx.trace?.step(
69
+ "resolveConcepts",
70
+ found.map(([n]) => rNode(ctx, n, "edgeless-form")),
71
+ found.map(([, h]) => rNode(ctx, h, "concept-sibling")),
72
+ "borrow a synonym's continuation edge for each edge-less form the search reached (a concept/halo hop)",
73
+ );
74
+ }
75
+ },
76
+ };
77
+ }
78
+
79
+ /** The connectors the cover may splice, OFFERED up front and BRIDGED only when
80
+ * the search asks (see {@link ConnectorLicence}): every pair a learnt whole
81
+ * could run together — two touching sites, each side as itself or as its
82
+ * answer, in both orders — and, when three or more answers are recognised, the
83
+ * first answer to each later one (the N-ary whole). */
84
+ export interface CoverConnectors extends ConnectorLicence {
85
+ /** Bridge the asked pairs not yet granted. */
86
+ grant(keys: Iterable<string>): Promise<void>;
50
87
  }
51
88
 
52
- export async function resolveConnectors(
89
+ export function offerConnectors(
53
90
  ctx: MindContext,
54
91
  sites: ReadonlyArray<Site>,
55
92
  query?: Uint8Array,
56
- ): Promise<Map<string, Uint8Array>> {
57
- const links = new Map<string, Uint8Array>();
93
+ ): CoverConnectors {
58
94
  const answerOf = (n: number) => guidedFirst(ctx, n) ?? n;
59
95
  // A site's continuation already present elsewhere in the query is stale
60
96
  // transcript evidence: cover still needs the site for structural context,
61
- // but liftAnswer will trim that continuation as already answered. Building
97
+ // but liftAnswer will trim that continuation as already answered. Offering
62
98
  // pairwise/n-ary bridges for it can only create connectors that are later
63
99
  // discarded — a semantically neutral gate (it removes work whose product
64
100
  // liftAnswer throws away), and a cumulative (multi-turn) query is exactly
@@ -98,20 +134,16 @@ export async function resolveConnectors(
98
134
  return restates(query, bytes, 0);
99
135
  });
100
136
  });
101
- const bridgePair = async (l: number, r: number) => {
102
- if (l === r || links.has(l + "," + r)) return;
103
- if (ctx.meter) ctx.meter.coverBridges++;
104
- const link = await bridge(ctx, read(ctx, l), read(ctx, r));
105
- if (link !== null) links.set(l + "," + r, link);
106
- };
137
+ const pairwise = new Set<string>();
107
138
  for (let i = 0; i + 1 < ordered.length; i++) {
108
139
  if (ordered[i].end !== ordered[i + 1].start) continue;
109
140
  const lefts = [ordered[i].payload, answerOf(ordered[i].payload)];
110
141
  const rights = [ordered[i + 1].payload, answerOf(ordered[i + 1].payload)];
111
142
  for (const l of new Set(lefts)) {
112
143
  for (const r of new Set(rights)) {
113
- await bridgePair(l, r);
114
- await bridgePair(r, l);
144
+ if (l === r) continue;
145
+ pairwise.add(l + "," + r);
146
+ pairwise.add(r + "," + l);
115
147
  }
116
148
  }
117
149
  }
@@ -123,46 +155,70 @@ export async function resolveConnectors(
123
155
  seenN.add(node);
124
156
  orderedNodes.push({ node, bytes: read(ctx, node) });
125
157
  }
158
+ const nary = new Map<
159
+ string,
160
+ { left: Uint8Array; right: Uint8Array; allowance: number }
161
+ >();
126
162
  if (orderedNodes.length >= 3) {
127
163
  const first = orderedNodes[0];
128
164
  const W = ctx.space.maxGroup;
129
165
  let middleBytes = 0; // Σ bytes of the answers BETWEEN first and m-th
130
166
  for (let m = 1; m < orderedNodes.length; m++) {
131
- const key = first.node + "," + orderedNodes[m].node;
132
- if (links.has(key)) {
133
- middleBytes += orderedNodes[m].bytes.length;
134
- continue;
135
- }
136
167
  // The N-ary interior legitimately holds every intermediate answer
137
168
  // plus one W-quantum of glue per joint — pass that allowance so the
138
- // bridge's phrase-scale cap admits the whole learnt run.
139
- const allowance = middleBytes + (m + 1) * W;
140
- if (ctx.meter) {
141
- ctx.meter.coverBridges++;
142
- ctx.meter.coverAllowanceBytes += allowance;
143
- }
144
- const interior = await bridge(
145
- ctx,
146
- first.bytes,
147
- orderedNodes[m].bytes,
148
- allowance,
149
- );
150
- if (interior !== null) links.set(key, interior);
169
+ // bridge's phrase-scale cap admits the whole learnt run. Asked only
170
+ // when the pairwise bridge of the same key (if offered) found nothing.
171
+ nary.set(first.node + "," + orderedNodes[m].node, {
172
+ left: first.bytes,
173
+ right: orderedNodes[m].bytes,
174
+ allowance: middleBytes + (m + 1) * W,
175
+ });
151
176
  middleBytes += orderedNodes[m].bytes.length;
152
177
  }
153
178
  }
154
- if (links.size > 0) {
155
- ctx.trace?.step(
156
- "resolveConnectors",
157
- ordered.map((s) => rItem(read(ctx, s.payload), "answer", s.payload)),
158
- [...links.entries()].map(([pair, bytes]) => ({
159
- text: `${pair}: "${decodeText(bytes)}"`,
160
- role: "connector",
161
- } as RationaleItem)),
162
- "the bytes the graph splices between adjacent answers (asked of the gist space)",
163
- );
164
- }
165
- return links;
179
+ const granted = new Map<string, Uint8Array | null>();
180
+ return {
181
+ offered: new Set([...pairwise, ...nary.keys()]),
182
+ granted,
183
+ asked: new Set(),
184
+ async grant(keys) {
185
+ const found: Array<[string, Uint8Array]> = [];
186
+ for (const key of keys) {
187
+ if (granted.has(key)) continue;
188
+ let link: Uint8Array | null = null;
189
+ if (pairwise.has(key)) {
190
+ const comma = key.indexOf(",");
191
+ if (ctx.meter) ctx.meter.coverBridges++;
192
+ link = await bridge(
193
+ ctx,
194
+ read(ctx, Number(key.slice(0, comma))),
195
+ read(ctx, Number(key.slice(comma + 1))),
196
+ );
197
+ }
198
+ const whole = nary.get(key);
199
+ if (link === null && whole !== undefined) {
200
+ if (ctx.meter) {
201
+ ctx.meter.coverBridges++;
202
+ ctx.meter.coverAllowanceBytes += whole.allowance;
203
+ }
204
+ link = await bridge(ctx, whole.left, whole.right, whole.allowance);
205
+ }
206
+ granted.set(key, link);
207
+ if (link !== null) found.push([key, link]);
208
+ }
209
+ if (found.length > 0) {
210
+ ctx.trace?.step(
211
+ "resolveConnectors",
212
+ ordered.map((s) => rItem(read(ctx, s.payload), "answer", s.payload)),
213
+ found.map(([pair, bytes]) => ({
214
+ text: `${pair}: "${decodeText(bytes)}"`,
215
+ role: "connector",
216
+ } as RationaleItem)),
217
+ "the bytes the graph splices between adjacent answers the search reached (asked of the gist space)",
218
+ );
219
+ }
220
+ },
221
+ };
166
222
  }
167
223
 
168
224
  // ── Pipeline mechanism ──────────────────────────────────────────────────────
@@ -178,7 +234,7 @@ export const coverMechanism: PipelineMechanism = {
178
234
 
179
235
  // Masking: computed spans are authoritative. Remove recognised sites
180
236
  // that overlap any computed span before building the cover search.
181
- const sites = computed.length === 0
237
+ let sites = computed.length === 0
182
238
  ? rec.sites
183
239
  : rec.sites.filter((s) =>
184
240
  !computed.some((u) => s.start < u.j && u.i < s.end)
@@ -203,14 +259,53 @@ export const coverMechanism: PipelineMechanism = {
203
259
  );
204
260
  }
205
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
+ );
283
+ if (leading.length < sites.length) {
284
+ if (ctx.meter) {
285
+ ctx.meter.unaskedFragments += sites.length - leading.length;
286
+ }
287
+ ctx.trace?.step(
288
+ "unaskedFragments",
289
+ sites.filter((s) => !leading.includes(s)).map((s) =>
290
+ rItem(query.subarray(s.start, s.end), "fragment", s.payload, [
291
+ s.start,
292
+ s.end,
293
+ ])
294
+ ),
295
+ [],
296
+ "a piece of other forms whose continuations the question names none of — it answers other questions",
297
+ );
298
+ sites = leading;
299
+ }
300
+
206
301
  if (sites.length === 0 && computed.length === 0) return [];
207
302
 
208
303
  const connectors = ctx.meter
209
- ? await ctx.meter.time(
210
- "cover.resolveConnectors",
211
- () => resolveConnectors(ctx, sites, query),
304
+ ? ctx.meter.timeSync(
305
+ "cover.offerConnectors",
306
+ () => offerConnectors(ctx, sites, query),
212
307
  )
213
- : await resolveConnectors(ctx, sites, query);
308
+ : offerConnectors(ctx, sites, query);
214
309
  let splits = rec.splits;
215
310
  if (computed.length > 0) {
216
311
  splits = new Set(rec.splits);
@@ -220,17 +315,15 @@ export const coverMechanism: PipelineMechanism = {
220
315
  }
221
316
  }
222
317
  const concepts = ctx.meter
223
- ? await ctx.meter.time(
224
- "cover.resolveConcepts",
225
- () => resolveConcepts(ctx, sites),
318
+ ? ctx.meter.timeSync(
319
+ "cover.offerConcepts",
320
+ () => offerConcepts(ctx, sites),
226
321
  )
227
- : await resolveConcepts(ctx, sites);
322
+ : offerConcepts(ctx, sites);
228
323
 
229
324
  const coverDeps = [
230
325
  ctx.trace?.lastIndex("recognise"),
231
326
  ctx.trace?.lastIndex("computeExtensions"),
232
- ctx.trace?.lastIndex("resolveConcepts"),
233
- ctx.trace?.lastIndex("resolveConnectors"),
234
327
  ].filter((x): x is number => x !== undefined);
235
328
 
236
329
  // Convert ComputedSpan[] to ComputedResult[] for the graph search.
@@ -251,17 +344,33 @@ export const coverMechanism: PipelineMechanism = {
251
344
  ...computedResults.map((u) => rItem(u.bytes, "computed")),
252
345
  ], coverDeps.length ? coverDeps : undefined);
253
346
 
254
- const solved = ctx.search.cover(
255
- query.length,
256
- sites,
257
- concepts,
258
- rec.leaves,
259
- splits,
260
- undefined,
261
- connectors,
262
- computedResults,
263
- ctx.trace ? (steps) => traceDerivation(ctx, steps) : undefined,
264
- );
347
+ // COVER, GRANT WHAT IT ASKED, COVER AGAIN — until a cover asks for nothing
348
+ // (see Licence in graph-search.ts). Only the final cover's derivations reach the
349
+ // rationale; a provisional one is superseded, not part of the answer.
350
+ let derivations: DerivationStep[][] = [];
351
+ let solved: ReturnType<typeof ctx.search.cover>;
352
+ for (;;) {
353
+ derivations = [];
354
+ solved = ctx.search.cover(
355
+ query.length,
356
+ sites,
357
+ concepts,
358
+ rec.leaves,
359
+ splits,
360
+ undefined,
361
+ connectors,
362
+ computedResults,
363
+ ctx.trace ? (steps) => derivations.push(steps) : undefined,
364
+ );
365
+ if (concepts.asked.size === 0 && connectors.asked.size === 0) break;
366
+ const grant = async () => {
367
+ await concepts.grant([...concepts.asked]);
368
+ await connectors.grant([...connectors.asked]);
369
+ };
370
+ if (ctx.meter) await ctx.meter.time("cover.grant", grant);
371
+ else await grant();
372
+ }
373
+ for (const steps of derivations) traceDerivation(ctx, steps);
265
374
  const segs = solved && solved.segs;
266
375
  tCover?.done(
267
376
  segs === null
@@ -317,8 +426,19 @@ export const coverMechanism: PipelineMechanism = {
317
426
  // restated span contributes nothing to the composed answer, so it must
318
427
  // not be priced as if it did (PASS-carried bytes are priced already;
319
428
  // the diagnostic label reflects the same distinction).
429
+ //
430
+ // …and a span made of nothing but corpus-global scaffolding names nothing:
431
+ // every window of it is a piece of more than √N stored forms, so the form
432
+ // recognised there — the song `What`, in the trained store — is one of
433
+ // thousands it could be. Voicing that form's fact explains no byte the
434
+ // asker owes: measured, `What country is Jerry Bock a citizen of?` was won
435
+ // by `The performer of What is Melinda Marx.` glued onto the right fact.
436
+ const scaffold = scaffoldSpans(ctx, query);
320
437
  const accounted: Array<[number, number]> = segs
321
- .filter((s) => s.rec && !segRestatesQuery(s, query, query.length, W))
438
+ .filter((s) =>
439
+ s.rec && !segRestatesQuery(s, query, query.length, W) &&
440
+ !scaffold.some(([a, b]) => a <= s.i && s.j <= b)
441
+ )
322
442
  .map((s) => [s.i, s.j]);
323
443
 
324
444
  return [{
@@ -8,8 +8,7 @@
8
8
  // that contains it.
9
9
 
10
10
  import type { MindContext } from "../types.js";
11
- import { read } from "../primitives.js";
12
- import { follow, isSpanShaped, locate, skillExemplar } from "../match.js";
11
+ import { locate } from "../match.js";
13
12
  import { concatBytes, indexOf } from "../../bytes.js";
14
13
  import { decodeText } from "../rationale.js";
15
14
  import type {
@@ -103,7 +103,7 @@ import { bytesEqual } from "../../bytes.js";
103
103
  import { rItem } from "../trace.js";
104
104
  import { formsOpenedBy } from "../traverse.js";
105
105
  import { STEP } from "../graph-search.js";
106
- import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
106
+ import type { PipelineMechanism } from "../pipeline-mechanism.js";
107
107
 
108
108
  /** A trained form the query opens, and the bytes by which it continues. */
109
109
  export interface PrefixCompletion {
@@ -6,7 +6,6 @@
6
6
 
7
7
  import { cosine } from "../../vec.js";
8
8
  import {
9
- conceptThreshold,
10
9
  consensusFloor,
11
10
  dominates,
12
11
  identityBar,
@@ -15,8 +14,14 @@ import {
15
14
  } from "../../geometry.js";
16
15
  import type { MindContext } from "../types.js";
17
16
  import { gistOf, read, resolve } from "../primitives.js";
18
- import { bytesEqual, indexOf } from "../../bytes.js";
19
- import { allWindowsAreScaffolding, corpusN, hubBound } from "../traverse.js";
17
+ import { indexOf } from "../../bytes.js";
18
+ import {
19
+ allWindowsAreScaffolding,
20
+ askedEvidence,
21
+ corpusN,
22
+ guidedFirst,
23
+ hubBound,
24
+ } from "../traverse.js";
20
25
  import {
21
26
  follow,
22
27
  project,
@@ -73,7 +78,6 @@ export async function recallByResonance(
73
78
  ...(complete ? { complete } : {}),
74
79
  };
75
80
  };
76
- const k = pre.k;
77
81
  const queryGist = pre.guide;
78
82
 
79
83
  // 0. Exact self-match — content-addressed, deterministic.
@@ -156,10 +160,18 @@ export async function recallByResonance(
156
160
  g !== null && g.length > 0 &&
157
161
  !lawRestates(query, g, 0, { proper: true })
158
162
  ) {
163
+ // EVIDENCE TRAVELS: when the question NAMED the continuation followed
164
+ // (traverse.ts, the exact tier — `Who is the father of Frederick II?`
165
+ // witnesses the father fact's own question `Frederick II father`), the
166
+ // spans that named it are explained too, not only the argument.
167
+ const hop = guidedFirst(ctx, arg.payload);
168
+ const named = hop === undefined
169
+ ? []
170
+ : askedEvidence(ctx, arg.payload, hop);
159
171
  return ground(
160
172
  g,
161
173
  "argument binding — the query's sole edge-source constituent, continuation followed",
162
- [[arg.start, arg.end]],
174
+ [[arg.start, arg.end], ...named],
163
175
  STEP,
164
176
  );
165
177
  }
@@ -38,7 +38,7 @@ 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
40
  import { dominates } from "../../geometry.js";
41
- import { bytesEqual, indexOf } from "../../bytes.js";
41
+ import { bytesEqual } from "../../bytes.js";
42
42
  import { restates } from "../derivation.js";
43
43
  import { STEP } from "../graph-search.js";
44
44
  import type {
package/src/mind/mind.ts CHANGED
@@ -9,41 +9,20 @@
9
9
  // Architecture: 4 primitives × 2 patterns = all inference.
10
10
  // Implementation split across src/mind/*.ts — this file assembles the Mind class.
11
11
 
12
- import { cosine, makeKeyring, rng, setVecConfig, Vec } from "../vec.js";
13
- import { bindSeat, fold, Sema, Space } from "../sema.js";
12
+ import { makeKeyring, rng, setVecConfig, Vec } from "../vec.js";
13
+ import { Sema, Space } from "../sema.js";
14
14
  import { sampleCorpus, searchCorpus } from "./corpus.js";
15
15
  import type { CorpusPair, CorpusResult } from "./corpus.js";
16
16
  import { Alphabet } from "../alphabet.js";
17
- import {
18
- bytesToTree,
19
- contentFoldIncremental,
20
- Grid,
21
- gridToTree,
22
- hilbertBytes,
23
- reachThreshold,
24
- stackGrids,
25
- } from "../geometry.js";
17
+ import { contentFoldIncremental, Grid, reachThreshold } from "../geometry.js";
26
18
  import { keyEnds } from "./canonical.js";
27
19
  import type { ContentFold } from "../geometry.js";
28
20
  import { BoundedMap, type Store } from "../store.js";
29
21
  import { SQliteStore } from "../store-sqlite.js";
30
22
  import { type MindConfig, resolveConfig } from "../config.js";
31
23
  import { type Canon, canonHash, textCanon, textEdgeTrim } from "../canon.js";
32
- import {
33
- type CandidateSpan,
34
- coverSequence,
35
- lightestDerivation,
36
- } from "../derive/src/index.js";
37
- import { bytesEqual, concat2, concatBytes, indexOf } from "../bytes.js";
38
- import {
39
- type ComputedResult,
40
- type DerivationItem,
41
- type DerivationStep,
42
- GraphSearch,
43
- type Leaf,
44
- type Seg,
45
- type Site,
46
- } from "./graph-search.js";
24
+ import { bytesEqual, concat2 } from "../bytes.js";
25
+ import { GraphSearch, type Leaf, type Site } from "./graph-search.js";
47
26
  import { Alu } from "../alu/src/index.js";
48
27
  import type { ComputedSpan, ExtensionHost } from "../extension.js";
49
28
 
@@ -147,16 +126,12 @@ interface ConversationData {
147
126
 
148
127
  // Mind module imports
149
128
  import type { AttentionRead, MindContext, Recognition } from "./types.js";
150
- import { changedNodes, liftAnswer, spliceAll } from "./types.js";
151
129
  import {
152
130
  canonResolve as canonResolveImpl,
153
- foldTree,
154
131
  gistOf,
155
132
  inputBytes,
156
- latin1Key,
157
133
  perceive as perceiveImpl,
158
134
  perceiveKey,
159
- read,
160
135
  resolve as resolveImpl,
161
136
  } from "./primitives.js";
162
137
  import {
@@ -166,6 +141,7 @@ import {
166
141
  leadsSomewhere,
167
142
  } from "./traverse.js";
168
143
  import { invalidateJunctionCache } from "./junction.js";
144
+ import type { WindowIndex } from "./evidence.js";
169
145
  import { follow } from "./match.js";
170
146
  import { recognise, segment } from "./recognition.js";
171
147
  import { meaningOf } from "./resonance.js";
@@ -358,6 +334,8 @@ export class Mind implements MindContext {
358
334
  * first-edge behaviour) and the reverse projection uses it for
359
335
  * reverse-recall disambiguation via `chooseAmong`. */
360
336
  _edgeGuide: Vec | null = null;
337
+ /** See {@link MindContext._edgeAsked}. */
338
+ _edgeAsked: { bytes: Uint8Array; index: WindowIndex } | null = null;
361
339
  /** Per-response memo of {@link chooseNext} picks — ensures every mechanism
362
340
  * of a single response follows the SAME continuation for each ambiguous
363
341
  * context node. */
@@ -672,6 +650,7 @@ export class Mind implements MindContext {
672
650
  this.canon = null;
673
651
  this.canonMemo = null;
674
652
  this._edgeGuide = null;
653
+ this._edgeAsked = null;
675
654
  this._edgeChoice.clear();
676
655
  }
677
656