@hviana/sema 0.8.3 → 0.8.5
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 +11 -10
- package/README.md +17 -38
- package/dist/example/demo.js +85 -34
- package/dist/src/geometry.d.ts +0 -10
- package/dist/src/geometry.js +0 -12
- package/dist/src/meter.d.ts +11 -0
- package/dist/src/meter.js +11 -0
- package/dist/src/mind/articulation.js +1 -1
- package/dist/src/mind/attention.js +2 -1
- package/dist/src/mind/derivation.d.ts +201 -0
- package/dist/src/mind/derivation.js +327 -0
- package/dist/src/mind/graph-search.d.ts +2 -1
- package/dist/src/mind/graph-search.js +37 -15
- package/dist/src/mind/match.d.ts +2 -0
- package/dist/src/mind/match.js +2 -0
- package/dist/src/mind/mechanisms/alu.js +0 -2
- package/dist/src/mind/mechanisms/cast.d.ts +1 -5
- package/dist/src/mind/mechanisms/cast.js +15 -18
- package/dist/src/mind/mechanisms/confluence.d.ts +0 -3
- package/dist/src/mind/mechanisms/confluence.js +3 -9
- package/dist/src/mind/mechanisms/cover.js +17 -20
- package/dist/src/mind/mechanisms/extraction.d.ts +0 -1
- package/dist/src/mind/mechanisms/extraction.js +13 -8
- package/dist/src/mind/mechanisms/prefix-completion.js +0 -1
- package/dist/src/mind/mechanisms/recall.d.ts +0 -1
- package/dist/src/mind/mechanisms/recall.js +8 -9
- package/dist/src/mind/mechanisms/reference.js +3 -4
- package/dist/src/mind/pipeline-mechanism.d.ts +1 -4
- package/dist/src/mind/pipeline.js +106 -41
- package/dist/src/mind/rationale.d.ts +0 -11
- package/dist/src/mind/rationale.js +6 -32
- package/dist/src/mind/reasoning.d.ts +4 -30
- package/dist/src/mind/reasoning.js +183 -151
- package/dist/src/mind/types.js +6 -3
- package/docs/INDEX.md +23 -24
- package/docs/INVARIANTS.md +16 -17
- package/docs/architecture/bounded-reads.md +4 -4
- package/docs/architecture/closure.md +65 -0
- package/docs/architecture/commonality.md +27 -18
- package/docs/architecture/cost-model.md +5 -5
- package/docs/architecture/exact-vs-approximate.md +4 -4
- package/docs/architecture/factored-machinery.md +14 -14
- package/docs/architecture/mechanism-market.md +9 -9
- package/docs/architecture/meter.md +4 -5
- package/docs/architecture/store.md +2 -2
- package/docs/architecture/thresholds.md +1 -1
- package/docs/failures/tempting-but-wrong.md +11 -1
- package/docs/harness/gates.md +6 -6
- package/docs/mechanisms/cover.md +2 -2
- package/example/demo.ts +90 -37
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/geometry.ts +0 -13
- package/src/meter.ts +11 -0
- package/src/mind/articulation.ts +0 -1
- package/src/mind/attention.ts +2 -1
- package/src/mind/derivation.ts +473 -0
- package/src/mind/graph-search.ts +37 -20
- package/src/mind/match.ts +2 -0
- package/src/mind/mechanisms/alu.ts +0 -2
- package/src/mind/mechanisms/cast.ts +17 -21
- package/src/mind/mechanisms/confluence.ts +3 -13
- package/src/mind/mechanisms/cover.ts +17 -20
- package/src/mind/mechanisms/extraction.ts +13 -9
- package/src/mind/mechanisms/prefix-completion.ts +0 -1
- package/src/mind/mechanisms/recall.ts +7 -9
- package/src/mind/mechanisms/reference.ts +2 -3
- package/src/mind/pipeline-mechanism.ts +1 -4
- package/src/mind/pipeline.ts +121 -46
- package/src/mind/rationale.ts +6 -36
- package/src/mind/reasoning.ts +208 -178
- package/src/mind/types.ts +5 -2
- package/test/133-the-decision-point-renders-the-state.test.mjs +204 -0
- package/test/134-the-law-explains-the-engines-own-refusal.test.mjs +237 -0
- package/test/135-one-law-any-producer.test.mjs +289 -0
- package/test/136-the-two-named-limits.test.mjs +205 -0
- package/test/137-the-law-lives-once-and-below.test.mjs +400 -0
- package/test/138-the-remainder-drains-only-what-a-move-declares.test.mjs +62 -0
- package/test/139-the-witness-is-engagement-not-explanation.test.mjs +51 -0
- package/test/140-irrelevant-supply-does-not-change-an-answer.test.mjs +48 -0
- package/test/141-the-question-is-paid-at-construction.test.mjs +98 -0
- package/test/36-already-answered-fusion.test.mjs +20 -2
- package/test/37-cluster-dispersion-fusion.test.mjs +30 -3
- package/test/38-reason-restate-guard.test.mjs +22 -2
- package/test/55-cost-meter.test.mjs +4 -1
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import type { MindContext } from "./types.js";
|
|
2
2
|
import type { Precomputed } from "./pipeline-mechanism.js";
|
|
3
|
-
|
|
4
|
-
* the question, so voicing it back only restates part of what was asked,
|
|
5
|
-
* never answers it. The exact guard recallByResonance already applies to
|
|
6
|
-
* its OWN grounding candidates (tier 1's `restates`, tier 2's subspan
|
|
7
|
-
* check, tier 0b's argument-binding subspan check) — every mechanism that
|
|
8
|
-
* walks a LEARNT CONTINUATION EDGE past an already-vetted grounding
|
|
9
|
-
* (reason()'s own hops below, and CAST's `projectCounterfactual` seat
|
|
10
|
-
* substitution — see cast.ts) needs the same guard applied to what the
|
|
11
|
-
* walk turns up, since `follow()`/`chooseNext`/`pivotInto` know nothing of
|
|
12
|
-
* the query at all — only of what structurally continues what. */
|
|
13
|
-
export declare function restatesQuery(query: Uint8Array, bytes: Uint8Array): boolean;
|
|
3
|
+
import { type DerivationState, type Span } from "./derivation.js";
|
|
14
4
|
/** Extend a grounded answer forward across facts (multi-hop reasoning).
|
|
15
5
|
* Pivots on the longest unconsumed learnt context each answer contains,
|
|
16
6
|
* then follows the pivot's continuation to the next fact. **The chain ends
|
|
@@ -26,28 +16,12 @@ export declare function restatesQuery(query: Uint8Array, bytes: Uint8Array): boo
|
|
|
26
16
|
* when it declared one — see the pivot's own containment rule. `pre` is the
|
|
27
17
|
* response's shared pre-computation — the post-grounding stages read the
|
|
28
18
|
* same container the mechanisms did. */
|
|
29
|
-
|
|
30
|
-
* answer), the spans of the grounding's UNCOVERED material that each step was
|
|
31
|
-
* justified by, and how many steps were taken. The last two exist so the
|
|
32
|
-
* caller can price the extension in the ladder's own currency — `steps · STEP`
|
|
33
|
-
* against `PASS · unaccounted` — instead of taking it unconditionally. Both
|
|
34
|
-
* are FACTS, not verdicts: nothing here says whether the extension was worth
|
|
35
|
-
* it; that is the comparison's job, one layer up. */
|
|
36
|
-
export interface ReasonedAnswer {
|
|
37
|
-
bytes: Uint8Array;
|
|
38
|
-
carried: Array<[number, number]>;
|
|
39
|
-
steps: number;
|
|
40
|
-
}
|
|
41
|
-
export declare function reason(ctx: MindContext, query: Uint8Array, answer: Uint8Array, preConsumed: ReadonlySet<number>, pre: Precomputed, voiced?: readonly Uint8Array[],
|
|
42
|
-
/** The query material the GROUNDING left uncovered — the cost ladder's own
|
|
43
|
-
* `unaccounted` spans. Only the reasoner's OWN extensions are judged
|
|
44
|
-
* against it; a mechanism carrying its own `used` set owns its shape. */
|
|
45
|
-
uncovered?: readonly (readonly [number, number])[]): Promise<ReasonedAnswer>;
|
|
19
|
+
export declare function reason(ctx: MindContext, query: Uint8Array, d0: DerivationState, preConsumed: ReadonlySet<number>, pre: Precomputed, voiced?: readonly Uint8Array[]): Promise<DerivationState>;
|
|
46
20
|
/** Fuse independent points of attention into one answer (multi-topic).
|
|
47
21
|
* When the consensus climb finds more than one dominant point, each
|
|
48
22
|
* independent point grounds its own answer; they are bridged together
|
|
49
23
|
* by any learnt connector the graph holds between them. */
|
|
50
|
-
export declare function fuseAttention(ctx: MindContext, query: Uint8Array,
|
|
24
|
+
export declare function fuseAttention(ctx: MindContext, query: Uint8Array, state: DerivationState, pre: Precomputed,
|
|
51
25
|
/** True when `primary` never touched the consensus climb at all — e.g. a
|
|
52
26
|
* pure ALU computation, which has no anchor of its own. commitVotes
|
|
53
27
|
* ALWAYS admits the dominant root regardless of its vote (attention.ts:
|
|
@@ -61,4 +35,4 @@ unclimbed?: boolean,
|
|
|
61
35
|
* which is the layer that knows how a given grounding records its evidence;
|
|
62
36
|
* fuseAttention just reads a position from it. Empty or absent preserves
|
|
63
37
|
* the original behaviour exactly. */
|
|
64
|
-
primarySpans?: ReadonlyArray<
|
|
38
|
+
primarySpans?: ReadonlyArray<Span>): Promise<DerivationState>;
|
|
@@ -8,25 +8,30 @@ import { resolve } from "./primitives.js";
|
|
|
8
8
|
import { hubBound } from "./traverse.js";
|
|
9
9
|
import { containsSpan, follow, haloSiblings, project } from "./match.js";
|
|
10
10
|
import { joinWithBridge, pivotInto } from "./resonance.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
|
|
11
|
+
import { admissible, advance } from "./derivation.js";
|
|
12
|
+
import { closure, restates, unaccountedBytes, } from "./derivation.js";
|
|
13
|
+
import { STEP } from "./graph-search.js";
|
|
14
|
+
/** Extend a grounded answer forward across facts (multi-hop reasoning).
|
|
15
|
+
* Pivots on the longest unconsumed learnt context each answer contains,
|
|
16
|
+
* then follows the pivot's continuation to the next fact. **The chain ends
|
|
17
|
+
* when it STOPS, never when a count runs out**: every exit is a refusal (no
|
|
18
|
+
* pivot, no forward step, no question material carried) and the walk is bounded
|
|
19
|
+
* by the material and the graph — `consumed` refuses to revisit a node. There
|
|
20
|
+
* is no hop allowance, so this doc deliberately names no `cfg` capacity: the
|
|
21
|
+
* cover prices every hop at `STEP` and lets the search decide the depth, and a
|
|
22
|
+
* second count here would be a second decision about the same thing.
|
|
23
|
+
* `preConsumed` carries node ids already
|
|
24
|
+
* spoken for by the grounding stage (cover/extract/CAST). `voiced` carries
|
|
25
|
+
* the BYTES of the anchors a mechanism declared it voiced (its `used` set),
|
|
26
|
+
* when it declared one — see the pivot's own containment rule. `pre` is the
|
|
27
|
+
* response's shared pre-computation — the post-grounding stages read the
|
|
28
|
+
* same container the mechanisms did. */
|
|
29
|
+
export async function reason(ctx, query, d0, preConsumed, pre, voiced = []) {
|
|
30
|
+
const answer = d0.product;
|
|
31
|
+
/** The query material the GROUNDING left uncovered — the state's own
|
|
32
|
+
* remainder. Only the reasoner's OWN extensions are judged against it; a
|
|
33
|
+
* mechanism carrying its own `used` set owns its shape. */
|
|
34
|
+
const uncovered = d0.remainder;
|
|
30
35
|
// Echo guard: a query that is ITSELF a learnt continuation (some context's
|
|
31
36
|
// answer) is being asked back at the system — hopping forward from it would
|
|
32
37
|
// chain through the very fact that produced it and echo the conversation
|
|
@@ -34,7 +39,7 @@ uncovered = []) {
|
|
|
34
39
|
// broad structural gate; pinned by test/31-audit.
|
|
35
40
|
const qId = pre.queryResolved;
|
|
36
41
|
if (qId !== null && ctx.store.prevCount(qId) > 0) {
|
|
37
|
-
return
|
|
42
|
+
return d0;
|
|
38
43
|
}
|
|
39
44
|
// Consume a node and its neighbours for pivot-cycle prevention — CAPPED at
|
|
40
45
|
// the hub bound, via the store's LIMITed edge reads: a common continuation's
|
|
@@ -52,7 +57,7 @@ uncovered = []) {
|
|
|
52
57
|
// is nothing left to chain for.
|
|
53
58
|
//
|
|
54
59
|
// Every stopping condition in the loop below judges the ANSWER (`consumed` /
|
|
55
|
-
// `
|
|
60
|
+
// the law's `restates` / `bytesEqual`); none asks whether the QUESTION was
|
|
56
61
|
// satisfied. So a single-hop question whose answer happens to name another
|
|
57
62
|
// learnt context extends past a correct answer and REPLACES it:
|
|
58
63
|
//
|
|
@@ -92,7 +97,7 @@ uncovered = []) {
|
|
|
92
97
|
? null
|
|
93
98
|
: ctx.store.prevFirst(groundedId, bound);
|
|
94
99
|
if (qId !== null && groundedPrev !== null && groundedPrev.includes(qId)) {
|
|
95
|
-
return
|
|
100
|
+
return d0;
|
|
96
101
|
}
|
|
97
102
|
const consumed = new Set();
|
|
98
103
|
/** `prev` lets a caller hand in an already-read reverse-edge list — hop 0
|
|
@@ -136,164 +141,158 @@ uncovered = []) {
|
|
|
136
141
|
else {
|
|
137
142
|
await preconsume();
|
|
138
143
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
// the extension's cost against what it explains, in the ladder's own currency.
|
|
149
|
-
const carried = [];
|
|
150
|
-
let steps = 0;
|
|
144
|
+
// ── THE WALK, AS THE LAW'S ───────────────────────────────────────────
|
|
145
|
+
//
|
|
146
|
+
// This function no longer decides whether a step may be taken: it OFFERS a
|
|
147
|
+
// continuation — a forward step from the answer's own learnt edge, or a pivot
|
|
148
|
+
// on a learnt context the answer contains — and `derivation.ts`'s law admits
|
|
149
|
+
// or refuses it. The state it offers against is the pipeline's own: the
|
|
150
|
+
// grounding's remainder (what the question still owes), its accounting, its
|
|
151
|
+
// cost.
|
|
152
|
+
//
|
|
151
153
|
// NO ALLOWANCE: THE CHAIN ENDS WHEN IT STOPS. Every exit below is the law —
|
|
152
154
|
// 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:
|
|
154
|
-
// step
|
|
155
|
-
// `consumed` refuses to revisit a node. `recallQueryK` no longer bounds
|
|
156
|
-
// reasoner here; it keeps its other roles (the bridge's candidate reads,
|
|
157
|
-
// pivot's probe budget, the resonance limits).
|
|
155
|
+
// bounded by the material and the graph rather than by a count: the law
|
|
156
|
+
// requires each step to engage what is left (or to move to new structure),
|
|
157
|
+
// and `consumed` refuses to revisit a node. `recallQueryK` no longer bounds
|
|
158
|
+
// the reasoner here; it keeps its other roles (the bridge's candidate reads,
|
|
159
|
+
// the pivot's probe budget, the resonance limits).
|
|
158
160
|
//
|
|
159
|
-
// Measured before removing
|
|
160
|
-
// case in the suite — is green and no slower without
|
|
161
|
-
//
|
|
161
|
+
// Measured before removing the allowance: test/89 — the corpus-cost guard, the
|
|
162
|
+
// heaviest case in the suite — is green and no slower without it (27 s against
|
|
163
|
+
// 30 s); and raising it from 12 to 200 changed neither the answer nor
|
|
162
164
|
// `pivotSteps` on the chain fixtures.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
const qv = pre.guide; // the response-wide guide IS the query's gist
|
|
166
|
+
const W = ctx.space.maxGroup;
|
|
167
|
+
// WHOSE EXTENSION IS THIS? `voiced` is what the mechanism WITHHELD (the
|
|
168
|
+
// pipeline sends the used anchors' CONTINUATIONS, not their bytes), so a
|
|
169
|
+
// non-empty `voiced` means exactly what that note says: the grounding came
|
|
170
|
+
// from a mechanism that carries its own short `used` set (cast/join) and
|
|
171
|
+
// therefore OWNS the shape of its answer. The further terms inside such a
|
|
172
|
+
// seat are legitimately followable (test/29 C3's `Mona Lisa` lives inside the
|
|
173
|
+
// voiced seat and leads on to a fact about neither analog), which the law
|
|
174
|
+
// expresses as the identity species of progress — `moves` — declared by the
|
|
175
|
+
// reporter and never inferred from the mechanism's name.
|
|
176
|
+
const producerOwnsShape = voiced.length > 0;
|
|
177
|
+
const startedFrom = answer;
|
|
178
|
+
let hop = 0;
|
|
179
|
+
let t;
|
|
180
|
+
// WHAT THE OFFERED STEP WOULD BE. The law decides, so the accepted step is
|
|
181
|
+
// traced where the decision went (`onTaken`) and a refused one is reported as
|
|
182
|
+
// the law's refusal (`onRefused`) — a step is never reported before it is
|
|
183
|
+
// admitted.
|
|
184
|
+
let pending = null;
|
|
185
|
+
const offer = async (d) => {
|
|
186
|
+
const cur = d.product;
|
|
187
|
+
// The first step's `cur` IS the grounding's product, so the guard above
|
|
188
|
+
// already resolved it and read its reverse edges — reuse both.
|
|
166
189
|
const curId = hop === 0 ? groundedId : resolve(ctx, cur);
|
|
167
190
|
consumeNode(curId, hop === 0 ? groundedPrev ?? undefined : undefined);
|
|
191
|
+
hop++;
|
|
168
192
|
// Forward-absorb: follow only UNCONSUMED continuations. The gate below
|
|
169
|
-
// checks an unconsumed edge EXISTS, but follow()'s chooseNext knows
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
//
|
|
193
|
+
// checks an unconsumed edge EXISTS, but follow()'s chooseNext knows nothing
|
|
194
|
+
// of `consumed` and may still walk to a consumed fixpoint — absorbing it
|
|
195
|
+
// would repeat content the grounding stage already spoke for, so a consumed
|
|
196
|
+
// fixpoint falls through to the pivot step instead. Offered with `moves`:
|
|
197
|
+
// completing the answer's OWN learnt form is an identity step, not a claim
|
|
198
|
+
// about the asker's material.
|
|
173
199
|
if (curId !== null &&
|
|
174
200
|
ctx.store.nextFirst(curId, bound).some((n) => !consumed.has(n))) {
|
|
175
201
|
const fwd = await follow(ctx, curId, qv);
|
|
176
202
|
const fwdId = fwd !== null ? resolve(ctx, fwd) : null;
|
|
177
203
|
if (fwd !== null && !bytesEqual(fwd, cur) &&
|
|
178
204
|
(fwdId === null || !consumed.has(fwdId)) &&
|
|
179
|
-
!
|
|
205
|
+
!restates(query, fwd, 0, { proper: true })) {
|
|
180
206
|
consumeAll(curId);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
]);
|
|
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");
|
|
185
|
-
cur = fwd;
|
|
186
|
-
steps++;
|
|
187
|
-
continue;
|
|
207
|
+
pending = { kind: "absorb", cur, curId, fwd };
|
|
208
|
+
return { product: fwd, contains: true, reaches: true, cost: STEP };
|
|
188
209
|
}
|
|
189
210
|
}
|
|
190
|
-
// Pivot:
|
|
211
|
+
// Pivot: the longest unconsumed learnt context the answer contains.
|
|
191
212
|
consumeAll(curId);
|
|
192
213
|
const pivot = await pivotInto(ctx, cur, consumed, voiced);
|
|
193
214
|
if (pivot === null)
|
|
194
|
-
|
|
215
|
+
return null;
|
|
195
216
|
const fc = await follow(ctx, pivot, qv);
|
|
196
217
|
consumeAll(pivot);
|
|
197
|
-
if (fc === null || bytesEqual(fc, cur) ||
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const producerOwnsShape = voiced.length > 0;
|
|
219
|
-
if (!producerOwnsShape && uncovered.length > 0) {
|
|
220
|
-
const W = ctx.space.maxGroup;
|
|
221
|
-
let progress = false;
|
|
222
|
-
let justified;
|
|
223
|
-
for (const [a, b] of uncovered) {
|
|
224
|
-
for (let i = a; i + W <= b && !progress; i++) {
|
|
225
|
-
if (indexOf(fc, query.subarray(i, i + W), 0) >= 0) {
|
|
226
|
-
progress = true;
|
|
227
|
-
justified = [a, b];
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (progress)
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
if (progress && justified !== undefined)
|
|
234
|
-
carried.push(justified);
|
|
235
|
-
if (!progress) {
|
|
236
|
-
// THE BRAKE, MADE VISIBLE. The reasoner declines a step that carries
|
|
237
|
-
// none of the material the grounding left uncovered — the drift the
|
|
238
|
-
// extension tests pin. A refusal that leaves no trace is the kind of
|
|
239
|
-
// silent cut AGENTS §6 forbids: the rationale is where a reader learns
|
|
240
|
-
// that an extension was declined for want of question material, and
|
|
241
|
-
// where the next person sees why the chain stopped here. Measured with
|
|
242
|
-
// the check disabled, test/110 and test/116 fail — so this brake is the
|
|
243
|
-
// only thing keeping the extension honest until the pivot reports its
|
|
244
|
-
// own accounted spans and the ladder can judge it instead.
|
|
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);
|
|
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 ` +
|
|
265
|
-
`uncovered (${left} byte(s) in ${uncovered.length} span(s)) — refused`);
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
218
|
+
if (fc === null || bytesEqual(fc, cur) ||
|
|
219
|
+
restates(query, fc, 0, { proper: true })) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
pending = { kind: "pivot", cur, pivot, fc };
|
|
223
|
+
// Offered with the identity species ONLY when the grounding declared what it
|
|
224
|
+
// speaks for; otherwise the law requires this step to carry question
|
|
225
|
+
// material the grounding left unaccounted, which is the drift the extension
|
|
226
|
+
// tests pin — refused by the law's own measure, not by a private window
|
|
227
|
+
// test.
|
|
228
|
+
return {
|
|
229
|
+
product: fc,
|
|
230
|
+
contains: true,
|
|
231
|
+
reaches: producerOwnsShape,
|
|
232
|
+
cost: STEP,
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
const closed_ = await closure(d0, query, W, offer, (before, after) => {
|
|
236
|
+
if (ctx.meter) {
|
|
237
|
+
ctx.meter.closureDrainedBytes += unaccountedBytes(before.remainder) -
|
|
238
|
+
unaccountedBytes(after.remainder);
|
|
268
239
|
}
|
|
269
|
-
|
|
270
|
-
|
|
240
|
+
const p = pending;
|
|
241
|
+
pending = null;
|
|
242
|
+
if (p === null)
|
|
243
|
+
return;
|
|
271
244
|
t ??= ctx.trace?.enter("reason", [rItem(startedFrom, "grounded")]);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
245
|
+
if (p.kind === "absorb") {
|
|
246
|
+
ctx.trace?.step("absorbForward", [rItem(p.cur, "answer", p.curId ?? undefined)], [rItem(p.fwd, "answer", resolve(ctx, p.fwd) ?? undefined)], "the answer is itself a learnt fact — follow its continuation to the fixpoint");
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
if (ctx.meter)
|
|
250
|
+
ctx.meter.pivotSteps++;
|
|
251
|
+
ctx.trace?.step("pivotStep", [rItem(p.cur, "answer"), rNode(ctx, p.pivot, "pivot")], [rItem(p.fc, "answer", resolve(ctx, p.fc) ?? undefined)], "pivot on the shared span this answer contains, then step forward across that fact");
|
|
252
|
+
}
|
|
253
|
+
}, (at) => {
|
|
254
|
+
const p = pending;
|
|
255
|
+
pending = null;
|
|
256
|
+
if (p === null || p.kind !== "pivot")
|
|
257
|
+
return;
|
|
258
|
+
// THE BRAKE, MADE VISIBLE — and it is now the LAW's refusal, reported
|
|
259
|
+
// where it happened. The reasoner declines a step that carries none of
|
|
260
|
+
// the material the grounding left unaccounted. A refusal that leaves no
|
|
261
|
+
// trace is the kind of silent cut AGENTS §6 forbids: the rationale is
|
|
262
|
+
// where a reader learns that an extension was declined for want of
|
|
263
|
+
// question material, and where the next person sees why the chain stopped
|
|
264
|
+
// here. Measured with the check disabled, test/110 and test/116 fail.
|
|
265
|
+
const left = unaccountedBytes(at.remainder);
|
|
266
|
+
ctx.trace?.step("pivotRefused", [rItem(p.cur, "answer"), rItem(query, "query")], at.remainder.map(([a, b]) => rItem(query.subarray(a, b), "uncovered")), `the step carries none of the question material the grounding left ` +
|
|
267
|
+
`unaccounted (${left} byte(s) in ${at.remainder.length} span(s)) — refused`);
|
|
268
|
+
});
|
|
276
269
|
// INSTRUMENTATION ONLY — the extension's two facts, untraced (meter.ts
|
|
277
270
|
// contract 1: a counter never reaches a decision). They are what a caller
|
|
278
|
-
// needs to PRICE the extension instead of taking it unconditionally
|
|
279
|
-
//
|
|
271
|
+
// needs to PRICE the extension instead of taking it unconditionally, and both
|
|
272
|
+
// are now read off the state the law advanced rather than accumulated beside
|
|
273
|
+
// it: the work it did is the cost it accumulated, and the material it carried
|
|
274
|
+
// is the accounting the law's witnesses added.
|
|
275
|
+
const steps = closed_.cost - d0.cost;
|
|
280
276
|
if (ctx.meter) {
|
|
281
277
|
ctx.meter.reasonSteps += steps;
|
|
282
|
-
|
|
278
|
+
// The accounting the law's witnesses added, summed by the law's own function
|
|
279
|
+
// over the tail of the state's list — and computed ONLY when a meter is
|
|
280
|
+
// attached: this used to slice and MAP a fresh array on every response, for a
|
|
281
|
+
// counter that usually does not exist. One allocation, under the meter.
|
|
282
|
+
ctx.meter.reasonCarriedBytes += unaccountedBytes(closed_.accounted.slice(d0.accounted.length));
|
|
283
283
|
}
|
|
284
|
-
t?.done([rItem(
|
|
285
|
-
// A FIXPOINT: no further step was
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
// a refusal, and the note is true again by construction.
|
|
284
|
+
t?.done([rItem(closed_.product, "answer", resolve(ctx, closed_.product) ?? undefined)],
|
|
285
|
+
// A FIXPOINT: no further step was offered, or the law refused the one that
|
|
286
|
+
// was. There is no allowance to exhaust, so the note is true by
|
|
287
|
+
// construction.
|
|
289
288
|
"the multi-hop chain's fixpoint");
|
|
290
|
-
return
|
|
289
|
+
return closed_;
|
|
291
290
|
}
|
|
292
291
|
/** Fuse independent points of attention into one answer (multi-topic).
|
|
293
292
|
* When the consensus climb finds more than one dominant point, each
|
|
294
293
|
* independent point grounds its own answer; they are bridged together
|
|
295
294
|
* by any learnt connector the graph holds between them. */
|
|
296
|
-
export async function fuseAttention(ctx, query,
|
|
295
|
+
export async function fuseAttention(ctx, query, state, pre,
|
|
297
296
|
/** True when `primary` never touched the consensus climb at all — e.g. a
|
|
298
297
|
* pure ALU computation, which has no anchor of its own. commitVotes
|
|
299
298
|
* ALWAYS admits the dominant root regardless of its vote (attention.ts:
|
|
@@ -308,6 +307,11 @@ unclimbed = false,
|
|
|
308
307
|
* fuseAttention just reads a position from it. Empty or absent preserves
|
|
309
308
|
* the original behaviour exactly. */
|
|
310
309
|
primarySpans = []) {
|
|
310
|
+
// THE STATE, NOT BARE BYTES: fusion is one more transition of the derivation
|
|
311
|
+
// the walk returned, so it reads that state's product and hands back a state.
|
|
312
|
+
// Its own structural gates stay here — this is the layer that can resolve
|
|
313
|
+
// those witnesses, and the law never re-derives one.
|
|
314
|
+
const primary = state.product;
|
|
311
315
|
// When the answer is structurally drawn from the query itself
|
|
312
316
|
// (extraction), it already spans all the query's pieces — fusion
|
|
313
317
|
// would only add noise from unrelated stored contexts. The gate is
|
|
@@ -316,7 +320,7 @@ primarySpans = []) {
|
|
|
316
320
|
// short answers over long queries, silently starving multi-topic queries
|
|
317
321
|
// of fusion.
|
|
318
322
|
if (containsSpan(ctx, query, primary))
|
|
319
|
-
return
|
|
323
|
+
return state;
|
|
320
324
|
// The committed points of attention ARE the shared climb's roots (same
|
|
321
325
|
// query, same k, same DF mode) — read them from Precomputed instead of
|
|
322
326
|
// re-climbing, so even a traced response pays for the climb once.
|
|
@@ -357,7 +361,7 @@ primarySpans = []) {
|
|
|
357
361
|
const lonePromotes = unclimbed && forest.length === 1 &&
|
|
358
362
|
forest[0].breadth > 0.5 && independentOfPrimary(forest[0]);
|
|
359
363
|
if (forest.length === 0 || (forest.length <= 1 && !lonePromotes)) {
|
|
360
|
-
return
|
|
364
|
+
return state;
|
|
361
365
|
}
|
|
362
366
|
// WHERE THE QUERY ASKED FOR IT. The sort below orders the fused pieces by
|
|
363
367
|
// query position, which is the whole point of the `start` field: a
|
|
@@ -433,7 +437,13 @@ primarySpans = []) {
|
|
|
433
437
|
// it fires on exact content-addressed recurrence, not on how strongly
|
|
434
438
|
// the root resonates.
|
|
435
439
|
const cont = await follow(ctx, root.anchor, qv);
|
|
436
|
-
if (cont !== null && cont.length > 0 &&
|
|
440
|
+
if (cont !== null && cont.length > 0 &&
|
|
441
|
+
// The law's positional reading: the caller knows the material it is
|
|
442
|
+
// looking for lies AT OR AFTER this root, which is the witness; the law
|
|
443
|
+
// owns the containment test itself. The `cont.length > 0` guard stays
|
|
444
|
+
// here because an EMPTY continuation indexes at every offset — the law
|
|
445
|
+
// has no opinion about whether "nothing" counts as said.
|
|
446
|
+
restates(query, cont, 0, { from: root.end })) {
|
|
437
447
|
ctx.trace?.step("alreadyAnswered", [rNode(ctx, root.anchor, "point", root.vote)], [rItem(cont, "continuation")], "this point's own learnt continuation already appears later in the query — already answered, not fused");
|
|
438
448
|
continue;
|
|
439
449
|
}
|
|
@@ -446,7 +456,7 @@ primarySpans = []) {
|
|
|
446
456
|
}
|
|
447
457
|
if (pieces.length === 1) {
|
|
448
458
|
t?.done([rItem(primary, "answer")], "no further independent point grounded");
|
|
449
|
-
return
|
|
459
|
+
return state;
|
|
450
460
|
}
|
|
451
461
|
pieces.sort((a, b) => a.start - b.start);
|
|
452
462
|
let out = pieces[0].bytes;
|
|
@@ -460,5 +470,27 @@ primarySpans = []) {
|
|
|
460
470
|
// back `primary` untouched. Untraced on purpose (meter.ts contract 1).
|
|
461
471
|
if (ctx.meter)
|
|
462
472
|
ctx.meter.fuseRuns++;
|
|
463
|
-
|
|
473
|
+
// A FUSION IS A TRANSITION, and the only one in the engine that can splice the
|
|
474
|
+
// QUESTION'S OWN material into the product. So it is OFFERED to the law rather
|
|
475
|
+
// than built by hand: the law reads the window the fused product holds — the
|
|
476
|
+
// same reading the carries admission uses, one definition — accounts for the
|
|
477
|
+
// span it carried, and lets the question's remainder drain on EVIDENCE. A
|
|
478
|
+
// fusion that carries nothing consumes nothing, because the reading finds no
|
|
479
|
+
// window; and `reaches` is declared only when the fusion composed another root,
|
|
480
|
+
// which is structure this derivation had not stood on.
|
|
481
|
+
const fusedT = {
|
|
482
|
+
product: out,
|
|
483
|
+
contains: true,
|
|
484
|
+
reaches: rest.length > 0,
|
|
485
|
+
cost: STEP,
|
|
486
|
+
};
|
|
487
|
+
const fusedWitness = admissible(state, fusedT, query, ctx.space.maxGroup);
|
|
488
|
+
if (fusedWitness === null)
|
|
489
|
+
return { ...state, product: out };
|
|
490
|
+
const fused = advance(state, fusedT, fusedWitness);
|
|
491
|
+
if (ctx.meter) {
|
|
492
|
+
ctx.meter.closureDrainedBytes += unaccountedBytes(state.remainder) -
|
|
493
|
+
unaccountedBytes(fused.remainder);
|
|
494
|
+
}
|
|
495
|
+
return fused;
|
|
464
496
|
}
|
package/dist/src/mind/types.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// GraphSearchHost is defined first (minimal imports) so GraphSearch can import
|
|
4
4
|
// it without pulling in the full MindContext.
|
|
5
|
-
import { bytesEqual, concatBytes
|
|
5
|
+
import { bytesEqual, concatBytes } from "../bytes.js";
|
|
6
|
+
import { restates } from "./derivation.js";
|
|
6
7
|
import { dominates } from "../geometry.js";
|
|
7
8
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
8
9
|
// FREE FUNCTIONS (pure, no state)
|
|
@@ -32,12 +33,14 @@ export function spliceAll(segs) {
|
|
|
32
33
|
export function segRestatesQuery(s, query, queryLen, W) {
|
|
33
34
|
if (!s.rec)
|
|
34
35
|
return false;
|
|
36
|
+
// THE LITERAL EXEMPTION IS THE CALLER'S. A span that IS the site's own bytes
|
|
37
|
+
// at its own position is naming what is already there, not substituting for
|
|
38
|
+
// it — and only this caller knows that, so it says so by not asking.
|
|
35
39
|
const literal = s.j - s.i === s.bytes.length &&
|
|
36
40
|
bytesEqual(s.bytes, query.subarray(s.i, s.j));
|
|
37
41
|
if (literal)
|
|
38
42
|
return false;
|
|
39
|
-
return s.bytes
|
|
40
|
-
indexOf(query, s.bytes, 0) >= 0;
|
|
43
|
+
return restates(query, s.bytes, W, { proper: true });
|
|
41
44
|
}
|
|
42
45
|
/** Lift the answer out of the cover for think: the recognised region, free of
|
|
43
46
|
* the asker's surrounding (unrecognised) framing — and free of any chosen
|
package/docs/INDEX.md
CHANGED
|
@@ -8,10 +8,10 @@ proof in `test/` (pins that fail when the law is broken).
|
|
|
8
8
|
|
|
9
9
|
| Task | Read | Why |
|
|
10
10
|
| --------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
11
|
-
| Add a mechanism | `docs/architecture/mechanism-market.md` + `docs/mechanisms/*.md` | Market contract:
|
|
12
|
-
| Add a threshold | `docs/architecture/thresholds.md` | All cutoffs are formulas over D/W/N
|
|
13
|
-
| Debug an answer | `docs/architecture/cost-model.md` + `src/meter.ts` | One
|
|
14
|
-
| Understand the fold | `docs/architecture/fold-contract.md` | Deposit and inference
|
|
11
|
+
| Add a mechanism | `docs/architecture/mechanism-market.md` + `docs/mechanisms/*.md` | Market contract: the four constraints |
|
|
12
|
+
| Add a threshold | `docs/architecture/thresholds.md` | All cutoffs are formulas over D/W/N; `config.ts` holds budgets only |
|
|
13
|
+
| Debug an answer | `docs/architecture/cost-model.md` + `src/meter.ts` | One ladder decides every grounding choice |
|
|
14
|
+
| Understand the fold | `docs/architecture/fold-contract.md` | Deposit and inference compute the same tree |
|
|
15
15
|
| Add a store backend | `docs/architecture/store.md` + `docs/architecture/bounded-reads.md` | `AbstractStore` owns domain logic; backends are thin wrappers with capped reads |
|
|
16
16
|
| Add an ALU operation | `src/alu/README.md` | One `registry.derive` per op composing existing ops; no new `derive` needed |
|
|
17
17
|
| Add a matcher or projection | `docs/architecture/match-project.md` | Mechanisms are `(matcher, direction, gate)` configs over the shared `match.ts` family |
|
|
@@ -19,23 +19,24 @@ proof in `test/` (pins that fail when the law is broken).
|
|
|
19
19
|
| Change vector search | `docs/architecture/exact-vs-approximate.md` + `docs/architecture/bounded-reads.md` | Scores propose, bytes dispose; ANN is bounded by `hubBound` |
|
|
20
20
|
| Profile or bound work | `docs/architecture/meter.md` + `docs/architecture/bounded-reads.md` | `meter.ts` is write-only; counters are product, phases are hints |
|
|
21
21
|
|
|
22
|
-
## Architecture laws (
|
|
22
|
+
## Architecture laws (14)
|
|
23
23
|
|
|
24
|
-
| Law | File | Summary
|
|
25
|
-
| --- | ------------------------------------------- |
|
|
26
|
-
| 1 | `docs/architecture/determinism.md` | No `Math.random`/`Date.now` in behaviour; seed-derived randomness; corpus-determined tie-breaks
|
|
27
|
-
| 2 | `docs/architecture/thresholds.md` | Every decision cutoff derived in `geometry.ts` over D/W/N; no tunable knobs
|
|
28
|
-
| 3 | `docs/architecture/exact-vs-approximate.md` | Vector scores rank only; identity via content-addressed lookup; five graded ladders
|
|
29
|
-
| 4 | `docs/architecture/cost-model.md` | Single ladder `MICRO`/`STEP`/`CONCEPT`/`PASS`; weight `moves + PASS·unaccounted`; `STEP`-grade compare
|
|
30
|
-
| 5 | `docs/architecture/match-project.md` | Shared `match.ts` family (`locate`/`alignGraded`/`frameSlots`/`project`); voicing gates belong to consumers
|
|
31
|
-
| 6 | `docs/architecture/mechanism-market.md` | `PipelineMechanism` (`floor`/`run`/`parse`); admissible-floor pruning and investment discipline
|
|
32
|
-
| 7 | `docs/architecture/commonality.md` |
|
|
33
|
-
| 8 | `docs/architecture/bounded-reads.md` | No per-query read grows with N; `hubBound=√N` enforced at store via LIMIT/probe/prefix caps
|
|
34
|
-
| 9 | `docs/architecture/store.md` | `AbstractStore` owns dedup/indexing/batch; `store-sqlite.ts` is thin wrappers; canon index optional
|
|
35
|
-
| 10 | `docs/architecture/fold-contract.md` | `perceiveDeposit` and `perceive` agree; `contentLevels` is single boundary rule; no W/offset dependence
|
|
36
|
-
| 11 | `docs/architecture/memoization.md` | `Precomputed` is per-response lazy cache (promise-cached async); `beginResponse`/`endResponse` lifecycle
|
|
37
|
-
| 12 | `docs/architecture/saturation.md` | Every walk names a deciding saturation beside its cap; cap is safety net, not decision
|
|
38
|
-
| 13 | `docs/architecture/meter.md` | `meter.ts` is write-only work accounting; counts are
|
|
24
|
+
| Law | File | Summary | Pins |
|
|
25
|
+
| --- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
26
|
+
| 1 | `docs/architecture/determinism.md` | No `Math.random`/`Date.now` in behaviour; seed-derived randomness; corpus-determined tie-breaks | `test/20` |
|
|
27
|
+
| 2 | `docs/architecture/thresholds.md` | Every decision cutoff derived in `geometry.ts` over D/W/N; no tunable knobs | `test/40`, `test/64` |
|
|
28
|
+
| 3 | `docs/architecture/exact-vs-approximate.md` | Vector scores rank only; identity via content-addressed lookup; five graded ladders | `test/51` |
|
|
29
|
+
| 4 | `docs/architecture/cost-model.md` | Single ladder `MICRO`/`STEP`/`CONCEPT`/`PASS`; weight `moves + PASS·unaccounted`; `STEP`-grade compare | `test/04`, `test/55` |
|
|
30
|
+
| 5 | `docs/architecture/match-project.md` | Shared `match.ts` family (`locate`/`alignGraded`/`frameSlots`/`project`); voicing gates belong to consumers | `test/24`, `test/76` |
|
|
31
|
+
| 6 | `docs/architecture/mechanism-market.md` | `PipelineMechanism` (`floor`/`run`/`parse`); admissible-floor pruning and investment discipline | `test/01`, `test/04` |
|
|
32
|
+
| 7 | `docs/architecture/commonality.md` | Three: global (`reachOf`+`dominates`), weave-local (`depth[]`), window rarity | `test/17`, `test/34` |
|
|
33
|
+
| 8 | `docs/architecture/bounded-reads.md` | No per-query read grows with N; `hubBound=√N` enforced at store via LIMIT/probe/prefix caps | `test/77`, `test/90` |
|
|
34
|
+
| 9 | `docs/architecture/store.md` | `AbstractStore` owns dedup/indexing/batch; `store-sqlite.ts` is thin wrappers; canon index optional | `test/08` |
|
|
35
|
+
| 10 | `docs/architecture/fold-contract.md` | `perceiveDeposit` and `perceive` agree; `contentLevels` is single boundary rule; no W/offset dependence | `test/59`, `test/63` |
|
|
36
|
+
| 11 | `docs/architecture/memoization.md` | `Precomputed` is per-response lazy cache (promise-cached async); `beginResponse`/`endResponse` lifecycle | `test/42` |
|
|
37
|
+
| 12 | `docs/architecture/saturation.md` | Every walk names a deciding saturation beside its cap; cap is safety net, not decision | `test/27`, `test/16` |
|
|
38
|
+
| 13 | `docs/architecture/meter.md` | `meter.ts` is write-only work accounting; counts are exact, phases nest | `test/55` |
|
|
39
|
+
| 14 | `docs/architecture/closure.md` | A derivation is closed when its structure accounts for the question's remainder; every transition asks that law | `test/133`–`140` |
|
|
39
40
|
|
|
40
41
|
## Mechanisms (8)
|
|
41
42
|
|
|
@@ -63,9 +64,7 @@ proof in `test/` (pins that fail when the law is broken).
|
|
|
63
64
|
- `docs/INVARIANTS.md` — the five invariants (determinism, derived thresholds,
|
|
64
65
|
exact-decides, one cost currency, bounded reads) with file-level routing.
|
|
65
66
|
- `docs/failures/tempting-but-wrong.md` — refuted simplifications that passed
|
|
66
|
-
review but failed pins
|
|
67
|
-
asymmetries, one-cone-exhausted stop).
|
|
67
|
+
review but failed pins.
|
|
68
68
|
- `docs/harness/gates.md` — how `AGENTS.md` recipes,
|
|
69
69
|
`bench/profile-inference.mjs`, and `test/*.test.mjs` enforce the laws.
|
|
70
|
-
- `docs/architecture/` —
|
|
71
|
-
is this way; no separate HOW).
|
|
70
|
+
- `docs/architecture/` — per-law derivation: each file says why, not how.
|