@hviana/sema 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +29 -29
- package/TRADEMARKS.md +0 -1
- package/dist/src/config.d.ts +11 -0
- package/dist/src/config.js +2 -0
- package/dist/src/geometry.d.ts +21 -0
- package/dist/src/geometry.js +21 -0
- package/dist/src/meter.d.ts +51 -0
- package/dist/src/meter.js +51 -0
- package/dist/src/mind/attention.d.ts +4 -0
- package/dist/src/mind/attention.js +165 -16
- package/dist/src/mind/canonical.d.ts +16 -0
- package/dist/src/mind/canonical.js +41 -0
- package/dist/src/mind/graph-search.js +33 -14
- package/dist/src/mind/match.d.ts +1 -1
- package/dist/src/mind/match.js +5 -3
- package/dist/src/mind/mechanisms/cast.js +1 -1
- package/dist/src/mind/mechanisms/confluence.js +24 -0
- package/dist/src/mind/mechanisms/recall.js +32 -4
- package/dist/src/mind/mind.d.ts +4 -2
- package/dist/src/mind/mind.js +5 -4
- package/dist/src/mind/pipeline-mechanism.d.ts +7 -0
- package/dist/src/mind/pipeline.js +41 -14
- package/dist/src/mind/primitives.js +9 -1
- package/dist/src/mind/rationale.d.ts +28 -1
- package/dist/src/mind/rationale.js +22 -1
- package/dist/src/mind/reasoning.d.ts +21 -3
- package/dist/src/mind/reasoning.js +73 -21
- package/dist/src/mind/recognition.js +4 -8
- package/dist/src/mind/resonance.js +20 -1
- package/dist/src/mind/trace.js +1 -0
- package/dist/src/mind/traverse.js +6 -2
- package/dist/src/mind/types.d.ts +36 -13
- package/docs/INVARIANTS.md +2 -2
- package/docs/architecture/bounded-reads.md +1 -1
- package/docs/architecture/commonality.md +2 -2
- package/docs/architecture/cost-model.md +2 -2
- package/docs/architecture/determinism.md +7 -7
- package/docs/architecture/match-project.md +2 -3
- package/docs/architecture/mechanism-market.md +10 -10
- package/docs/architecture/meter.md +5 -5
- package/docs/architecture/store.md +3 -3
- package/docs/failures/tempting-but-wrong.md +3 -4
- package/docs/harness/gates.md +2 -2
- package/docs/mechanisms/cast.md +2 -2
- package/docs/mechanisms/cover.md +2 -3
- package/docs/mechanisms/extraction.md +7 -7
- package/docs/mechanisms/recall.md +8 -9
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/alu/README.md +11 -12
- package/src/config.ts +13 -0
- package/src/geometry.ts +21 -0
- package/src/meter.ts +51 -0
- package/src/mind/attention.ts +167 -16
- package/src/mind/canonical.ts +43 -0
- package/src/mind/graph-search.ts +39 -14
- package/src/mind/match.ts +5 -3
- package/src/mind/mechanisms/cast.ts +3 -1
- package/src/mind/mechanisms/confluence.ts +24 -0
- package/src/mind/mechanisms/recall.ts +32 -4
- package/src/mind/mind.ts +6 -4
- package/src/mind/pipeline-mechanism.ts +7 -0
- package/src/mind/pipeline.ts +49 -16
- package/src/mind/primitives.ts +9 -1
- package/src/mind/rationale.ts +35 -1
- package/src/mind/reasoning.ts +92 -15
- package/src/mind/recognition.ts +4 -8
- package/src/mind/resonance.ts +19 -1
- package/src/mind/trace.ts +1 -0
- package/src/mind/traverse.ts +7 -5
- package/src/mind/types.ts +36 -13
- package/test/105-derive-through-reports-its-refusal.test.mjs +24 -0
- package/test/118-the-join-reaches-a-key-off-the-cut.test.mjs +74 -0
- package/test/119-the-work-does-not-grow-with-the-corpus.test.mjs +122 -0
- package/test/120-composition-is-consequence.test.mjs +132 -0
- package/test/121-the-extension-does-not-grow-with-the-corpus.test.mjs +128 -0
- package/test/122-the-climb-search-does-not-grow-with-the-corpus.test.mjs +117 -0
- package/test/123-the-paired-formulas-agree.test.mjs +90 -0
- package/test/125-the-post-grounding-branch-publishes-its-operand.test.mjs +51 -0
- package/test/126-the-pipeline-does-not-name-mechanisms.test.mjs +42 -0
- package/test/128-the-leads-somewhere-pair-agrees.test.mjs +83 -0
- package/test/129-the-trace-payload-shape.test.mjs +164 -0
- package/test/32-confluence.test.mjs +68 -0
- package/test/38-reason-restate-guard.test.mjs +8 -2
- package/test/43-cast-analog-seat.test.mjs +10 -0
- package/test/55-cost-meter.test.mjs +859 -0
|
@@ -6,8 +6,9 @@ import { rItem, rNode } from "./trace.js";
|
|
|
6
6
|
import { bytesEqual, indexOf } from "../bytes.js";
|
|
7
7
|
import { resolve } from "./primitives.js";
|
|
8
8
|
import { hubBound } from "./traverse.js";
|
|
9
|
-
import { follow, haloSiblings, project } from "./match.js";
|
|
9
|
+
import { containsSpan, follow, haloSiblings, project } from "./match.js";
|
|
10
10
|
import { joinWithBridge, pivotInto } from "./resonance.js";
|
|
11
|
+
import { unaccountedBytes } from "./rationale.js";
|
|
11
12
|
/** Whether `bytes` is a proper byte-subspan of `query` — already present in
|
|
12
13
|
* the question, so voicing it back only restates part of what was asked,
|
|
13
14
|
* never answers it. The exact guard recallByResonance already applies to
|
|
@@ -21,15 +22,6 @@ import { joinWithBridge, pivotInto } from "./resonance.js";
|
|
|
21
22
|
export function restatesQuery(query, bytes) {
|
|
22
23
|
return bytes.length < query.length && indexOf(query, bytes, 0) >= 0;
|
|
23
24
|
}
|
|
24
|
-
/** Extend a grounded answer forward across facts (multi-hop reasoning).
|
|
25
|
-
* Pivots on the longest unconsumed learnt context each answer contains,
|
|
26
|
-
* then follows the pivot's continuation to the next fact. Repeats up
|
|
27
|
-
* to `cfg.recallQueryK` hops. `preConsumed` carries node ids already
|
|
28
|
-
* spoken for by the grounding stage (cover/extract/CAST). `voiced` carries
|
|
29
|
-
* the BYTES of the anchors a mechanism declared it voiced (its `used` set),
|
|
30
|
-
* when it declared one — see the pivot's own containment rule. `pre` is the
|
|
31
|
-
* response's shared pre-computation — the post-grounding stages read the
|
|
32
|
-
* same container the mechanisms did. */
|
|
33
25
|
export async function reason(ctx, query, answer, preConsumed, pre, voiced = [],
|
|
34
26
|
/** The query material the GROUNDING left uncovered — the cost ladder's own
|
|
35
27
|
* `unaccounted` spans. Only the reasoner's OWN extensions are judged
|
|
@@ -41,8 +33,9 @@ uncovered = []) {
|
|
|
41
33
|
// back. The grounded answer alone is the honest read-out. Deliberately a
|
|
42
34
|
// broad structural gate; pinned by test/31-audit.
|
|
43
35
|
const qId = pre.queryResolved;
|
|
44
|
-
if (qId !== null && ctx.store.prevCount(qId) > 0)
|
|
45
|
-
return answer;
|
|
36
|
+
if (qId !== null && ctx.store.prevCount(qId) > 0) {
|
|
37
|
+
return { bytes: answer, carried: [], steps: 0 };
|
|
38
|
+
}
|
|
46
39
|
// Consume a node and its neighbours for pivot-cycle prevention — CAPPED at
|
|
47
40
|
// the hub bound, via the store's LIMITed edge reads: a common continuation's
|
|
48
41
|
// reverse fan-in (and a hub context's forward fan-out) is corpus-sized, and
|
|
@@ -99,7 +92,7 @@ uncovered = []) {
|
|
|
99
92
|
? null
|
|
100
93
|
: ctx.store.prevFirst(groundedId, bound);
|
|
101
94
|
if (qId !== null && groundedPrev !== null && groundedPrev.includes(qId)) {
|
|
102
|
-
return answer;
|
|
95
|
+
return { bytes: answer, carried: [], steps: 0 };
|
|
103
96
|
}
|
|
104
97
|
const consumed = new Set();
|
|
105
98
|
/** `prev` lets a caller hand in an already-read reverse-edge list — hop 0
|
|
@@ -147,7 +140,27 @@ uncovered = []) {
|
|
|
147
140
|
const qv = pre.guide; // the response-wide guide IS the query's gist
|
|
148
141
|
let t;
|
|
149
142
|
const startedFrom = answer;
|
|
150
|
-
|
|
143
|
+
// INSTRUMENTATION ONLY — the two facts the extension's own decision already
|
|
144
|
+
// used and threw away: the spans of uncovered material each step was
|
|
145
|
+
// JUSTIFIED by (the gate below computes which span carries it and kept only a
|
|
146
|
+
// boolean), and how many steps were taken. Nothing here decides anything:
|
|
147
|
+
// both are read after the loop, to bump counters and to let the caller compare
|
|
148
|
+
// the extension's cost against what it explains, in the ladder's own currency.
|
|
149
|
+
const carried = [];
|
|
150
|
+
let steps = 0;
|
|
151
|
+
// NO ALLOWANCE: THE CHAIN ENDS WHEN IT STOPS. Every exit below is the law —
|
|
152
|
+
// no pivot, no forward step, no question material carried — and the walk is
|
|
153
|
+
// bounded by the material and the graph rather than by a count: each taken
|
|
154
|
+
// step must carry a W-window of the uncovered material (finite), and
|
|
155
|
+
// `consumed` refuses to revisit a node. `recallQueryK` no longer bounds the
|
|
156
|
+
// reasoner here; it keeps its other roles (the bridge's candidate reads, the
|
|
157
|
+
// pivot's probe budget, the resonance limits).
|
|
158
|
+
//
|
|
159
|
+
// Measured before removing it: test/89 — the corpus-cost guard, the heaviest
|
|
160
|
+
// case in the suite — is green and no slower without the allowance (27 s
|
|
161
|
+
// against 30 s); and raising it from 12 to 200 changed neither the answer nor
|
|
162
|
+
// `pivotSteps` on the chain fixtures.
|
|
163
|
+
for (let hop = 0;; hop++) {
|
|
151
164
|
// Hop 0's `cur` IS `answer`, so the guard above already resolved it and
|
|
152
165
|
// read its reverse edges — reuse both rather than repeat them.
|
|
153
166
|
const curId = hop === 0 ? groundedId : resolve(ctx, cur);
|
|
@@ -170,6 +183,7 @@ uncovered = []) {
|
|
|
170
183
|
]);
|
|
171
184
|
ctx.trace?.step("absorbForward", [rItem(cur, "answer", curId)], [rItem(fwd, "answer", resolve(ctx, fwd) ?? undefined)], "the answer is itself a learnt fact — follow its continuation to the fixpoint");
|
|
172
185
|
cur = fwd;
|
|
186
|
+
steps++;
|
|
173
187
|
continue;
|
|
174
188
|
}
|
|
175
189
|
}
|
|
@@ -205,14 +219,19 @@ uncovered = []) {
|
|
|
205
219
|
if (!producerOwnsShape && uncovered.length > 0) {
|
|
206
220
|
const W = ctx.space.maxGroup;
|
|
207
221
|
let progress = false;
|
|
222
|
+
let justified;
|
|
208
223
|
for (const [a, b] of uncovered) {
|
|
209
224
|
for (let i = a; i + W <= b && !progress; i++) {
|
|
210
|
-
if (indexOf(fc, query.subarray(i, i + W), 0) >= 0)
|
|
225
|
+
if (indexOf(fc, query.subarray(i, i + W), 0) >= 0) {
|
|
211
226
|
progress = true;
|
|
227
|
+
justified = [a, b];
|
|
228
|
+
}
|
|
212
229
|
}
|
|
213
230
|
if (progress)
|
|
214
231
|
break;
|
|
215
232
|
}
|
|
233
|
+
if (progress && justified !== undefined)
|
|
234
|
+
carried.push(justified);
|
|
216
235
|
if (!progress) {
|
|
217
236
|
// THE BRAKE, MADE VISIBLE. The reasoner declines a step that carries
|
|
218
237
|
// none of the material the grounding left uncovered — the drift the
|
|
@@ -223,7 +242,25 @@ uncovered = []) {
|
|
|
223
242
|
// the check disabled, test/110 and test/116 fail — so this brake is the
|
|
224
243
|
// only thing keeping the extension honest until the pivot reports its
|
|
225
244
|
// own accounted spans and the ladder can judge it instead.
|
|
226
|
-
|
|
245
|
+
//
|
|
246
|
+
// THE PROMISE IS NOW KEPT, AND THE BRAKE TURNS OUT TO BE THE LADDER'S
|
|
247
|
+
// OWN CONSEQUENCE. The extension reports what it carried (`carried`,
|
|
248
|
+
// the span each step was justified by) and what it cost (`steps`), both
|
|
249
|
+
// counted in the meter (`reasonCarriedBytes`, `reasonSteps`), so the
|
|
250
|
+
// ladder CAN judge it: it accepts while
|
|
251
|
+
//
|
|
252
|
+
// steps · STEP < PASS · carried
|
|
253
|
+
//
|
|
254
|
+
// and this brake accepts whenever the step carries a `W`-window, i.e.
|
|
255
|
+
// whenever `carried ≥ W ≥ 1`. With `PASS/STEP = 1000` the two therefore
|
|
256
|
+
// agree on every extension with `steps ≤ 1000 · carried` — and every
|
|
257
|
+
// extension this repository produces takes 0 or 1 steps (measured on
|
|
258
|
+
// chains of 3, 8, 20 and 40 links). Above that bound the ladder would
|
|
259
|
+
// refuse what this brake accepts, which is the corner named in the
|
|
260
|
+
// closure report's limits: a chain of thousands of links explaining a
|
|
261
|
+
// handful of bytes. No guard is added for it — a limit without a
|
|
262
|
+
// derivation is exactly what the brake must not become.
|
|
263
|
+
const left = unaccountedBytes(uncovered);
|
|
227
264
|
ctx.trace?.step("pivotRefused", [rItem(cur, "answer"), rItem(query, "query")], uncovered.map(([a, b]) => rItem(query.subarray(a, b), "uncovered")), `the step carries none of the question material the grounding left ` +
|
|
228
265
|
`uncovered (${left} byte(s) in ${uncovered.length} span(s)) — refused`);
|
|
229
266
|
break;
|
|
@@ -234,9 +271,23 @@ uncovered = []) {
|
|
|
234
271
|
t ??= ctx.trace?.enter("reason", [rItem(startedFrom, "grounded")]);
|
|
235
272
|
ctx.trace?.step("pivotStep", [rItem(cur, "answer"), rNode(ctx, pivot, "pivot")], [rItem(fc, "answer", resolve(ctx, fc) ?? undefined)], "pivot on the shared span this answer contains, then step forward across that fact");
|
|
236
273
|
cur = fc;
|
|
274
|
+
steps++;
|
|
275
|
+
}
|
|
276
|
+
// INSTRUMENTATION ONLY — the extension's two facts, untraced (meter.ts
|
|
277
|
+
// contract 1: a counter never reaches a decision). They are what a caller
|
|
278
|
+
// needs to PRICE the extension instead of taking it unconditionally: the work
|
|
279
|
+
// it did (`steps · STEP`) and the uncovered material it carried.
|
|
280
|
+
if (ctx.meter) {
|
|
281
|
+
ctx.meter.reasonSteps += steps;
|
|
282
|
+
ctx.meter.reasonCarriedBytes += unaccountedBytes(carried);
|
|
237
283
|
}
|
|
238
|
-
t?.done([rItem(cur, "answer", resolve(ctx, cur) ?? undefined)],
|
|
239
|
-
|
|
284
|
+
t?.done([rItem(cur, "answer", resolve(ctx, cur) ?? undefined)],
|
|
285
|
+
// A FIXPOINT: no further step was possible. This note used to also cover an
|
|
286
|
+
// exhausted hop allowance — a different fact, and the reason F1 added a
|
|
287
|
+
// counter for it. The allowance is gone, so the only way out of the loop is
|
|
288
|
+
// a refusal, and the note is true again by construction.
|
|
289
|
+
"the multi-hop chain's fixpoint");
|
|
290
|
+
return { bytes: cur, carried, steps };
|
|
240
291
|
}
|
|
241
292
|
/** Fuse independent points of attention into one answer (multi-topic).
|
|
242
293
|
* When the consensus climb finds more than one dominant point, each
|
|
@@ -405,8 +456,9 @@ primarySpans = []) {
|
|
|
405
456
|
out = await joinWithBridge(ctx, out, pieces[i].bytes);
|
|
406
457
|
}
|
|
407
458
|
t?.done([rItem(out, "answer", resolve(ctx, out) ?? undefined)], `fused ${pieces.length} independent points of attention into one answer`);
|
|
459
|
+
// THE FACT IS THE FUSED ANSWER, not the call: every early return above hands
|
|
460
|
+
// back `primary` untouched. Untraced on purpose (meter.ts contract 1).
|
|
461
|
+
if (ctx.meter)
|
|
462
|
+
ctx.meter.fuseRuns++;
|
|
408
463
|
return out;
|
|
409
464
|
}
|
|
410
|
-
// (resonance.js is already a static dependency above — `bridge` — so the old
|
|
411
|
-
// dynamic import of pivotInto guarded against a cycle that does not exist.)
|
|
412
|
-
import { containsSpan } from "./match.js";
|
|
@@ -519,8 +519,11 @@ function recogniseImpl(ctx, bytes) {
|
|
|
519
519
|
if (end - start < W)
|
|
520
520
|
return false;
|
|
521
521
|
if (flatProbe(start, end) === null) {
|
|
522
|
-
if (!canonBudget)
|
|
522
|
+
if (!canonBudget) {
|
|
523
|
+
if (ctx.meter)
|
|
524
|
+
ctx.meter.canonProbesDenied++;
|
|
523
525
|
return false;
|
|
526
|
+
}
|
|
524
527
|
if (!canonAdmits(start, end))
|
|
525
528
|
return false;
|
|
526
529
|
}
|
|
@@ -543,13 +546,6 @@ function recogniseImpl(ctx, bytes) {
|
|
|
543
546
|
// endpoints in order and running out partway along the query. A form
|
|
544
547
|
// longer than that is out of this tier's reach — but so is a form the
|
|
545
548
|
// chain cannot span, and that is exactly the trade the budget prices.
|
|
546
|
-
// The factor is chainReach(W), the same W² scale the chain already
|
|
547
|
-
// trusts; no new constant.
|
|
548
|
-
// The factor is chainReach(W) — the same W² scale the chain itself
|
|
549
|
-
// trusts — so the cap is derived from the fold's geometry, never tuned.
|
|
550
|
-
// (It was briefly an environment variable while the cost was being
|
|
551
|
-
// measured; an env-read here would make inference non-reproducible,
|
|
552
|
-
// which the determinism contract forbids outright.)
|
|
553
549
|
// The factor is chainReach(W) — the same W² scale the chain itself
|
|
554
550
|
// trusts — so the cap is derived from the fold's geometry, never tuned.
|
|
555
551
|
// (It was briefly an environment variable while the cost was being
|
|
@@ -249,7 +249,14 @@ export async function joinWithBridge(ctx, left, right) {
|
|
|
249
249
|
* overlap, so C3's genuine further hop — "Mona Lisa", a term inside the seat
|
|
250
250
|
* sentence but part of NEITHER analog — still fires. */
|
|
251
251
|
export async function pivotInto(ctx, answer, consumed, voiced = []) {
|
|
252
|
-
|
|
252
|
+
// The pivot's OWN shortlist capacity — not `recallQueryK`: they are different
|
|
253
|
+
// quantities (a mechanical sweep's probe budget vs the bridge's candidate-read
|
|
254
|
+
// allowance), and one number serving both means tightening either silently
|
|
255
|
+
// starves the other. The reason is the duplication, NOT a measured strangle:
|
|
256
|
+
// an earlier version of this comment claimed "at recallQueryK 1 the pivot finds
|
|
257
|
+
// no pivot", and that was probed and is FALSE on test/23's fixture — the
|
|
258
|
+
// strangle is fixture-specific, so it is not the evidence for this split.
|
|
259
|
+
const k = ctx.cfg.pivotProbeK;
|
|
253
260
|
// ONE perception of the answer, shared by the probe budget and the walk —
|
|
254
261
|
// this used to fold the same bytes twice, back to back, on every hop.
|
|
255
262
|
const tree = perceive(ctx, answer);
|
|
@@ -288,6 +295,18 @@ export async function pivotInto(ctx, answer, consumed, voiced = []) {
|
|
|
288
295
|
for (const c of n.kids)
|
|
289
296
|
queue.push(c); // breadth-first: larger regions first
|
|
290
297
|
}
|
|
298
|
+
// The sweep's two FACTS, untraced (meter.ts contract 1: a counter never
|
|
299
|
+
// reaches a decision). `probes` is the work done; the shortfall is the
|
|
300
|
+
// capacity the cap withheld — the branches the breadth-first order never got
|
|
301
|
+
// to. Whether that withheld anything that mattered is NOT said here: the
|
|
302
|
+
// order spends the largest regions first, and recognition below still
|
|
303
|
+
// contributes every exact containment candidate regardless of the budget.
|
|
304
|
+
if (ctx.meter) {
|
|
305
|
+
ctx.meter.pivotProbes += probes;
|
|
306
|
+
const unprobed = branchCount - probeCap;
|
|
307
|
+
if (unprobed > 0)
|
|
308
|
+
ctx.meter.pivotBranchesUnprobed += unprobed;
|
|
309
|
+
}
|
|
291
310
|
// THE FULL recognition, memo-shared with every other reader of these bytes.
|
|
292
311
|
// A "skip the edge trims here" variant was refuted (see recognise's own
|
|
293
312
|
// note): those trims are what find a WHOLE trained form embedded at an
|
package/dist/src/mind/trace.js
CHANGED
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
import { cosine } from "../vec.js";
|
|
9
9
|
import { gistOf, read } from "./primitives.js";
|
|
10
10
|
import { canonicalWindows, leafIdPrefix, leafIdRun } from "./canonical.js";
|
|
11
|
+
// Imported at the TOP, where every other import is. They used to sit 800 lines
|
|
12
|
+
// down under a note claiming the position mattered ("before trace module is
|
|
13
|
+
// loaded") — it does not: an ES module's static imports are HOISTED, so the
|
|
14
|
+
// file's line order never decides load order. The note described an intention
|
|
15
|
+
// the runtime does not honour; the imports move and the claim goes.
|
|
16
|
+
import { decodeText } from "./rationale.js";
|
|
11
17
|
//
|
|
12
18
|
// Budgeted on the same terms as the reach memo below (caches.md): these three
|
|
13
19
|
// maps are cleared on every write, but a long read-only session over a large
|
|
@@ -704,8 +710,6 @@ export function chooseAmong(ctx, candidates, guide) {
|
|
|
704
710
|
? { id: found.item, score: found.score }
|
|
705
711
|
: { id: candidates[0], score: -Infinity };
|
|
706
712
|
}
|
|
707
|
-
// ── Trace shim (used by chooseNext before trace module is loaded) ────────
|
|
708
|
-
import { decodeText } from "./rationale.js";
|
|
709
713
|
function rItemShort(ctx, id, role, score) {
|
|
710
714
|
return {
|
|
711
715
|
text: decodeText(read(ctx, id)),
|
package/dist/src/mind/types.d.ts
CHANGED
|
@@ -35,15 +35,21 @@ export interface GraphSearchHost {
|
|
|
35
35
|
starts: ReadonlySet<number>;
|
|
36
36
|
};
|
|
37
37
|
chooseNext?(node: number): number | undefined;
|
|
38
|
-
/** The
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
|
|
38
|
+
/** The lengths `p` for which `prefix ‖ tail[0..p]` IS A STORED NODE, ascending
|
|
39
|
+
* — the join's candidate set, in the tail's own coordinates. Optional: a host
|
|
40
|
+
* that cannot answer makes the join fall back to every prefix, which is exact
|
|
41
|
+
* and complete but pays a `resolve` per offset.
|
|
42
|
+
*
|
|
43
|
+
* WHY NOT THE FOLD'S CUTS. A key names a relation exactly when the
|
|
44
|
+
* concatenation is a node, and a node's end is the end of ITS OWN stream —
|
|
45
|
+
* where the fold never emits a cut (geometry's `emit` guards `at >= n`). So a
|
|
46
|
+
* key can end strictly inside the tail with no boundary anywhere near it:
|
|
47
|
+
* measured, "stockholm mayor" exists, leads on to the mayor fact, and its
|
|
48
|
+
* boundary 6 is in neither the tail's cuts ([4,7]) nor the concatenation's.
|
|
49
|
+
* The fold's boundaries are a SUBSET of the real ends, not a proxy for them,
|
|
50
|
+
* and using them skipped the shortest names first — which is a semantic law,
|
|
51
|
+
* not an optimisation (test/106, test/108 pin it). */
|
|
52
|
+
contentKeyEnds?(prefix: Uint8Array, tail: Uint8Array): readonly number[];
|
|
47
53
|
/** The admission predicate — `traverse.ts`'s `leadsSomewhere`, its ONE
|
|
48
54
|
* definition: does this node bear an edge or a halo? Optional, so a bare
|
|
49
55
|
* host (a raw Store and nothing else) still works; when present, the search
|
|
@@ -104,11 +110,28 @@ export interface Attention {
|
|
|
104
110
|
* strength and its place.
|
|
105
111
|
* `vote` is a sum over every region that agreed, so it grows with how many
|
|
106
112
|
* places corroborated; `peak` is what the strongest one of them said on its
|
|
107
|
-
* own.
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
113
|
+
* own. THIS USED TO PRESCRIBE THE WRONG OPERAND. It read: "a consumer
|
|
114
|
+
* holding this point to consensusFloor(N) — a bar that prices ONE region's
|
|
115
|
+
* maximally-discriminative evidence — must read `peak`, not `vote`." The
|
|
116
|
+
* engine reads the POOLED vote, and thresholds.md §2 derives the floor for
|
|
117
|
+
* exactly that ("Pooled-vote significance floor": one maximally-specific
|
|
118
|
+
* region contributes at most ln N, and ln(N)+1/2 demands corroboration
|
|
119
|
+
* BEYOND one region). MEASURED across 27 anchors on 6 queries: all 11
|
|
120
|
+
* admissions cleared the floor by the sum and NONE by `peak` alone — a gate
|
|
121
|
+
* reading `peak` would refuse every root the engine elects. `peak` remains
|
|
122
|
+
* what it is: the strongest SINGLE region's contribution. */
|
|
111
123
|
peak: number;
|
|
124
|
+
/** The IDF-WEIGHTED sum behind this point — the quantity `consensusFloor` is
|
|
125
|
+
* derived for, and therefore the one the floor gates must read. It is
|
|
126
|
+
* MODE-INDEPENDENT by construction (its per-region weight is
|
|
127
|
+
* `mutual · idf / roots`, never the mode-dependent `wf`), so gating on it
|
|
128
|
+
* makes an anchor's admission the same in `inverse`, `direct` and `combined`.
|
|
129
|
+
* In `inverse` — the only mode the engine runs — it equals `vote` exactly
|
|
130
|
+
* (measured, test/55 test 17), so nothing about today's verdicts changes.
|
|
131
|
+
* MEASURED before this field existed: gating on `vote` DID flip a verdict,
|
|
132
|
+
* anchor 87 of test/55's query (inverse 2.682 admitted, direct 1.468
|
|
133
|
+
* refused, floor 2.292). */
|
|
134
|
+
idfVote: number;
|
|
112
135
|
/** SCALE-INVARIANT confidence: the fraction of the query's OWN regions
|
|
113
136
|
* whose evidence this point accounts for (Σ RegionVote.absorbed among
|
|
114
137
|
* its contributors, over the query's total region count) — read PER-
|
package/docs/INVARIANTS.md
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
| 5 | Bounded reads | `src/store.ts:AbstractStore:nextFirst,parentsFirst,containersSlice,hasNext,bytesPrefix` `src/mind/traverse.ts:hubBound,hubCap` | `test/90` `test/14` | `bounded-reads.md` |
|
|
12
12
|
| 6 | Fold contract | `src/geometry.ts:contentLevels` `src/mind/canonical.ts:canonicalWindows,chainReach` `src/canon.ts:canonicalizer` | `test/59` `test/63` | `fold-contract.md` |
|
|
13
13
|
| 7 | Mechanism market | `src/mind/pipeline-mechanism.ts:PipelineMechanism,Precomputed` `src/mind/pipeline.ts:think,worthRunning` | `test/01` `test/04` | `mechanism-market.md` |
|
|
14
|
-
| 8 | Two commonality measures | `src/mind/traverse.ts:reachOf,dominates,corpusN` (global) `
|
|
14
|
+
| 8 | Two commonality measures | `src/mind/traverse.ts:reachOf,dominates,corpusN` (global) `cast.ts:depth[],MIN_WEAVE` (weave-local) | `test/17` `test/34` | `commonality.md` |
|
|
15
15
|
| 9 | Memoization idempotence | `src/mind/pipeline-mechanism.ts:Precomputed` `src/mind/mind.ts:beginResponse,endResponse,_resolvedSubtrees` | `test/42` | `memoization.md` |
|
|
16
16
|
| 10 | Caches as budgets | `src/store.ts:BoundedMap` `src/config.ts:StoreConfig:bytesCacheMax,recCacheBytes,haloCacheBytes` | `test/96` `test/91` | `caches.md` |
|
|
17
17
|
| 11 | Honest degradation | `src/mind/pipeline.ts:weight=moves+PASS*unaccounted` `src/store.ts:BoundedMap:miss→re-derive` | `test/28` `test/84` | `store.md`+`caches.md` |
|
|
18
18
|
| 12 | Meter contracts | `src/meter.ts:Meter,PhaseCost,time` `src/mind/pipeline-mechanism.ts:Precomputed.shared` | `test/55` | `meter.md` |
|
|
19
|
-
| 13 | Saturation | `
|
|
19
|
+
| 13 | Saturation | `traverse.ts:edgeAncestors,types.ts:SaturationReason` `src/mind/junction.ts:junctionContainersFrom` `src/mind/resonance.ts:pivotInto` | `test/27` `test/16` | `saturation.md` |
|
|
@@ -18,7 +18,7 @@ boundFor(n) = ceil(sqrt(max(2, n))) // ctx-free reading
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Defined once in `mind/traverse.ts` (`corpusN`, `hubBound`, `hubCap`,
|
|
21
|
-
`boundFor`). Every consumer imports them; never
|
|
21
|
+
`boundFor`). Every consumer imports them; never re-derive them inline.
|
|
22
22
|
|
|
23
23
|
## Enforcement at the store level
|
|
24
24
|
|
|
@@ -19,8 +19,8 @@ scaffolding. Powers the consensus climb, edge following, and vote pooling.
|
|
|
19
19
|
|
|
20
20
|
## Weave-local — `depth[]` + `MIN_WEAVE` + `dominates`
|
|
21
21
|
|
|
22
|
-
_Defined in `src/mind/
|
|
23
|
-
`
|
|
22
|
+
_Defined and gated in `src/mind/mechanisms/cast.ts` (`depth[]` from the shared
|
|
23
|
+
weave, `MIN_WEAVE`); used by CAST._
|
|
24
24
|
|
|
25
25
|
For an alignment weave, `depth[i]` counts how many aligned structures cover byte
|
|
26
26
|
`i` of the query. `MIN_WEAVE = 2` requires agreement beyond a pair (pair columns
|
|
@@ -59,8 +59,8 @@ exceeds the true remaining cost.
|
|
|
59
59
|
## Policy is not cost
|
|
60
60
|
|
|
61
61
|
"Computation always wins" is **not** priced into the ladder (a computed result
|
|
62
|
-
costs `STEP`, same as a learned edge). It is enforced by masking: `
|
|
63
|
-
removes recognised sites overlapped by a `ComputedResult
|
|
62
|
+
costs `STEP`, same as a learned edge). It is enforced by masking: `cover.ts`
|
|
63
|
+
removes recognised sites overlapped by a `ComputedResult`, so the computation is
|
|
64
64
|
the sole completion there. Keep policy in callers; keep the engine neutral.
|
|
65
65
|
|
|
66
66
|
## Pins
|
|
@@ -20,7 +20,7 @@ flaky, the contract was broken, not the test.
|
|
|
20
20
|
entropy root. Subsystems derive deterministically:
|
|
21
21
|
|
|
22
22
|
- **Alphabet** — `Alphabet` (`src/alphabet.ts`) via `rng` (`src/vec.ts:rng`)
|
|
23
|
-
seeded as `seed ^ seedMask`; builds 16→64→256 vectors
|
|
23
|
+
seeded as `seed ^ seedMask`; builds 16→64→256 vectors.
|
|
24
24
|
- **Keyring / Space** — `Space.seats` (`src/sema.ts:Space`) via `makeKeyring`
|
|
25
25
|
(`src/vec.ts:makeKeyring`) and `rng` seeded from `seed` in `Mind`
|
|
26
26
|
(`src/mind/mind.ts`); `fold`/`twoEndedSeat`/`companySignature` are pure over
|
|
@@ -34,8 +34,8 @@ derived from `D`/`W`/`N`, not sampled.
|
|
|
34
34
|
|
|
35
35
|
## Tie-breaks are corpus-determined
|
|
36
36
|
|
|
37
|
-
Every choice
|
|
38
|
-
|
|
37
|
+
Every choice bottoms out in a fixed ordering — insertion order or lowest node id
|
|
38
|
+
— not interchangeable (`test/34`). The fallback is **first-inserted**:
|
|
39
39
|
|
|
40
40
|
- `guidedFirst` (`src/mind/traverse.ts:guidedFirst`) — guided pick via
|
|
41
41
|
`chooseNext` else first-inserted edge (`nextFirst` LIMIT 1).
|
|
@@ -46,7 +46,7 @@ lowest node id. The universal no-evidence fallback is **first-inserted**:
|
|
|
46
46
|
- `companySignature` (`src/sema.ts:companySignature`) — `rng(id ^ 0x9e3779b9)`,
|
|
47
47
|
i.e. seeded by node id, not observation order.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Never use last-inserted.
|
|
50
50
|
|
|
51
51
|
## Memoization and trace must not break identity
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ Per-response memos (`Precomputed`, `perceiveMemo`, `recogniseMemo`, `climbMemo`,
|
|
|
56
56
|
`src/mind/primitives.ts`) are sound because asking never writes. Only
|
|
57
57
|
`guidedNext`/`sharedReachMemo` are trace-bypassed;
|
|
58
58
|
`perceiveMemo`/`recogniseMemo`/`climbMemo` are always consulted — `foldTree`'s
|
|
59
|
-
subtree fast path skips `visit` (and
|
|
59
|
+
subtree fast path skips `visit` (and site emission) for cached subtrees, so
|
|
60
60
|
bypassing makes `recognise` non-idempotent.
|
|
61
61
|
|
|
62
62
|
## Follow it
|
|
@@ -69,5 +69,5 @@ call `Math.random`/`Date.now` on a behavioural path.
|
|
|
69
69
|
|
|
70
70
|
- `test/42` pins recognition idempotence under trace — traced and untraced
|
|
71
71
|
`recognise` must return the same cached object and site count.
|
|
72
|
-
- Determinism suites — `test/03`, `test/04`, `test/08`, `test/20`
|
|
73
|
-
|
|
72
|
+
- Determinism suites — `test/03`, `test/04`, `test/08`, `test/20` — assert same
|
|
73
|
+
seed + same training ⇒ byte-identical answers and stores.
|
|
@@ -16,7 +16,7 @@ functions over bytes and the store — no mechanism owns a private copy.
|
|
|
16
16
|
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
17
17
|
| **Match** (locate structure) | `locate` (exact → halo → gist ladder), `alignRuns` (literal W-gram weave), `alignGraded` (literal + halo gaps), `alignAround` / `frameSlots` (seeded frame with contracted gaps), `bestHaloMate` (in-list halo), `analogyStrength` / `sharedFrameStrength` (distributional + structural analogy) | Finds where a query sits in a learnt form. |
|
|
18
18
|
| **Project** (direction) | `follow` (forward to fixpoint, first hop may `conceptHop`), `reverseContext` (reverse to context), `project` (forward else reverse), `conceptHop` (halo sibling with edge) | Moves along the store from the match — forward toward answers, reverse toward contexts. |
|
|
19
|
-
| **Gate** (structural licence) | `isSpanShaped` (sparse subsequence —
|
|
19
|
+
| **Gate** (structural licence) | `isSpanShaped` (OPEN reading — sparse subsequence), `containsSpan` (STRICT reading — contiguous run or resolved node), `skillExemplar` (anchor → context + answer), `carriesFillers` (substitution carriage — strict voicing licence) | Two readings; not interchangeable. |
|
|
20
20
|
|
|
21
21
|
Mechanisms declare only `(matcher, direction, gate)`. Thresholds behind gates
|
|
22
22
|
live in `src/geometry.ts` — the match layer never invents a cutoff.
|
|
@@ -52,8 +52,7 @@ The shared layer never refuses on a consumer's behalf. Reference owns its four
|
|
|
52
52
|
gates: frame dominates the query, each slot reaches `W` on both sides, no
|
|
53
53
|
insertion/deletion, fillers pairwise distinct — plus `carriesFillers` on the
|
|
54
54
|
chosen pair. CAST, recall, and cover each apply their own gate over the same
|
|
55
|
-
shared inventory. Moving a
|
|
56
|
-
responsible for the refusal.
|
|
55
|
+
shared inventory. Moving a gate into `match.ts` would hide who owns the refusal.
|
|
57
56
|
|
|
58
57
|
## Pins
|
|
59
58
|
|
|
@@ -19,6 +19,7 @@ interface MechanismResult {
|
|
|
19
19
|
unexplained: string;
|
|
20
20
|
scaffolding?: number;
|
|
21
21
|
complete?: boolean;
|
|
22
|
+
used?: ReadonlySet<number>;
|
|
22
23
|
}
|
|
23
24
|
```
|
|
24
25
|
|
|
@@ -30,7 +31,7 @@ interface MechanismResult {
|
|
|
30
31
|
|
|
31
32
|
## Decider
|
|
32
33
|
|
|
33
|
-
`think`
|
|
34
|
+
`think` iterates `defaultMechanisms` in list order:
|
|
34
35
|
|
|
35
36
|
```
|
|
36
37
|
defaultMechanisms = [cover, cast, confluence, extraction, reference, recall,
|
|
@@ -39,8 +40,7 @@ defaultMechanisms = [cover, cast, confluence, extraction, reference, recall,
|
|
|
39
40
|
|
|
40
41
|
Weight is one currency: `weight = moves + PASS · unaccountedBytes` where
|
|
41
42
|
`unaccountedBytes = unexplainedSpans(query.length, accounted)`. Comparison is at
|
|
42
|
-
`STEP` grade
|
|
43
|
-
`scaffolding` bytes, then list order.
|
|
43
|
+
`STEP` grade ; equal grade prefers fewer `scaffolding` bytes, then list order.
|
|
44
44
|
|
|
45
45
|
## Four constraints
|
|
46
46
|
|
|
@@ -48,16 +48,16 @@ Weight is one currency: `weight = moves + PASS · unaccountedBytes` where
|
|
|
48
48
|
never touches another; no mechanism asks what already decided.
|
|
49
49
|
2. **Declared competence** — binary structural gates inside `floor`/`run` (query
|
|
50
50
|
length, anchor shape, weave existence). Never a learned score; rationale
|
|
51
|
-
states
|
|
51
|
+
states why a mechanism abstained.
|
|
52
52
|
3. **Visible budget** — every corpus-scale loop is capped at a named constant:
|
|
53
53
|
`√N` via `hubBound`/`hubCap` and `k = 2·recallQueryK` (`Precomputed.k`).
|
|
54
|
-
Enforced at the store
|
|
54
|
+
Enforced at the store.
|
|
55
55
|
4. **Evidence travels** — every candidate carries `accounted` (query spans
|
|
56
56
|
explained), `moves` (priced on `MICRO/STEP/CONCEPT/PASS`), `unexplained`
|
|
57
57
|
(diagnostic label); optionally `scaffolding` (answer bytes from unrecognised
|
|
58
58
|
spans — equal-grade tie-break) and `complete` (trained-form continuation
|
|
59
59
|
reached via identity; post-grounding must not extend). The decider honours
|
|
60
|
-
|
|
60
|
+
all three without knowing who set them.
|
|
61
61
|
|
|
62
62
|
## Two disciplines
|
|
63
63
|
|
|
@@ -70,8 +70,8 @@ Weight is one currency: `weight = moves + PASS · unaccountedBytes` where
|
|
|
70
70
|
- **Investment discipline.** `worthRunning` is passed _into_ `floor`. A floor
|
|
71
71
|
that would first-touch an expensive shared analysis (`pre.attention()` climb,
|
|
72
72
|
`pre.weave()`, `pre.resonance()`) checks `worthRunning(cheapestBound)` first
|
|
73
|
-
and returns the uninvested bound
|
|
74
|
-
|
|
73
|
+
and returns the uninvested bound if it loses. Never compute a shared analysis
|
|
74
|
+
just to discard it. `cast.ts`/`extraction.ts` are the references.
|
|
75
75
|
|
|
76
76
|
## Accounting
|
|
77
77
|
|
|
@@ -86,8 +86,8 @@ Weight is one currency: `weight = moves + PASS · unaccountedBytes` where
|
|
|
86
86
|
same act is charged twice (`PASS`/byte dominates).
|
|
87
87
|
|
|
88
88
|
`accounted` is a cost-ladder quantity; `cover.ts` leaves masked computed spans
|
|
89
|
-
out
|
|
90
|
-
`
|
|
89
|
+
out so `PASS`-bridged bytes are still charged. `unexplained`, `narrowDecision`,
|
|
90
|
+
`thinGrounding` are observational only.
|
|
91
91
|
|
|
92
92
|
## Pins
|
|
93
93
|
|
|
@@ -17,11 +17,11 @@ it. Harness: `bench/profile-inference.mjs`.
|
|
|
17
17
|
non-deterministic hints reported separately — never use them to gate
|
|
18
18
|
behaviour.
|
|
19
19
|
|
|
20
|
-
3. **Phases nest, they do not partition.**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
inclusive wall-clock
|
|
24
|
-
|
|
20
|
+
3. **Phases nest, they do not partition.** Each phase is charged by the layer
|
|
21
|
+
doing the work (`recognise`, the climb's two, the bridge), and a mechanism's
|
|
22
|
+
`floor` contains whatever shared analysis it first-touched. Read a phase as
|
|
23
|
+
inclusive wall-clock; never sum phases. `CostReport.elapsedMs` is the only
|
|
24
|
+
whole.
|
|
25
25
|
|
|
26
26
|
4. **Count once.** Off by default and free when off
|
|
27
27
|
(`new Mind({ profile:
|
|
@@ -36,8 +36,8 @@ root never costs a full walk.
|
|
|
36
36
|
|
|
37
37
|
## Gist, halo, dedup
|
|
38
38
|
|
|
39
|
-
On `put*`, content dedup (`hashOf`→probe→mint) gates first.
|
|
40
|
-
|
|
39
|
+
On `put*`, content dedup (`hashOf`→probe→mint) gates first. Short keys are
|
|
40
|
+
cached (`DEDUP_KEY_MAX` bypass). Near-dedup merges by `mergeThreshold(D)` on
|
|
41
41
|
unit gist cosine. Gists sit in `_pendingGist` (byte-budgeted `BoundedMap`);
|
|
42
42
|
`indexSubtree` & `pourHalo` promote via `_vecContentUpsert`/`_vecHaloUpsert` in
|
|
43
43
|
`batchSize` batches. Buffers flush on cadence, `commit()`, and close. Halo mass
|
|
@@ -55,7 +55,7 @@ deferred transaction.
|
|
|
55
55
|
Every in-memory cache is a `BoundedMap` with byte accounting and eviction (`lru`
|
|
56
56
|
vs `smallest` + `clock`/`reorder` recency). ANN reads
|
|
57
57
|
(`resonate`/`resonateHalo`) are content-addressed (`vecKey`) and dropped on any
|
|
58
|
-
index mutation; `
|
|
58
|
+
index mutation; `RESONATE_CACHE_MAX=4096`.
|
|
59
59
|
|
|
60
60
|
## Maintenance (incremental)
|
|
61
61
|
|
|
@@ -30,8 +30,7 @@ not to do, why it fails, and what to do instead.
|
|
|
30
30
|
- **WRONG:** Break equal-rank ties by picking the most recently inserted
|
|
31
31
|
edge/node.
|
|
32
32
|
- **WHY:** Tie-breaks must be corpus-determined and stable; last-inserted is
|
|
33
|
-
recency-dependent
|
|
34
|
-
first-inserted fallback).
|
|
33
|
+
recency-dependent (`AGENTS §2` Invariant 1 — first-inserted fallback).
|
|
35
34
|
- **CORRECT:** `guidedFirst`/`chooseNext`/`chooseAmong`: rank then
|
|
36
35
|
first-inserted (lowest node id / `LIMIT 1` insertion order). Pinned by
|
|
37
36
|
`test/03-recall.test.mjs` determinism suites.
|
|
@@ -55,8 +54,8 @@ not to do, why it fails, and what to do instead.
|
|
|
55
54
|
policy is enforced by masking, not pricing (`AGENTS §2` Invariant 4 — One cost
|
|
56
55
|
currency; `docs/architecture/cost-model.md` § Policy is not cost).
|
|
57
56
|
- **CORRECT:** Keep `PASS` dominating; enforce precedence in the caller (e.g.
|
|
58
|
-
`
|
|
59
|
-
|
|
57
|
+
`cover.ts` masks recognised sites overlapped by `ComputedResult`). Pinned by
|
|
58
|
+
`test/04-think.test.mjs` and `test/55-cost-meter.test.mjs`.
|
|
60
59
|
|
|
61
60
|
### 6. Reimplementing `locate`/`align` inside a mechanism
|
|
62
61
|
|
package/docs/harness/gates.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Four executable gates. Each: run the command, check what it guards, follow its
|
|
4
4
|
§.
|
|
5
5
|
|
|
6
|
-
## 1 — Correctness (all
|
|
6
|
+
## 1 — Correctness (all suites)
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
npm test
|
|
@@ -24,7 +24,7 @@ node bench/profile-inference.mjs --trace # trace is a debugging aid, not product
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Guards without trace: counters deterministic and diffable between runs; phases
|
|
27
|
-
nest (not disjoint —
|
|
27
|
+
nest (not disjoint — each phase is charged by its own layer); shared analyses
|
|
28
28
|
charged to themselves, not to the first toucher; millisecond fields are
|
|
29
29
|
non-deterministic hints only. With `--trace`, recognition idempotence still
|
|
30
30
|
holds (`test/42`). `src/meter.ts`, `docs/architecture/meter.md`, §55,
|
package/docs/mechanisms/cast.md
CHANGED
|
@@ -12,7 +12,7 @@ schema yields its own candidate and `think`'s single weight comparison picks.
|
|
|
12
12
|
halo-matched `pre.rec.sites`. The product is `pre.weave()` — `points[]` (each
|
|
13
13
|
with graded `runs[]`) and a per-query-byte `depth[]` (how many structures cover
|
|
14
14
|
that byte). CAST's single-vs-multi test is measured from those runs: a second
|
|
15
|
-
point must add ≥ one perception quantum of coverage the widest
|
|
15
|
+
point must add ≥ one perception quantum of coverage the widest does not.
|
|
16
16
|
|
|
17
17
|
## Gate — weave-local discriminative frame
|
|
18
18
|
|
|
@@ -76,5 +76,5 @@ redirection, or analogical comparison), not from a literal continuation.
|
|
|
76
76
|
## Source
|
|
77
77
|
|
|
78
78
|
`src/mind/mechanisms/cast.ts` (`counterfactualTransfer`, `seatOfNode`,
|
|
79
|
-
`MIN_WEAVE`), `src/mind/match.ts` (`alignGraded`, `project
|
|
79
|
+
`MIN_WEAVE`, `weave.depth`), `src/mind/match.ts` (`alignGraded`, `project`),
|
|
80
80
|
`src/geometry.ts` (`dominates`), `src/mind/graph-search.ts` (`STEP`).
|
package/docs/mechanisms/cover.md
CHANGED
|
@@ -15,9 +15,8 @@ consumes them directly; any site whose bytes overlap a computed span is masked
|
|
|
15
15
|
- `formRules` follow continuation edges (`GraphSearch.formRules`): each hop
|
|
16
16
|
costs `STEP` (1). Forks across all continuations up to the hub bound;
|
|
17
17
|
disambiguation is distributional, not heuristic.
|
|
18
|
-
- Edge-less forms may hop via a halo sibling (`conceptHop` / `resolveConcepts`
|
|
19
|
-
|
|
20
|
-
continuation.
|
|
18
|
+
- Edge-less forms may hop via a halo sibling (`conceptHop` / `resolveConcepts`)
|
|
19
|
+
at `CONCEPT` (10), borrowing a synonym's continuation.
|
|
21
20
|
|
|
22
21
|
## Gate — `leadsSomewhere` (`src/mind/traverse.ts`)
|
|
23
22
|
|