@hviana/sema 0.7.1 → 0.7.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.
- package/HOW_IT_WORKS.md +17 -16
- package/dist/src/meter.d.ts +13 -0
- package/dist/src/meter.js +27 -0
- package/dist/src/mind/junction.js +13 -1
- package/dist/src/mind/mechanisms/prefix-completion.d.ts +2 -1
- package/dist/src/mind/mechanisms/prefix-completion.js +37 -19
- package/dist/src/mind/pipeline.d.ts +3 -2
- package/dist/src/mind/pipeline.js +58 -40
- package/dist/src/mind/recognition.d.ts +16 -7
- package/dist/src/mind/recognition.js +21 -12
- package/dist/src/mind/resonance.js +14 -7
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/meter.ts +26 -0
- package/src/mind/junction.ts +12 -1
- package/src/mind/mechanisms/prefix-completion.ts +37 -19
- package/src/mind/pipeline.ts +68 -51
- package/src/mind/recognition.ts +20 -16
- package/src/mind/resonance.ts +13 -7
package/HOW_IT_WORKS.md
CHANGED
|
@@ -4434,16 +4434,19 @@ before the conversion. Derived from the existing bars; never tuned.
|
|
|
4434
4434
|
### 21.5 The refusal path — the substitution bridge, before silence
|
|
4435
4435
|
|
|
4436
4436
|
Everything geometric has now failed. One tier remains, making a **structural**
|
|
4437
|
-
claim about the query that resonance cannot state.
|
|
4438
|
-
**
|
|
4439
|
-
|
|
4440
|
-
threshold. When the query gist has no concept-level match to anything stored, an
|
|
4441
|
-
exhaustive scan would only score more vectors below the bar (profiled at 38–40K
|
|
4442
|
-
vectors scored per refusing query on a 325K-context store, costing 44% of
|
|
4443
|
-
think). Whether the gist ranks _anything_ at concept level is the discriminator
|
|
4444
|
-
— corpus size never was. The list is shared response-wide, so whichever
|
|
4437
|
+
claim about the query that resonance cannot state. Its proposal source is the
|
|
4438
|
+
response's **one top-k read** (`Precomputed.resonance`, §14.5) — the same ranked
|
|
4439
|
+
list recall's earlier tiers already consulted, shared response-wide so whichever
|
|
4445
4440
|
mechanism first-touches it pays once and every later reader is free.
|
|
4446
4441
|
|
|
4442
|
+
It used to be a **wide** list, widened to an exhaustive index scan whenever the
|
|
4443
|
+
top hit cleared the concept threshold. That was removed: the bridge's own
|
|
4444
|
+
candidate cap is `2 · recallQueryK`, so the top-k already IS everything it can
|
|
4445
|
+
consume, and every proposal is byte-verified downstream (§4.3) — an exhaustive
|
|
4446
|
+
scan bought an O(k) need at O(index) cost (profiled: 244K vectors scored per
|
|
4447
|
+
refusing query, ~1.5 s, every answer byte-identical to the top-k read). Test/95
|
|
4448
|
+
pins its absence.
|
|
4449
|
+
|
|
4447
4450
|
#### The substitution bridge
|
|
4448
4451
|
|
|
4449
4452
|
**The gap.** A query phrased through a near-synonym of a trained word ("Name the
|
|
@@ -5288,16 +5291,14 @@ recallByResonance(query, pre):
|
|
|
5288
5291
|
return { bytes: g, accounted: nothing, moves: STEP }
|
|
5289
5292
|
|
|
5290
5293
|
# ── the REFUSAL PATH ─────────────────────────────────────────────
|
|
5291
|
-
# pre.
|
|
5292
|
-
#
|
|
5293
|
-
#
|
|
5294
|
-
#
|
|
5295
|
-
# : hits # the gist ranks nothing at concept
|
|
5296
|
-
# # level, so a wider scan says nothing
|
|
5294
|
+
# pre.resonance() — the response's ONE top-k read, already paid for by
|
|
5295
|
+
# the tiers above. The bridge caps its own candidates at 2·recallQueryK,
|
|
5296
|
+
# so the top-k is exactly the budget it can consume; there is no wider
|
|
5297
|
+
# list, and every proposal is byte-verified below.
|
|
5297
5298
|
|
|
5298
5299
|
# 3b. substitution / identity bridge
|
|
5299
|
-
bridged ≔ substitutionBridge(query, pre.
|
|
5300
|
-
# anchors: rarest query windows → edgeAncestors, plus
|
|
5300
|
+
bridged ≔ substitutionBridge(query, ids(pre.resonance))
|
|
5301
|
+
# anchors: rarest query windows → edgeAncestors, plus those ids
|
|
5301
5302
|
# align byte-for-byte; a mismatch substitutes only under
|
|
5302
5303
|
# CORROBORATION ∧ GRADED IDENTITY ∧ RAW BALANCE
|
|
5303
5304
|
# accept when matched+substituted DOMINATES the query, every
|
package/dist/src/meter.d.ts
CHANGED
|
@@ -129,6 +129,13 @@ export declare class Meter {
|
|
|
129
129
|
/** Nodes popped by those ascents, against their √N·W budget — the counter
|
|
130
130
|
* that shows whether the walks are deciding early or burning the budget. */
|
|
131
131
|
junctionPops: number;
|
|
132
|
+
/** Ascents that ended by EXHAUSTING the expansion budget rather than by
|
|
133
|
+
* deciding — the walk abstained and the caller silently fell through to a
|
|
134
|
+
* lower tier of the ladder (§2.13: a degradation nothing else reports).
|
|
135
|
+
* It rises the moment a SHARED budget is drained by an earlier walk, which
|
|
136
|
+
* is what makes "this tier answered nothing" distinguishable from "this
|
|
137
|
+
* tier never got to look". */
|
|
138
|
+
junctionBudgetExhausted: number;
|
|
132
139
|
/** Arbitrary byte spans whose distributional company was VSA-bundled from
|
|
133
140
|
* existing episode halos. */
|
|
134
141
|
spanHalos: number;
|
|
@@ -156,6 +163,12 @@ export declare class Meter {
|
|
|
156
163
|
/** Charge `ms`, one call, and a counter delta to a named phase.
|
|
157
164
|
* Insertion-ordered, so a report reads in execution order. */
|
|
158
165
|
charge(phase: string, ms: number, delta?: Record<string, number>): void;
|
|
166
|
+
/** Time one SYNCHRONOUS phase. The sync/async seam (§2.10) is a real
|
|
167
|
+
* contract — perception, recognition and the graph search are synchronous —
|
|
168
|
+
* so a synchronous layer must not be wrapped in `time`'s promise just to be
|
|
169
|
+
* measured: that would make the profiled path await where the unprofiled
|
|
170
|
+
* one does not, and a meter never changes what a layer computes. */
|
|
171
|
+
timeSync<T>(phase: string, fn: () => T): T;
|
|
159
172
|
/** Time one async phase and attribute the work done inside it. Returns
|
|
160
173
|
* the awaited value untouched — a meter never changes what a layer
|
|
161
174
|
* computes, only what is known about it. */
|
package/dist/src/meter.js
CHANGED
|
@@ -122,6 +122,13 @@ export class Meter {
|
|
|
122
122
|
/** Nodes popped by those ascents, against their √N·W budget — the counter
|
|
123
123
|
* that shows whether the walks are deciding early or burning the budget. */
|
|
124
124
|
junctionPops = 0;
|
|
125
|
+
/** Ascents that ended by EXHAUSTING the expansion budget rather than by
|
|
126
|
+
* deciding — the walk abstained and the caller silently fell through to a
|
|
127
|
+
* lower tier of the ladder (§2.13: a degradation nothing else reports).
|
|
128
|
+
* It rises the moment a SHARED budget is drained by an earlier walk, which
|
|
129
|
+
* is what makes "this tier answered nothing" distinguishable from "this
|
|
130
|
+
* tier never got to look". */
|
|
131
|
+
junctionBudgetExhausted = 0;
|
|
125
132
|
/** Arbitrary byte spans whose distributional company was VSA-bundled from
|
|
126
133
|
* existing episode halos. */
|
|
127
134
|
spanHalos = 0;
|
|
@@ -173,6 +180,26 @@ export class Meter {
|
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
182
|
}
|
|
183
|
+
/** Time one SYNCHRONOUS phase. The sync/async seam (§2.10) is a real
|
|
184
|
+
* contract — perception, recognition and the graph search are synchronous —
|
|
185
|
+
* so a synchronous layer must not be wrapped in `time`'s promise just to be
|
|
186
|
+
* measured: that would make the profiled path await where the unprofiled
|
|
187
|
+
* one does not, and a meter never changes what a layer computes. */
|
|
188
|
+
timeSync(phase, fn) {
|
|
189
|
+
const before = this.snapshot();
|
|
190
|
+
const t = performance.now();
|
|
191
|
+
try {
|
|
192
|
+
return fn();
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
const ms = performance.now() - t;
|
|
196
|
+
const after = this.snapshot();
|
|
197
|
+
const delta = {};
|
|
198
|
+
for (const k of Object.keys(after))
|
|
199
|
+
delta[k] = after[k] - before[k];
|
|
200
|
+
this.charge(phase, ms, delta);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
176
203
|
/** Time one async phase and attribute the work done inside it. Returns
|
|
177
204
|
* the awaited value untouched — a meter never changes what a layer
|
|
178
205
|
* computes, only what is known about it. */
|
|
@@ -185,7 +185,19 @@ unordered = false) {
|
|
|
185
185
|
id,
|
|
186
186
|
d: 0,
|
|
187
187
|
}));
|
|
188
|
-
while (stack.length > 0 && out.length < bound
|
|
188
|
+
while (stack.length > 0 && out.length < bound) {
|
|
189
|
+
// BUDGET EXHAUSTION IS AN ABSTENTION, AND IT MUST BE VISIBLE (§2.13). The
|
|
190
|
+
// walk stops with work still on the stack, the caller reads "no container"
|
|
191
|
+
// and falls through to a lower ladder rung — indistinguishable, from the
|
|
192
|
+
// outside, from a walk that looked everywhere and found nothing. With a
|
|
193
|
+
// SHARED budget (cross-region's one k·W allowance per tier) an EARLIER
|
|
194
|
+
// pair can drain it, so a later pair's exact tier may never run at all;
|
|
195
|
+
// this counter is the only thing that says so.
|
|
196
|
+
if (b.n-- <= 0) {
|
|
197
|
+
if (ctx.meter)
|
|
198
|
+
ctx.meter.junctionBudgetExhausted++;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
189
201
|
const { id: x, d } = stack.pop();
|
|
190
202
|
if (ctx.meter)
|
|
191
203
|
ctx.meter.junctionPops++;
|
|
@@ -16,7 +16,8 @@ export interface PrefixCompletion {
|
|
|
16
16
|
* it, when the continuation is sub-quantum, when a candidate's continuation
|
|
17
17
|
* cannot be read through, or when the candidates disagree.
|
|
18
18
|
*
|
|
19
|
-
* `ranked` must be a list the caller has ALREADY fetched
|
|
19
|
+
* `ranked` must be a list the caller has ALREADY fetched (the write side's
|
|
20
|
+
* window index, or the response's memoised top-k); this mechanism never
|
|
20
21
|
* resonates on its own (see the header's cost note). */
|
|
21
22
|
export declare function prefixCompletion(ctx: MindContext, query: Uint8Array, ranked: ReadonlyArray<number>): PrefixCompletion | null;
|
|
22
23
|
export declare const prefixMechanism: PipelineMechanism;
|
|
@@ -45,15 +45,23 @@
|
|
|
45
45
|
// from `resonate(k)` at k = 24, 256 AND 2048 — while forms scoring LOWER
|
|
46
46
|
// (Germany 0.5670, Yemen 0.5591) are returned. `k` only reorders WITHIN
|
|
47
47
|
// the IVF clusters already probed, exactly as Store.resonate's doc warns,
|
|
48
|
-
// so no k recovers it.
|
|
48
|
+
// so no k recovers it.
|
|
49
49
|
//
|
|
50
|
-
// So this is a RETRIEVABILITY gap, not a semantic one, and
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
50
|
+
// So this is a RETRIEVABILITY gap, not a semantic one, and the ANN is the wrong
|
|
51
|
+
// instrument for it: a proper prefix's gist cannot rank its own continuation.
|
|
52
|
+
// The repair is CONTENT-ADDRESSED (§2.3) — `formsOpenedBy` (traverse.ts) reads
|
|
53
|
+
// the leaf-id WINDOW index the write side already maintains and answers "which
|
|
54
|
+
// trained forms does this byte run open?" in a bounded √N walk. That is this
|
|
55
|
+
// mechanism's first supply. The response's memoised top-k `resonance()` is the
|
|
56
|
+
// second, for prefixes long enough that the gist still ranks the form; it is
|
|
57
|
+
// read, never re-issued.
|
|
58
|
+
//
|
|
59
|
+
// AN EXHAUSTIVE ANN LIST IS NOT A SUPPLY HERE, AND WAS REMOVED. This tier once
|
|
60
|
+
// read `Precomputed.wideResonance()` — a full-index `resonate(guide, √N,
|
|
61
|
+
// exhaustive)` — on the argument that the target "ranks 8 with `exhaustive`".
|
|
62
|
+
// It bought an O(k) need at O(index) cost (measured: 244K annVectorReads per
|
|
63
|
+
// refusing query, ~1.5 s) for candidates the window index proposes directly.
|
|
64
|
+
// See pipeline-mechanism.ts's REMOVED note; test/95 pins its absence.
|
|
57
65
|
//
|
|
58
66
|
// THREE GUARDS, each falsified into existence by measurement — do not drop any:
|
|
59
67
|
//
|
|
@@ -97,7 +105,8 @@ import { STEP } from "../graph-search.js";
|
|
|
97
105
|
* it, when the continuation is sub-quantum, when a candidate's continuation
|
|
98
106
|
* cannot be read through, or when the candidates disagree.
|
|
99
107
|
*
|
|
100
|
-
* `ranked` must be a list the caller has ALREADY fetched
|
|
108
|
+
* `ranked` must be a list the caller has ALREADY fetched (the write side's
|
|
109
|
+
* window index, or the response's memoised top-k); this mechanism never
|
|
101
110
|
* resonates on its own (see the header's cost note). */
|
|
102
111
|
export function prefixCompletion(ctx, query, ranked) {
|
|
103
112
|
const W = ctx.space.maxGroup;
|
|
@@ -218,16 +227,25 @@ export const prefixMechanism = {
|
|
|
218
227
|
return STEP;
|
|
219
228
|
},
|
|
220
229
|
async run(ctx, query, pre) {
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
// ONE SUPPLY PASS, not a two-tier `??`. The window index (exact,
|
|
231
|
+
// content-addressed) and the response's memoised top-k (approximate) are
|
|
232
|
+
// concatenated and the three guards decide ONCE over the union. A
|
|
233
|
+
// first-then-fallback chain would let the APPROXIMATE tier override the
|
|
234
|
+
// EXACT one (§2.3): when formsOpenedBy finds two continuations, guard 3
|
|
235
|
+
// returns null and the fallback re-runs the guards on resonance's top-k
|
|
236
|
+
// alone — which, seeing only one of the two forms, would voice it. That is
|
|
237
|
+
// precisely the disagreement-suppression guard 3 exists to prevent, and it
|
|
238
|
+
// is the exact tier's ambiguity being washed away by the approximate tier.
|
|
239
|
+
// Evaluating the union means a disagreement the window index saw can never
|
|
240
|
+
// be hidden by what the ANN happens to rank. The ANN read is the
|
|
241
|
+
// response's ONE memoised top-k (§2.11), already paid by recall's refusal
|
|
242
|
+
// path on the queries where this mechanism fires, so reading it here is not
|
|
243
|
+
// a second index scan.
|
|
244
|
+
const ids = [
|
|
245
|
+
...formsOpenedBy(ctx, query),
|
|
246
|
+
...(await pre.resonance()).map((h) => h.id),
|
|
247
|
+
];
|
|
248
|
+
const completed = prefixCompletion(ctx, query, ids);
|
|
231
249
|
if (completed === null)
|
|
232
250
|
return [];
|
|
233
251
|
return [{
|
|
@@ -52,8 +52,9 @@ export interface RegimePredictionData {
|
|
|
52
52
|
/** retrieval | composition — the two regimes R1 measured as a ~100× cost
|
|
53
53
|
* step. */
|
|
54
54
|
regime: "retrieval" | "composition";
|
|
55
|
-
/** The incumbent's grade
|
|
56
|
-
* it
|
|
55
|
+
/** The incumbent's grade once the first mechanism's turn is over (it ran, or
|
|
56
|
+
* it was skipped), or null when nothing has grounded — `best === null`,
|
|
57
|
+
* which is composition with no incumbent. */
|
|
57
58
|
incumbentGrade: number | null;
|
|
58
59
|
/** The cheapest composition floor in grade units (`grade(2 * STEP)` = 2,
|
|
59
60
|
* CAST's floor) — the bar the incumbent must sit at or below for the
|
|
@@ -97,8 +97,11 @@ export async function think(ctx, query, mechs) {
|
|
|
97
97
|
// own store work (perceive → foldTree → resolve), which used to land in
|
|
98
98
|
// `think` and in nothing narrower — the meter's one accounting surface must
|
|
99
99
|
// charge it to itself, exactly as attention/weave/resonance are charged.
|
|
100
|
+
// SYNCHRONOUS phase: recognition is on the sync side of §2.10's seam, so it
|
|
101
|
+
// is timed with `timeSync` — wrapping it in a promise would make a profiled
|
|
102
|
+
// response await where an unprofiled one does not.
|
|
100
103
|
const rec = meter
|
|
101
|
-
?
|
|
104
|
+
? meter.timeSync("recognise", () => recognise(ctx, query))
|
|
102
105
|
: recognise(ctx, query);
|
|
103
106
|
// Phase 1: collect computed spans from mechanisms that implement parse()
|
|
104
107
|
const computed = meter
|
|
@@ -163,12 +166,59 @@ export async function think(ctx, query, mechs) {
|
|
|
163
166
|
best = c;
|
|
164
167
|
};
|
|
165
168
|
const worthRunning = (floor) => best === null || grade(floor) < grade(best.weight);
|
|
169
|
+
// REGIME PREDICTION (R8) — observational only. Once the FIRST mechanism has
|
|
170
|
+
// had its turn (cover, which §2.6 places first and floors at 0), the market's
|
|
171
|
+
// outcome is already determined by the one cost ladder: the consensus climb
|
|
172
|
+
// runs exactly when `worthRunning(2 * STEP)` is true — CAST (floor 2·STEP) is
|
|
173
|
+
// the cheapest mechanism that first-touches it, so an incumbent at or below
|
|
174
|
+
// grade 2 prunes CAST and, with it, confluence (3·STEP) and extraction
|
|
175
|
+
// (CONCEPT+STEP) (retrieval); anything above — or no incumbent — runs the
|
|
176
|
+
// full market and the climb (composition). The predicate is `worthRunning`,
|
|
177
|
+
// the same function the loop itself uses — nothing is computed here that the
|
|
178
|
+
// engine had not already computed, and nothing is read back by inference.
|
|
179
|
+
//
|
|
180
|
+
// EMITTED BEFORE THE SECOND MECHANISM'S FLOOR, never after some mechanism's
|
|
181
|
+
// run: a "prediction" published after the fact could assert "the climb will
|
|
182
|
+
// not run" about a climb that already ran — which is what happens whenever
|
|
183
|
+
// the first mechanism is SKIPPED (null floor or pruned) and the block sits at
|
|
184
|
+
// the end of the first mechanism that actually ran. Emitting on entry to
|
|
185
|
+
// iteration 1 makes the claim true by construction, whatever the first
|
|
186
|
+
// mechanism did, and keeps the payload identical on the ordinary path (the
|
|
187
|
+
// incumbent cannot change between the two positions).
|
|
188
|
+
let regimeReported = false;
|
|
189
|
+
const reportRegime = () => {
|
|
190
|
+
if (regimeReported)
|
|
191
|
+
return;
|
|
192
|
+
regimeReported = true;
|
|
193
|
+
const climbFloorGrade = grade(2 * STEP);
|
|
194
|
+
// TS narrows `best` to null in the outer flow (it cannot see the closure
|
|
195
|
+
// assignments in `consider`) — cast back, the same read-back as `decided`
|
|
196
|
+
// below.
|
|
197
|
+
const incumbent = best;
|
|
198
|
+
const incumbentGrade = incumbent === null ? null : grade(incumbent.weight);
|
|
199
|
+
const regime = worthRunning(2 * STEP)
|
|
200
|
+
? "composition"
|
|
201
|
+
: "retrieval";
|
|
202
|
+
ctx.trace?.step("regimePrediction", [rItem(query, "query")], [], regime === "retrieval"
|
|
203
|
+
? `retrieval regime — incumbent grade ${incumbentGrade} ≤ climb floor ${climbFloorGrade}, ` +
|
|
204
|
+
`so no mechanism floored above that grade runs; the consensus climb will not run`
|
|
205
|
+
: `composition regime — ${incumbentGrade === null
|
|
206
|
+
? "no incumbent (nothing grounded)"
|
|
207
|
+
: `incumbent grade ${incumbentGrade}`} above climb floor ${climbFloorGrade}, so the full market and climb run`, undefined, {
|
|
208
|
+
version: 1,
|
|
209
|
+
regime,
|
|
210
|
+
incumbentGrade,
|
|
211
|
+
climbFloorGrade,
|
|
212
|
+
});
|
|
213
|
+
};
|
|
166
214
|
// Phase 3: grounding loop
|
|
167
215
|
// Per-mechanism accounting (src/meter.ts). The market's whole premise is
|
|
168
216
|
// that mechanisms compete on one cost scale — so the profiling read-out is
|
|
169
217
|
// also per-mechanism, uniformly: the loop never asks which one it holds.
|
|
170
|
-
let
|
|
171
|
-
|
|
218
|
+
for (let mi = 0; mi < mechanisms.length; mi++) {
|
|
219
|
+
const mech = mechanisms[mi];
|
|
220
|
+
if (mi > 0)
|
|
221
|
+
reportRegime();
|
|
172
222
|
const floor = meter
|
|
173
223
|
? await meter.time(`${mech.name}.floor`, () => mech.floor(ctx, query, pre, worthRunning))
|
|
174
224
|
: await mech.floor(ctx, query, pre, worthRunning);
|
|
@@ -204,43 +254,11 @@ export async function think(ctx, query, mechs) {
|
|
|
204
254
|
scaffolding: r.scaffolding,
|
|
205
255
|
});
|
|
206
256
|
}
|
|
207
|
-
// REGIME PREDICTION (R8) — observational only. After the FIRST mechanism
|
|
208
|
-
// runs (cover, which §2.6 places first and floors at 0), the market's
|
|
209
|
-
// outcome is already determined: the consensus climb runs exactly when
|
|
210
|
-
// `worthRunning(2 * STEP)` is true — CAST (floor 2·STEP) is the cheapest
|
|
211
|
-
// mechanism that first-touches it, so an incumbent at or below grade 2
|
|
212
|
-
// prunes CAST and, with it, confluence (3·STEP) and extraction
|
|
213
|
-
// (CONCEPT+STEP) (retrieval); anything above — or no incumbent — runs the
|
|
214
|
-
// full market and the climb (composition). The predicate is
|
|
215
|
-
// `worthRunning`, the same function the loop just used — nothing is
|
|
216
|
-
// computed here that the engine had not already computed, and nothing is
|
|
217
|
-
// read back by inference.
|
|
218
|
-
if (!regimeReported) {
|
|
219
|
-
regimeReported = true;
|
|
220
|
-
const climbFloorGrade = grade(2 * STEP);
|
|
221
|
-
// TS narrows `best` to null in the outer flow (it cannot see the closure
|
|
222
|
-
// assignments in `consider`) — cast back, the same read-back as `decided`
|
|
223
|
-
// below.
|
|
224
|
-
const incumbent = best;
|
|
225
|
-
const incumbentGrade = incumbent === null
|
|
226
|
-
? null
|
|
227
|
-
: grade(incumbent.weight);
|
|
228
|
-
const regime = worthRunning(2 * STEP)
|
|
229
|
-
? "composition"
|
|
230
|
-
: "retrieval";
|
|
231
|
-
ctx.trace?.step("regimePrediction", [rItem(query, "query")], [], regime === "retrieval"
|
|
232
|
-
? `retrieval regime — incumbent grade ${incumbentGrade} ≤ climb floor ${climbFloorGrade}, so no composition mechanism runs; ` +
|
|
233
|
-
`the consensus climb will not run`
|
|
234
|
-
: `composition regime — ${incumbentGrade === null
|
|
235
|
-
? "no incumbent (nothing grounded)"
|
|
236
|
-
: `incumbent grade ${incumbentGrade}`} above climb floor ${climbFloorGrade}, so the full market and climb run`, undefined, {
|
|
237
|
-
version: 1,
|
|
238
|
-
regime,
|
|
239
|
-
incumbentGrade,
|
|
240
|
-
climbFloorGrade,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
257
|
}
|
|
258
|
+
// A market of ONE mechanism never reaches iteration 1; the step is still
|
|
259
|
+
// emitted exactly once per think(), so a consumer never has to ask whether
|
|
260
|
+
// the list was long enough for the prediction to exist.
|
|
261
|
+
reportRegime();
|
|
244
262
|
// (TS cannot see the closure assignments into `best` and narrows it to its
|
|
245
263
|
// initial null, so the read-back needs the assertion.)
|
|
246
264
|
const decided = best;
|
|
@@ -385,7 +403,7 @@ export async function think(ctx, query, mechs) {
|
|
|
385
403
|
? reasoned
|
|
386
404
|
: meter
|
|
387
405
|
? await meter.time("fuse", () => fuseAttention(ctx, query, reasoned, pre, unclimbed, primarySpans))
|
|
388
|
-
: await fuseAttention(ctx, query, reasoned, pre, unclimbed,
|
|
406
|
+
: await fuseAttention(ctx, query, reasoned, pre, unclimbed, primarySpans);
|
|
389
407
|
done(fused, "grounded, reasoned forward, fused across points of attention");
|
|
390
408
|
return { bytes: fused, provenance };
|
|
391
409
|
}
|
|
@@ -10,13 +10,22 @@ import type { MindContext, Recognition, Segment } from "./types.js";
|
|
|
10
10
|
* the longest known leaf, chained into flat branches. Names forms the
|
|
11
11
|
* query's own cut cannot, and records sub-leaf boundaries as `splits`.
|
|
12
12
|
*
|
|
13
|
-
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
13
|
+
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
14
|
+
*
|
|
15
|
+
* ONE READING PER BYTE STREAM, deliberately: there is no "cheap mode" that
|
|
16
|
+
* skips the edge-trim fallbacks. A `trimmed` variant was tried and REFUTED
|
|
17
|
+
* twice over. Its premise — "the trims only recover misaligned FRAGMENTS, so
|
|
18
|
+
* a consumer whose gate rejects fragments loses nothing" — is false: the
|
|
19
|
+
* left/right trim loops below exist precisely to find WHOLE trained forms
|
|
20
|
+
* embedded at an offset the query's own fold did not cut, and such a form has
|
|
21
|
+
* no structural parents or containers, so it passes the pivot's fragment gate
|
|
22
|
+
* and is exactly the candidate a multi-hop chain steps through. Skipping them
|
|
23
|
+
* narrows the pivot's evidence silently. And a per-caller variant has to key
|
|
24
|
+
* the memo by the variant, which breaks the "computed at most once" property
|
|
25
|
+
* (§2.11): the pipeline recognises a grounded answer untrimmed for
|
|
26
|
+
* `preConsumed`, and the pivot then recognises the same bytes again — the
|
|
27
|
+
* saving inverts into a doubling on the path it was measured for. */
|
|
28
|
+
export declare function recognise(ctx: MindContext, bytes: Uint8Array): Recognition;
|
|
20
29
|
/** Segment bytes using the geometry's own groupings — leaf-parent
|
|
21
30
|
* nodes from the perceived tree, with consecutive bare leaves merged
|
|
22
31
|
* into one segment. Each segment's gist is perceived from its bytes
|
|
@@ -21,13 +21,22 @@ import { isChunk } from "../sema.js";
|
|
|
21
21
|
* the longest known leaf, chained into flat branches. Names forms the
|
|
22
22
|
* query's own cut cannot, and records sub-leaf boundaries as `splits`.
|
|
23
23
|
*
|
|
24
|
-
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
24
|
+
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
25
|
+
*
|
|
26
|
+
* ONE READING PER BYTE STREAM, deliberately: there is no "cheap mode" that
|
|
27
|
+
* skips the edge-trim fallbacks. A `trimmed` variant was tried and REFUTED
|
|
28
|
+
* twice over. Its premise — "the trims only recover misaligned FRAGMENTS, so
|
|
29
|
+
* a consumer whose gate rejects fragments loses nothing" — is false: the
|
|
30
|
+
* left/right trim loops below exist precisely to find WHOLE trained forms
|
|
31
|
+
* embedded at an offset the query's own fold did not cut, and such a form has
|
|
32
|
+
* no structural parents or containers, so it passes the pivot's fragment gate
|
|
33
|
+
* and is exactly the candidate a multi-hop chain steps through. Skipping them
|
|
34
|
+
* narrows the pivot's evidence silently. And a per-caller variant has to key
|
|
35
|
+
* the memo by the variant, which breaks the "computed at most once" property
|
|
36
|
+
* (§2.11): the pipeline recognises a grounded answer untrimmed for
|
|
37
|
+
* `preConsumed`, and the pivot then recognises the same bytes again — the
|
|
38
|
+
* saving inverts into a doubling on the path it was measured for. */
|
|
39
|
+
export function recognise(ctx, bytes) {
|
|
31
40
|
// Content-keyed memo — works for both single-turn respond() and multi-turn
|
|
32
41
|
// respondTurn() (where the map persists across calls). ALWAYS consulted,
|
|
33
42
|
// regardless of tracing — matching perceive()'s own memo, which carries no
|
|
@@ -67,7 +76,7 @@ export function recognise(ctx, bytes, trimmed = false) {
|
|
|
67
76
|
// not silent), so it is emitted here directly rather than only inside
|
|
68
77
|
// recogniseImpl.
|
|
69
78
|
if (ctx.recogniseMemo) {
|
|
70
|
-
const key =
|
|
79
|
+
const key = latin1Key(bytes);
|
|
71
80
|
const hit = ctx.recogniseMemo.get(key);
|
|
72
81
|
if (hit !== undefined) {
|
|
73
82
|
if (ctx.meter)
|
|
@@ -79,13 +88,13 @@ export function recognise(ctx, bytes, trimmed = false) {
|
|
|
79
88
|
`lead somewhere (over ${hit.leaves.length} perceived leaves) [cached]`);
|
|
80
89
|
return hit;
|
|
81
90
|
}
|
|
82
|
-
const fresh = recogniseImpl(ctx, bytes
|
|
91
|
+
const fresh = recogniseImpl(ctx, bytes);
|
|
83
92
|
ctx.recogniseMemo.set(key, fresh);
|
|
84
93
|
return fresh;
|
|
85
94
|
}
|
|
86
|
-
return recogniseImpl(ctx, bytes
|
|
95
|
+
return recogniseImpl(ctx, bytes);
|
|
87
96
|
}
|
|
88
|
-
function recogniseImpl(ctx, bytes
|
|
97
|
+
function recogniseImpl(ctx, bytes) {
|
|
89
98
|
if (ctx.meter) {
|
|
90
99
|
ctx.meter.recognitions++;
|
|
91
100
|
ctx.meter.recognisedBytes += bytes.length;
|
|
@@ -199,7 +208,7 @@ function recogniseImpl(ctx, bytes, trimmed = false) {
|
|
|
199
208
|
// n.kids !== null enforces above) rather than degenerate into
|
|
200
209
|
// single-byte-atom territory, which atomIsHub already governs
|
|
201
210
|
// separately.
|
|
202
|
-
else if (
|
|
211
|
+
else if (end - start - 1 >= 2) {
|
|
203
212
|
// The chunk's own boundary is drawn by content geometry, not by
|
|
204
213
|
// any notion of "form" — it can include one edge byte the query's
|
|
205
214
|
// fold happened to attach here that the trained span never had
|
|
@@ -288,13 +288,13 @@ export async function pivotInto(ctx, answer, consumed, voiced = []) {
|
|
|
288
288
|
for (const c of n.kids)
|
|
289
289
|
queue.push(c); // breadth-first: larger regions first
|
|
290
290
|
}
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
const rec = recognise(ctx, answer
|
|
291
|
+
// THE FULL recognition, memo-shared with every other reader of these bytes.
|
|
292
|
+
// A "skip the edge trims here" variant was refuted (see recognise's own
|
|
293
|
+
// note): those trims are what find a WHOLE trained form embedded at an
|
|
294
|
+
// offset the answer's fold did not cut, and such a form is parentless,
|
|
295
|
+
// container-free and edge-bearing — i.e. exactly what the filter below
|
|
296
|
+
// ADMITS as a pivot, not what it rejects.
|
|
297
|
+
const rec = recognise(ctx, answer);
|
|
298
298
|
for (const s of rec.sites) {
|
|
299
299
|
if (!consumed.has(s.payload) && ctx.store.hasNext(s.payload)) {
|
|
300
300
|
scored.set(s.payload, Math.max(scored.get(s.payload) ?? 0, 1));
|
|
@@ -322,6 +322,13 @@ export async function pivotInto(ctx, answer, consumed, voiced = []) {
|
|
|
322
322
|
let pivotId = null;
|
|
323
323
|
for (const c of ranked) {
|
|
324
324
|
const id = c.id;
|
|
325
|
+
// A ZERO-LENGTH candidate is not a pivot. `argmaxBy(…, 0, strict)` used to
|
|
326
|
+
// carry this floor in its threshold argument, and dropping it here would
|
|
327
|
+
// admit an empty node: `indexOf(answer, <empty>)` returns 0, so every
|
|
328
|
+
// filter below passes and the chain would hop through nothing (§2.13 —
|
|
329
|
+
// empty bytes are truthy).
|
|
330
|
+
if (c.len === 0)
|
|
331
|
+
continue;
|
|
325
332
|
// A PIVOT MUST BE A THING THE CORPUS DEPOSITED, NOT A PIECE OF ONE.
|
|
326
333
|
// "Longest wins" ranks candidates but never asks whether the winner is
|
|
327
334
|
// an entity at all, and by the time a chain reaches here `consumeAll`
|
package/jsr.json
CHANGED
package/package.json
CHANGED
package/src/meter.ts
CHANGED
|
@@ -176,6 +176,13 @@ export class Meter {
|
|
|
176
176
|
/** Nodes popped by those ascents, against their √N·W budget — the counter
|
|
177
177
|
* that shows whether the walks are deciding early or burning the budget. */
|
|
178
178
|
junctionPops = 0;
|
|
179
|
+
/** Ascents that ended by EXHAUSTING the expansion budget rather than by
|
|
180
|
+
* deciding — the walk abstained and the caller silently fell through to a
|
|
181
|
+
* lower tier of the ladder (§2.13: a degradation nothing else reports).
|
|
182
|
+
* It rises the moment a SHARED budget is drained by an earlier walk, which
|
|
183
|
+
* is what makes "this tier answered nothing" distinguishable from "this
|
|
184
|
+
* tier never got to look". */
|
|
185
|
+
junctionBudgetExhausted = 0;
|
|
179
186
|
/** Arbitrary byte spans whose distributional company was VSA-bundled from
|
|
180
187
|
* existing episode halos. */
|
|
181
188
|
spanHalos = 0;
|
|
@@ -231,6 +238,25 @@ export class Meter {
|
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
|
|
241
|
+
/** Time one SYNCHRONOUS phase. The sync/async seam (§2.10) is a real
|
|
242
|
+
* contract — perception, recognition and the graph search are synchronous —
|
|
243
|
+
* so a synchronous layer must not be wrapped in `time`'s promise just to be
|
|
244
|
+
* measured: that would make the profiled path await where the unprofiled
|
|
245
|
+
* one does not, and a meter never changes what a layer computes. */
|
|
246
|
+
timeSync<T>(phase: string, fn: () => T): T {
|
|
247
|
+
const before = this.snapshot();
|
|
248
|
+
const t = performance.now();
|
|
249
|
+
try {
|
|
250
|
+
return fn();
|
|
251
|
+
} finally {
|
|
252
|
+
const ms = performance.now() - t;
|
|
253
|
+
const after = this.snapshot();
|
|
254
|
+
const delta: Record<string, number> = {};
|
|
255
|
+
for (const k of Object.keys(after)) delta[k] = after[k] - before[k];
|
|
256
|
+
this.charge(phase, ms, delta);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
234
260
|
/** Time one async phase and attribute the work done inside it. Returns
|
|
235
261
|
* the awaited value untouched — a meter never changes what a layer
|
|
236
262
|
* computes, only what is known about it. */
|
package/src/mind/junction.ts
CHANGED
|
@@ -264,7 +264,18 @@ export function junctionContainersFrom(
|
|
|
264
264
|
id,
|
|
265
265
|
d: 0,
|
|
266
266
|
}));
|
|
267
|
-
while (stack.length > 0 && out.length < bound
|
|
267
|
+
while (stack.length > 0 && out.length < bound) {
|
|
268
|
+
// BUDGET EXHAUSTION IS AN ABSTENTION, AND IT MUST BE VISIBLE (§2.13). The
|
|
269
|
+
// walk stops with work still on the stack, the caller reads "no container"
|
|
270
|
+
// and falls through to a lower ladder rung — indistinguishable, from the
|
|
271
|
+
// outside, from a walk that looked everywhere and found nothing. With a
|
|
272
|
+
// SHARED budget (cross-region's one k·W allowance per tier) an EARLIER
|
|
273
|
+
// pair can drain it, so a later pair's exact tier may never run at all;
|
|
274
|
+
// this counter is the only thing that says so.
|
|
275
|
+
if (b.n-- <= 0) {
|
|
276
|
+
if (ctx.meter) ctx.meter.junctionBudgetExhausted++;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
268
279
|
const { id: x, d } = stack.pop()!;
|
|
269
280
|
if (ctx.meter) ctx.meter.junctionPops++;
|
|
270
281
|
const f = cachedRead(ctx, cache, x, maxContainer);
|
|
@@ -45,15 +45,23 @@
|
|
|
45
45
|
// from `resonate(k)` at k = 24, 256 AND 2048 — while forms scoring LOWER
|
|
46
46
|
// (Germany 0.5670, Yemen 0.5591) are returned. `k` only reorders WITHIN
|
|
47
47
|
// the IVF clusters already probed, exactly as Store.resonate's doc warns,
|
|
48
|
-
// so no k recovers it.
|
|
48
|
+
// so no k recovers it.
|
|
49
49
|
//
|
|
50
|
-
// So this is a RETRIEVABILITY gap, not a semantic one, and
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
50
|
+
// So this is a RETRIEVABILITY gap, not a semantic one, and the ANN is the wrong
|
|
51
|
+
// instrument for it: a proper prefix's gist cannot rank its own continuation.
|
|
52
|
+
// The repair is CONTENT-ADDRESSED (§2.3) — `formsOpenedBy` (traverse.ts) reads
|
|
53
|
+
// the leaf-id WINDOW index the write side already maintains and answers "which
|
|
54
|
+
// trained forms does this byte run open?" in a bounded √N walk. That is this
|
|
55
|
+
// mechanism's first supply. The response's memoised top-k `resonance()` is the
|
|
56
|
+
// second, for prefixes long enough that the gist still ranks the form; it is
|
|
57
|
+
// read, never re-issued.
|
|
58
|
+
//
|
|
59
|
+
// AN EXHAUSTIVE ANN LIST IS NOT A SUPPLY HERE, AND WAS REMOVED. This tier once
|
|
60
|
+
// read `Precomputed.wideResonance()` — a full-index `resonate(guide, √N,
|
|
61
|
+
// exhaustive)` — on the argument that the target "ranks 8 with `exhaustive`".
|
|
62
|
+
// It bought an O(k) need at O(index) cost (measured: 244K annVectorReads per
|
|
63
|
+
// refusing query, ~1.5 s) for candidates the window index proposes directly.
|
|
64
|
+
// See pipeline-mechanism.ts's REMOVED note; test/95 pins its absence.
|
|
57
65
|
//
|
|
58
66
|
// THREE GUARDS, each falsified into existence by measurement — do not drop any:
|
|
59
67
|
//
|
|
@@ -114,7 +122,8 @@ export interface PrefixCompletion {
|
|
|
114
122
|
* it, when the continuation is sub-quantum, when a candidate's continuation
|
|
115
123
|
* cannot be read through, or when the candidates disagree.
|
|
116
124
|
*
|
|
117
|
-
* `ranked` must be a list the caller has ALREADY fetched
|
|
125
|
+
* `ranked` must be a list the caller has ALREADY fetched (the write side's
|
|
126
|
+
* window index, or the response's memoised top-k); this mechanism never
|
|
118
127
|
* resonates on its own (see the header's cost note). */
|
|
119
128
|
export function prefixCompletion(
|
|
120
129
|
ctx: MindContext,
|
|
@@ -264,16 +273,25 @@ export const prefixMechanism: PipelineMechanism = {
|
|
|
264
273
|
return STEP;
|
|
265
274
|
},
|
|
266
275
|
async run(ctx, query, pre) {
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
// ONE SUPPLY PASS, not a two-tier `??`. The window index (exact,
|
|
277
|
+
// content-addressed) and the response's memoised top-k (approximate) are
|
|
278
|
+
// concatenated and the three guards decide ONCE over the union. A
|
|
279
|
+
// first-then-fallback chain would let the APPROXIMATE tier override the
|
|
280
|
+
// EXACT one (§2.3): when formsOpenedBy finds two continuations, guard 3
|
|
281
|
+
// returns null and the fallback re-runs the guards on resonance's top-k
|
|
282
|
+
// alone — which, seeing only one of the two forms, would voice it. That is
|
|
283
|
+
// precisely the disagreement-suppression guard 3 exists to prevent, and it
|
|
284
|
+
// is the exact tier's ambiguity being washed away by the approximate tier.
|
|
285
|
+
// Evaluating the union means a disagreement the window index saw can never
|
|
286
|
+
// be hidden by what the ANN happens to rank. The ANN read is the
|
|
287
|
+
// response's ONE memoised top-k (§2.11), already paid by recall's refusal
|
|
288
|
+
// path on the queries where this mechanism fires, so reading it here is not
|
|
289
|
+
// a second index scan.
|
|
290
|
+
const ids = [
|
|
291
|
+
...formsOpenedBy(ctx, query),
|
|
292
|
+
...(await pre.resonance()).map((h) => h.id),
|
|
293
|
+
];
|
|
294
|
+
const completed = prefixCompletion(ctx, query, ids);
|
|
277
295
|
if (completed === null) return [];
|
|
278
296
|
return [{
|
|
279
297
|
bytes: completed.form,
|
package/src/mind/pipeline.ts
CHANGED
|
@@ -144,8 +144,9 @@ export interface RegimePredictionData {
|
|
|
144
144
|
/** retrieval | composition — the two regimes R1 measured as a ~100× cost
|
|
145
145
|
* step. */
|
|
146
146
|
regime: "retrieval" | "composition";
|
|
147
|
-
/** The incumbent's grade
|
|
148
|
-
* it
|
|
147
|
+
/** The incumbent's grade once the first mechanism's turn is over (it ran, or
|
|
148
|
+
* it was skipped), or null when nothing has grounded — `best === null`,
|
|
149
|
+
* which is composition with no incumbent. */
|
|
149
150
|
incumbentGrade: number | null;
|
|
150
151
|
/** The cheapest composition floor in grade units (`grade(2 * STEP)` = 2,
|
|
151
152
|
* CAST's floor) — the bar the incumbent must sit at or below for the
|
|
@@ -190,8 +191,11 @@ export async function think(
|
|
|
190
191
|
// own store work (perceive → foldTree → resolve), which used to land in
|
|
191
192
|
// `think` and in nothing narrower — the meter's one accounting surface must
|
|
192
193
|
// charge it to itself, exactly as attention/weave/resonance are charged.
|
|
194
|
+
// SYNCHRONOUS phase: recognition is on the sync side of §2.10's seam, so it
|
|
195
|
+
// is timed with `timeSync` — wrapping it in a promise would make a profiled
|
|
196
|
+
// response await where an unprofiled one does not.
|
|
193
197
|
const rec = meter
|
|
194
|
-
?
|
|
198
|
+
? meter.timeSync("recognise", () => recognise(ctx, query))
|
|
195
199
|
: recognise(ctx, query);
|
|
196
200
|
|
|
197
201
|
// Phase 1: collect computed spans from mechanisms that implement parse()
|
|
@@ -294,12 +298,66 @@ export async function think(
|
|
|
294
298
|
const worthRunning = (floor: number) =>
|
|
295
299
|
best === null || grade(floor) < grade(best.weight);
|
|
296
300
|
|
|
301
|
+
// REGIME PREDICTION (R8) — observational only. Once the FIRST mechanism has
|
|
302
|
+
// had its turn (cover, which §2.6 places first and floors at 0), the market's
|
|
303
|
+
// outcome is already determined by the one cost ladder: the consensus climb
|
|
304
|
+
// runs exactly when `worthRunning(2 * STEP)` is true — CAST (floor 2·STEP) is
|
|
305
|
+
// the cheapest mechanism that first-touches it, so an incumbent at or below
|
|
306
|
+
// grade 2 prunes CAST and, with it, confluence (3·STEP) and extraction
|
|
307
|
+
// (CONCEPT+STEP) (retrieval); anything above — or no incumbent — runs the
|
|
308
|
+
// full market and the climb (composition). The predicate is `worthRunning`,
|
|
309
|
+
// the same function the loop itself uses — nothing is computed here that the
|
|
310
|
+
// engine had not already computed, and nothing is read back by inference.
|
|
311
|
+
//
|
|
312
|
+
// EMITTED BEFORE THE SECOND MECHANISM'S FLOOR, never after some mechanism's
|
|
313
|
+
// run: a "prediction" published after the fact could assert "the climb will
|
|
314
|
+
// not run" about a climb that already ran — which is what happens whenever
|
|
315
|
+
// the first mechanism is SKIPPED (null floor or pruned) and the block sits at
|
|
316
|
+
// the end of the first mechanism that actually ran. Emitting on entry to
|
|
317
|
+
// iteration 1 makes the claim true by construction, whatever the first
|
|
318
|
+
// mechanism did, and keeps the payload identical on the ordinary path (the
|
|
319
|
+
// incumbent cannot change between the two positions).
|
|
320
|
+
let regimeReported = false;
|
|
321
|
+
const reportRegime = () => {
|
|
322
|
+
if (regimeReported) return;
|
|
323
|
+
regimeReported = true;
|
|
324
|
+
const climbFloorGrade = grade(2 * STEP);
|
|
325
|
+
// TS narrows `best` to null in the outer flow (it cannot see the closure
|
|
326
|
+
// assignments in `consider`) — cast back, the same read-back as `decided`
|
|
327
|
+
// below.
|
|
328
|
+
const incumbent = best as Candidate | null;
|
|
329
|
+
const incumbentGrade = incumbent === null ? null : grade(incumbent.weight);
|
|
330
|
+
const regime: "retrieval" | "composition" = worthRunning(2 * STEP)
|
|
331
|
+
? "composition"
|
|
332
|
+
: "retrieval";
|
|
333
|
+
ctx.trace?.step(
|
|
334
|
+
"regimePrediction",
|
|
335
|
+
[rItem(query, "query")],
|
|
336
|
+
[],
|
|
337
|
+
regime === "retrieval"
|
|
338
|
+
? `retrieval regime — incumbent grade ${incumbentGrade} ≤ climb floor ${climbFloorGrade}, ` +
|
|
339
|
+
`so no mechanism floored above that grade runs; the consensus climb will not run`
|
|
340
|
+
: `composition regime — ${
|
|
341
|
+
incumbentGrade === null
|
|
342
|
+
? "no incumbent (nothing grounded)"
|
|
343
|
+
: `incumbent grade ${incumbentGrade}`
|
|
344
|
+
} above climb floor ${climbFloorGrade}, so the full market and climb run`,
|
|
345
|
+
undefined,
|
|
346
|
+
{
|
|
347
|
+
version: 1,
|
|
348
|
+
regime,
|
|
349
|
+
incumbentGrade,
|
|
350
|
+
climbFloorGrade,
|
|
351
|
+
} satisfies RegimePredictionData,
|
|
352
|
+
);
|
|
353
|
+
};
|
|
297
354
|
// Phase 3: grounding loop
|
|
298
355
|
// Per-mechanism accounting (src/meter.ts). The market's whole premise is
|
|
299
356
|
// that mechanisms compete on one cost scale — so the profiling read-out is
|
|
300
357
|
// also per-mechanism, uniformly: the loop never asks which one it holds.
|
|
301
|
-
let
|
|
302
|
-
|
|
358
|
+
for (let mi = 0; mi < mechanisms.length; mi++) {
|
|
359
|
+
const mech = mechanisms[mi];
|
|
360
|
+
if (mi > 0) reportRegime();
|
|
303
361
|
const floor = meter
|
|
304
362
|
? await meter.time(
|
|
305
363
|
`${mech.name}.floor`,
|
|
@@ -347,52 +405,11 @@ export async function think(
|
|
|
347
405
|
scaffolding: r.scaffolding,
|
|
348
406
|
});
|
|
349
407
|
}
|
|
350
|
-
// REGIME PREDICTION (R8) — observational only. After the FIRST mechanism
|
|
351
|
-
// runs (cover, which §2.6 places first and floors at 0), the market's
|
|
352
|
-
// outcome is already determined: the consensus climb runs exactly when
|
|
353
|
-
// `worthRunning(2 * STEP)` is true — CAST (floor 2·STEP) is the cheapest
|
|
354
|
-
// mechanism that first-touches it, so an incumbent at or below grade 2
|
|
355
|
-
// prunes CAST and, with it, confluence (3·STEP) and extraction
|
|
356
|
-
// (CONCEPT+STEP) (retrieval); anything above — or no incumbent — runs the
|
|
357
|
-
// full market and the climb (composition). The predicate is
|
|
358
|
-
// `worthRunning`, the same function the loop just used — nothing is
|
|
359
|
-
// computed here that the engine had not already computed, and nothing is
|
|
360
|
-
// read back by inference.
|
|
361
|
-
if (!regimeReported) {
|
|
362
|
-
regimeReported = true;
|
|
363
|
-
const climbFloorGrade = grade(2 * STEP);
|
|
364
|
-
// TS narrows `best` to null in the outer flow (it cannot see the closure
|
|
365
|
-
// assignments in `consider`) — cast back, the same read-back as `decided`
|
|
366
|
-
// below.
|
|
367
|
-
const incumbent = best as Candidate | null;
|
|
368
|
-
const incumbentGrade = incumbent === null
|
|
369
|
-
? null
|
|
370
|
-
: grade(incumbent.weight);
|
|
371
|
-
const regime: "retrieval" | "composition" = worthRunning(2 * STEP)
|
|
372
|
-
? "composition"
|
|
373
|
-
: "retrieval";
|
|
374
|
-
ctx.trace?.step(
|
|
375
|
-
"regimePrediction",
|
|
376
|
-
[rItem(query, "query")],
|
|
377
|
-
[],
|
|
378
|
-
regime === "retrieval"
|
|
379
|
-
? `retrieval regime — incumbent grade ${incumbentGrade} ≤ climb floor ${climbFloorGrade}, so no composition mechanism runs; ` +
|
|
380
|
-
`the consensus climb will not run`
|
|
381
|
-
: `composition regime — ${
|
|
382
|
-
incumbentGrade === null
|
|
383
|
-
? "no incumbent (nothing grounded)"
|
|
384
|
-
: `incumbent grade ${incumbentGrade}`
|
|
385
|
-
} above climb floor ${climbFloorGrade}, so the full market and climb run`,
|
|
386
|
-
undefined,
|
|
387
|
-
{
|
|
388
|
-
version: 1,
|
|
389
|
-
regime,
|
|
390
|
-
incumbentGrade,
|
|
391
|
-
climbFloorGrade,
|
|
392
|
-
} satisfies RegimePredictionData,
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
408
|
}
|
|
409
|
+
// A market of ONE mechanism never reaches iteration 1; the step is still
|
|
410
|
+
// emitted exactly once per think(), so a consumer never has to ask whether
|
|
411
|
+
// the list was long enough for the prediction to exist.
|
|
412
|
+
reportRegime();
|
|
396
413
|
|
|
397
414
|
// (TS cannot see the closure assignments into `best` and narrows it to its
|
|
398
415
|
// initial null, so the read-back needs the assertion.)
|
|
@@ -592,7 +609,7 @@ export async function think(
|
|
|
592
609
|
reasoned,
|
|
593
610
|
pre,
|
|
594
611
|
unclimbed,
|
|
595
|
-
|
|
612
|
+
primarySpans,
|
|
596
613
|
);
|
|
597
614
|
|
|
598
615
|
done(
|
package/src/mind/recognition.ts
CHANGED
|
@@ -32,16 +32,24 @@ import type { Leaf, Site } from "./graph-search.js";
|
|
|
32
32
|
* the longest known leaf, chained into flat branches. Names forms the
|
|
33
33
|
* query's own cut cannot, and records sub-leaf boundaries as `splits`.
|
|
34
34
|
*
|
|
35
|
-
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
35
|
+
* Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus.
|
|
36
|
+
*
|
|
37
|
+
* ONE READING PER BYTE STREAM, deliberately: there is no "cheap mode" that
|
|
38
|
+
* skips the edge-trim fallbacks. A `trimmed` variant was tried and REFUTED
|
|
39
|
+
* twice over. Its premise — "the trims only recover misaligned FRAGMENTS, so
|
|
40
|
+
* a consumer whose gate rejects fragments loses nothing" — is false: the
|
|
41
|
+
* left/right trim loops below exist precisely to find WHOLE trained forms
|
|
42
|
+
* embedded at an offset the query's own fold did not cut, and such a form has
|
|
43
|
+
* no structural parents or containers, so it passes the pivot's fragment gate
|
|
44
|
+
* and is exactly the candidate a multi-hop chain steps through. Skipping them
|
|
45
|
+
* narrows the pivot's evidence silently. And a per-caller variant has to key
|
|
46
|
+
* the memo by the variant, which breaks the "computed at most once" property
|
|
47
|
+
* (§2.11): the pipeline recognises a grounded answer untrimmed for
|
|
48
|
+
* `preConsumed`, and the pivot then recognises the same bytes again — the
|
|
49
|
+
* saving inverts into a doubling on the path it was measured for. */
|
|
41
50
|
export function recognise(
|
|
42
51
|
ctx: MindContext,
|
|
43
52
|
bytes: Uint8Array,
|
|
44
|
-
trimmed = false,
|
|
45
53
|
): Recognition {
|
|
46
54
|
// Content-keyed memo — works for both single-turn respond() and multi-turn
|
|
47
55
|
// respondTurn() (where the map persists across calls). ALWAYS consulted,
|
|
@@ -82,7 +90,7 @@ export function recognise(
|
|
|
82
90
|
// not silent), so it is emitted here directly rather than only inside
|
|
83
91
|
// recogniseImpl.
|
|
84
92
|
if (ctx.recogniseMemo) {
|
|
85
|
-
const key =
|
|
93
|
+
const key = latin1Key(bytes);
|
|
86
94
|
const hit = ctx.recogniseMemo.get(key);
|
|
87
95
|
if (hit !== undefined) {
|
|
88
96
|
if (ctx.meter) ctx.meter.recogniseHits++;
|
|
@@ -100,18 +108,14 @@ export function recognise(
|
|
|
100
108
|
);
|
|
101
109
|
return hit;
|
|
102
110
|
}
|
|
103
|
-
const fresh = recogniseImpl(ctx, bytes
|
|
111
|
+
const fresh = recogniseImpl(ctx, bytes);
|
|
104
112
|
ctx.recogniseMemo.set(key, fresh);
|
|
105
113
|
return fresh;
|
|
106
114
|
}
|
|
107
|
-
return recogniseImpl(ctx, bytes
|
|
115
|
+
return recogniseImpl(ctx, bytes);
|
|
108
116
|
}
|
|
109
117
|
|
|
110
|
-
function recogniseImpl(
|
|
111
|
-
ctx: MindContext,
|
|
112
|
-
bytes: Uint8Array,
|
|
113
|
-
trimmed = false,
|
|
114
|
-
): Recognition {
|
|
118
|
+
function recogniseImpl(ctx: MindContext, bytes: Uint8Array): Recognition {
|
|
115
119
|
if (ctx.meter) {
|
|
116
120
|
ctx.meter.recognitions++;
|
|
117
121
|
ctx.meter.recognisedBytes += bytes.length;
|
|
@@ -224,7 +228,7 @@ function recogniseImpl(
|
|
|
224
228
|
// n.kids !== null enforces above) rather than degenerate into
|
|
225
229
|
// single-byte-atom territory, which atomIsHub already governs
|
|
226
230
|
// separately.
|
|
227
|
-
else if (
|
|
231
|
+
else if (end - start - 1 >= 2) {
|
|
228
232
|
// The chunk's own boundary is drawn by content geometry, not by
|
|
229
233
|
// any notion of "form" — it can include one edge byte the query's
|
|
230
234
|
// fold happened to attach here that the trained span never had
|
package/src/mind/resonance.ts
CHANGED
|
@@ -365,13 +365,13 @@ export async function pivotInto(
|
|
|
365
365
|
}
|
|
366
366
|
for (const c of n.kids) queue.push(c); // breadth-first: larger regions first
|
|
367
367
|
}
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
const rec = recognise(ctx, answer
|
|
368
|
+
// THE FULL recognition, memo-shared with every other reader of these bytes.
|
|
369
|
+
// A "skip the edge trims here" variant was refuted (see recognise's own
|
|
370
|
+
// note): those trims are what find a WHOLE trained form embedded at an
|
|
371
|
+
// offset the answer's fold did not cut, and such a form is parentless,
|
|
372
|
+
// container-free and edge-bearing — i.e. exactly what the filter below
|
|
373
|
+
// ADMITS as a pivot, not what it rejects.
|
|
374
|
+
const rec = recognise(ctx, answer);
|
|
375
375
|
for (const s of rec.sites) {
|
|
376
376
|
if (!consumed.has(s.payload) && ctx.store.hasNext(s.payload)) {
|
|
377
377
|
scored.set(s.payload, Math.max(scored.get(s.payload) ?? 0, 1));
|
|
@@ -399,6 +399,12 @@ export async function pivotInto(
|
|
|
399
399
|
let pivotId: number | null = null;
|
|
400
400
|
for (const c of ranked) {
|
|
401
401
|
const id = c.id;
|
|
402
|
+
// A ZERO-LENGTH candidate is not a pivot. `argmaxBy(…, 0, strict)` used to
|
|
403
|
+
// carry this floor in its threshold argument, and dropping it here would
|
|
404
|
+
// admit an empty node: `indexOf(answer, <empty>)` returns 0, so every
|
|
405
|
+
// filter below passes and the chain would hop through nothing (§2.13 —
|
|
406
|
+
// empty bytes are truthy).
|
|
407
|
+
if (c.len === 0) continue;
|
|
402
408
|
// A PIVOT MUST BE A THING THE CORPUS DEPOSITED, NOT A PIECE OF ONE.
|
|
403
409
|
// "Longest wins" ranks candidates but never asks whether the winner is
|
|
404
410
|
// an entity at all, and by the time a chain reaches here `consumeAll`
|