pi-mega-compact 0.20.0 → 0.20.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/dist/config/vector-cortex.js +25 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +2 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-reconstruct.js +33 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-residual.js +51 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex.js +2 -0
- package/dist/extensions/dashboard-server/routes.js +1 -1
- package/dist/extensions/dashboard-server/server.js +5 -1
- package/dist/src/config/vector-cortex.js +25 -0
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/reconstruct/_acceptance-helpers.js +365 -0
- package/dist/src/vector-cortex/reconstruct/assemble.js +137 -0
- package/dist/src/vector-cortex/reconstruct/closure.js +268 -0
- package/dist/src/vector-cortex/reconstruct/types.js +46 -0
- package/dist/src/vector-cortex/reconstruct/validate.js +152 -0
- package/dist/src/vector-cortex/residual/codec.js +224 -0
- package/dist/src/vector-cortex/residual/dct.js +158 -0
- package/dist/src/vector-cortex/residual/fixture-payload.js +77 -0
- package/dist/src/vector-cortex/residual/gf256.js +182 -0
- package/dist/src/vector-cortex/residual/parity.js +245 -0
- package/dist/src/vector-cortex/residual/quantize.js +200 -0
- package/dist/src/vector-cortex/residual/stream.js +124 -0
- package/dist/src/vector-cortex/residual/types.js +55 -0
- package/dist/vector-cortex/reconstruct/_acceptance-helpers.js +365 -0
- package/dist/vector-cortex/reconstruct/assemble.js +137 -0
- package/dist/vector-cortex/reconstruct/closure.js +268 -0
- package/dist/vector-cortex/reconstruct/types.js +46 -0
- package/dist/vector-cortex/reconstruct/validate.js +152 -0
- package/dist/vector-cortex/residual/codec.js +224 -0
- package/dist/vector-cortex/residual/dct.js +158 -0
- package/dist/vector-cortex/residual/fixture-payload.js +77 -0
- package/dist/vector-cortex/residual/gf256.js +182 -0
- package/dist/vector-cortex/residual/parity.js +245 -0
- package/dist/vector-cortex/residual/quantize.js +200 -0
- package/dist/vector-cortex/residual/stream.js +124 -0
- package/dist/vector-cortex/residual/types.js +55 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-n4z5w9Ox.js → AreaChart-XF3jPpvn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-n4z5w9Ox.js.map → AreaChart-XF3jPpvn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-BLGjWWBr.js → BarChart-DnYYn0GF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-BLGjWWBr.js.map → BarChart-DnYYn0GF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-CAnrKKVK.js → CacheTab-D3bVskCL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-CAnrKKVK.js.map → CacheTab-D3bVskCL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-D-GL7Ngq.js → EventsTab-CX_8myfc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-D-GL7Ngq.js.map → EventsTab-CX_8myfc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-C4x5qQ8s.js → HealthTab-CnVzBQvN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-C4x5qQ8s.js.map → HealthTab-CnVzBQvN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BSPs0eq5.js → MaintenanceTab-Cao--dtV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BSPs0eq5.js.map → MaintenanceTab-Cao--dtV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BWEUtTSu.js → MemoryMapTab-DZdI-9ig.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BWEUtTSu.js.map → MemoryMapTab-DZdI-9ig.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Dhm1c3Cx.js → MetricsTab-SlpSmNU4.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Dhm1c3Cx.js.map → MetricsTab-SlpSmNU4.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Cm6cySiQ.js → OverviewTab-C_-_4au9.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Cm6cySiQ.js.map → OverviewTab-C_-_4au9.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DxLN1N4K.js → ReposTab-CyWedWZC.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DxLN1N4K.js.map → ReposTab-CyWedWZC.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CZuI4ISW.js → SessionsTab-wqPBMIJZ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CZuI4ISW.js.map → SessionsTab-wqPBMIJZ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-C_0VOomm.js → SetupTab-MojXmuUf.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-C_0VOomm.js.map → SetupTab-MojXmuUf.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BhbaRLmi.js → TimeSavedCard-BxcplEOJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BhbaRLmi.js.map → TimeSavedCard-BxcplEOJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CXJmbjje.js → TurnsTab-D8_qWbjY.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CXJmbjje.js.map → TurnsTab-D8_qWbjY.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-B3yisAyB.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-B3yisAyB.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-C5uvMCzp.js → WikiTab-Cfd-QZYz.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-C5uvMCzp.js.map → WikiTab-Cfd-QZYz.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-Cl_fxJcg.js → button-tX5ht0bb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-Cl_fxJcg.js.map → button-tX5ht0bb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-BH8Le5YM.js → card-BT3Z5dDg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-BH8Le5YM.js.map → card-BT3Z5dDg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-sZ6ZNtBi.js → generateCategoricalChart-B6p2WnkY.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-sZ6ZNtBi.js.map → generateCategoricalChart-B6p2WnkY.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-CX9zv8cJ.js → index-CFLekP12.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-CX9zv8cJ.js.map → index-CFLekP12.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-CXJhcjhM.js → switch-B52oAMSw.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-CXJhcjhM.js.map → switch-B52oAMSw.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-CoLtIc6y.js → toggle-VxxVc5Tp.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-CoLtIc6y.js.map → toggle-VxxVc5Tp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-fSXho606.js → useSSE-DAVdZnG7.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-fSXho606.js.map → useSSE-DAVdZnG7.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/api/vector-cortex.ts +9 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +37 -0
- package/extensions/dashboard-client/src/types/vector-cortex.ts +16 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex.ts +57 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +12 -0
- package/extensions/dashboard-server/routes-vector-cortex-reconstruct.ts +41 -0
- package/extensions/dashboard-server/routes-vector-cortex-residual.ts +60 -0
- package/extensions/dashboard-server/routes-vector-cortex.ts +2 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +4 -0
- package/package.json +1 -1
- package/src/config/vector-cortex.ts +27 -0
- package/src/config.ts +2 -0
- package/src/vector-cortex/reconstruct/_acceptance-helpers.ts +455 -0
- package/src/vector-cortex/reconstruct/assemble.ts +170 -0
- package/src/vector-cortex/reconstruct/closure.ts +299 -0
- package/src/vector-cortex/reconstruct/types.ts +330 -0
- package/src/vector-cortex/reconstruct/validate.ts +184 -0
- package/src/vector-cortex/residual/codec.ts +292 -0
- package/src/vector-cortex/residual/dct.ts +166 -0
- package/src/vector-cortex/residual/fixture-payload.ts +90 -0
- package/src/vector-cortex/residual/gf256.ts +196 -0
- package/src/vector-cortex/residual/parity.ts +283 -0
- package/src/vector-cortex/residual/quantize.ts +230 -0
- package/src/vector-cortex/residual/stream.ts +135 -0
- package/src/vector-cortex/residual/types.ts +236 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js.map +0 -1
|
@@ -134,6 +134,31 @@ export const VC3C_ENABLED = () => sprintFlag("MEGACOMPACT_VC3C");
|
|
|
134
134
|
* dashboard shards aggregate view.
|
|
135
135
|
*/
|
|
136
136
|
export const VC4A_ENABLED = () => sprintFlag("MEGACOMPACT_VC4A");
|
|
137
|
+
/**
|
|
138
|
+
* VC4B — residual codec and numeric parity (ResidualCodecV1 / ParityShardV1).
|
|
139
|
+
* Default ON. `MEGACOMPACT_VC4B=0` disables and is byte-identical to the
|
|
140
|
+
* predecessor (mode C: no residual artifact is admitted, the exact compressed
|
|
141
|
+
* payload / ledger bytes remain the only representation, zero
|
|
142
|
+
* `vector_cortex_residual_admitted` / `vector_cortex_parity_recovery_failed`
|
|
143
|
+
* emissions; the VC4A shard manifest and its goldens are unchanged). The real
|
|
144
|
+
* consumers are the codec admission seam (codec.ts) and the reader-only
|
|
145
|
+
* dashboard residual aggregate view. The codec math itself is PURE — flag OFF
|
|
146
|
+
* gates the reporter/admission seam, never the arithmetic.
|
|
147
|
+
*/
|
|
148
|
+
export const VC4B_ENABLED = () => sprintFlag("MEGACOMPACT_VC4B");
|
|
149
|
+
/**
|
|
150
|
+
* VC4C — reconstruction fidelity (closure + assemble + validate). Default ON.
|
|
151
|
+
* `MEGACOMPACT_VC4C=0` disables and is byte-identical to the predecessor
|
|
152
|
+
* (VC4B): no conservative closure is computed, the reconstruction validator's
|
|
153
|
+
* `vector_cortex_reconstruction_validated` / `vector_cortex_closure_rejected`
|
|
154
|
+
* events are never emitted, and the assembled reconstruction is never produced
|
|
155
|
+
* (the prompt continues to be built by the legacy VC4B exact/residual path and
|
|
156
|
+
* the VC4A shard goldens are unchanged). The closure/assemble/validate
|
|
157
|
+
* functions are PURE — flag OFF gates the reporter seam, never the arithmetic.
|
|
158
|
+
* This flag MUST also be a dashboard SETTINGS toggle (visible in config UI,
|
|
159
|
+
* never in EXCLUDED_SETTINGS), mirroring VC4A/VC4B.
|
|
160
|
+
*/
|
|
161
|
+
export const VC4C_ENABLED = () => sprintFlag("MEGACOMPACT_VC4C");
|
|
137
162
|
// ---------------------------------------------------------------------------
|
|
138
163
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker).
|
|
139
164
|
// Rolled numbers for one 60s window; VC0C consumes these at its breaker seam.
|
package/dist/config.js
CHANGED
|
@@ -114,4 +114,4 @@ export const NEW_UI = () => ragEnabled("MEGACOMPACT_NEW_UI");
|
|
|
114
114
|
// default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
|
|
115
115
|
// so root consumers share one source of truth.
|
|
116
116
|
// ---------------------------------------------------------------------------
|
|
117
|
-
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
117
|
+
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
@@ -147,6 +147,8 @@ export const SETTINGS = [
|
|
|
147
147
|
boolDirect("MEGACOMPACT_VC3B", "VC3B Deterministic Topology", "Deterministic cortical topology (TopologyV1/EdgeV1): per-(source,head) top-k=16/head calibrated-threshold edges, stable score-desc/then-target-ID sort, dependency directed + contradiction symmetric paired records, one stable generation digest. OFF = mode C, no topology graph built/emitted, predecessor-precise topology view, byte-identical predecessor.", true),
|
|
148
148
|
boolDirect("MEGACOMPACT_VC3C", "VC3C Topology Query + Router Invalidation", "TopologyQueryV1/RouterKeyV2 structured keys (length-delimited, unsigned-byte order, no prefix ambiguity), exact (session,generation) invalidation, stale-generation rejection (TOP_GENERATION_STALE), and the M6 router-generation-v2 copy/validate/switch migration. OFF = mode C, no structured router key / generation invalidation, byte-identical predecessor.", true),
|
|
149
149
|
boolDirect("MEGACOMPACT_VC4A", "VC4A Dual-Tier Shards", "SemanticShardV1/ExactShardV1/ShardManifestV1: partition a session ONLY at complete EventV2 boundaries; exact shards preserve every tool call/result pair, anchor and invalid UTF-8 event as original bytes (pairs never split across exact shards); manifest enforces disjoint sorted ranges + complete protected-span coverage. OFF = mode C, exact anchors/current transcript only, byte-identical predecessor.", true),
|
|
150
|
+
boolDirect("MEGACOMPACT_VC4B", "VC4B Residual Basis Parity", "Residual codec: orthonormal DCT-II basis + int16 block quantization + block-scoped exact correction stream + (9,6) Reed-Solomon parity shards with SHA-256 corruption detection; admission gates on encodedSize <= 95% of exact-compressed size. OFF = mode C, no residual artifact produced, byte-identical predecessor.", true),
|
|
151
|
+
boolDirect("MEGACOMPACT_VC4C", "VC4C Reconstruction Fidelity", "Conservative closure + source-order assembly + reconstruction validator: recursively closes dependencies and whole tool pairs to a fixed point, resolves contradictions by retaining the later exact source resolution, assembles spans solely by source range, and rejects missing anchors / split pairs / digest mismatch / unresolved contradiction. Mandatory token estimate is content-only and handed unchanged to VC5A. OFF = mode C, no closure/validator, byte-identical predecessor (VC4B).", true),
|
|
150
152
|
],
|
|
151
153
|
},
|
|
152
154
|
{
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard handler: GET /api/vector-cortex/reconstruct (VC4C).
|
|
3
|
+
*
|
|
4
|
+
* Reader-only reconstruction-fidelity aggregate. Mirrors the VC4B residual
|
|
5
|
+
* handler: path guard + 405 on non-GET, gated on the sprint flag, returns a
|
|
6
|
+
* zero-valued view when disabled (byte-identical predecessor contract). Never
|
|
7
|
+
* returns reconstructed spans, exact bytes, or prompt text.
|
|
8
|
+
*/
|
|
9
|
+
import { VC4C_ENABLED } from "../../src/config.js";
|
|
10
|
+
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
11
|
+
export function handleVectorCortexReconstruct(req, res, _ctx) {
|
|
12
|
+
const url = req.url ?? "";
|
|
13
|
+
const path = url.split("?")[0] ?? url;
|
|
14
|
+
if (path !== "/api/vector-cortex/reconstruct")
|
|
15
|
+
return false;
|
|
16
|
+
if (req.method !== "GET") {
|
|
17
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const enabled = VC4C_ENABLED();
|
|
21
|
+
const body = {
|
|
22
|
+
enabled,
|
|
23
|
+
closureAttempts: 0,
|
|
24
|
+
closureRejections: 0,
|
|
25
|
+
validatedCount: 0,
|
|
26
|
+
invalidatedCount: 0,
|
|
27
|
+
spanTotal: 0,
|
|
28
|
+
byteTotal: 0,
|
|
29
|
+
updatedAt: new Date().toISOString(),
|
|
30
|
+
};
|
|
31
|
+
sendJson(res, 200, body);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-vector-cortex-residual.ts — VC4B residual basis parity
|
|
3
|
+
* dashboard route.
|
|
4
|
+
*
|
|
5
|
+
* Reader-only GET /api/vector-cortex/residual returning a COUNT/BYTE aggregate
|
|
6
|
+
* (encode attempts, admitted/rejected counts, recovery failures, encoded/exact
|
|
7
|
+
* byte totals) — never residual payloads, correction streams, shard bytes, or
|
|
8
|
+
* original source bytes. Flag-gated on MEGACOMPACT_VC4B: `enabled:false` when off
|
|
9
|
+
* (byte-identical to the pre-VC4B predecessor).
|
|
10
|
+
*
|
|
11
|
+
* The VC4B residual codec is PURE IN-MEMORY logic in this sprint (it has no
|
|
12
|
+
* durable metrics store yet), so the aggregate reports the current status
|
|
13
|
+
* truthfully: `enabled` reflects the flag, and the count/byte fields are zero
|
|
14
|
+
* until a future sprint persists a metrics store. This route is the seam that
|
|
15
|
+
* sprint will populate. Non-fatal: a missing state dir degrades to
|
|
16
|
+
* `enabled:false`.
|
|
17
|
+
*
|
|
18
|
+
* Guardrails: PREVENT-PI-004 (local filesystem read only / in-process state),
|
|
19
|
+
* PREVENT-011 (no `any`), reader-only aggregate (counts/bytes only).
|
|
20
|
+
*/
|
|
21
|
+
import { VC4B_ENABLED } from "../../src/config.js";
|
|
22
|
+
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
23
|
+
/**
|
|
24
|
+
* Reader-only GET /api/vector-cortex/residual (VC4B).
|
|
25
|
+
*/
|
|
26
|
+
export function handleVectorCortexResidual(req, res, _ctx) {
|
|
27
|
+
const url = req.url ?? "";
|
|
28
|
+
const path = url.split("?")[0] ?? url;
|
|
29
|
+
if (path !== "/api/vector-cortex/residual")
|
|
30
|
+
return false;
|
|
31
|
+
if (req.method !== "GET") {
|
|
32
|
+
// Reader-only path: cannot be "off" without a GET; it is genuinely read-only.
|
|
33
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
const enabled = VC4B_ENABLED();
|
|
37
|
+
const body = {
|
|
38
|
+
enabled,
|
|
39
|
+
// No durable residual metrics store is staged yet in this sprint (pure
|
|
40
|
+
// in-memory encode), so the aggregates are truthfully zero.
|
|
41
|
+
encodeAttempts: 0,
|
|
42
|
+
admittedCount: 0,
|
|
43
|
+
rejectedCount: 0,
|
|
44
|
+
recoveryFailures: 0,
|
|
45
|
+
encodedByteTotal: 0,
|
|
46
|
+
exactByteTotal: 0,
|
|
47
|
+
updatedAt: new Date().toISOString(),
|
|
48
|
+
};
|
|
49
|
+
sendJson(res, 200, body);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
@@ -19,3 +19,5 @@ export { handleVectorCortexLedger } from "./routes-vector-cortex-ledger.js";
|
|
|
19
19
|
export { handleVectorCortexTopology } from "./routes-vector-cortex-topology.js";
|
|
20
20
|
export { handleVectorCortexQuery } from "./routes-vector-cortex-query.js";
|
|
21
21
|
export { handleVectorCortexShards } from "./routes-vector-cortex-shards.js";
|
|
22
|
+
export { handleVectorCortexResidual } from "./routes-vector-cortex-residual.js";
|
|
23
|
+
export { handleVectorCortexReconstruct } from "./routes-vector-cortex-reconstruct.js";
|
|
@@ -23,4 +23,4 @@ export { handleRagSettings } from "./routes-rag-settings.js";
|
|
|
23
23
|
export { handleRagMetrics } from "./routes-rag-metrics.js";
|
|
24
24
|
export { handleModelThresholds } from "./routes-model-thresholds.js";
|
|
25
25
|
export { handleWiki } from "./routes-wiki.js";
|
|
26
|
-
export { handleVectorCortexEvaluation, handleVectorCortexHealth, handleVectorCortexBreakersReset, handleVectorCortexLedger, handleVectorCortexTopology, handleVectorCortexQuery, handleVectorCortexShards, } from "./routes-vector-cortex.js";
|
|
26
|
+
export { handleVectorCortexEvaluation, handleVectorCortexHealth, handleVectorCortexBreakersReset, handleVectorCortexLedger, handleVectorCortexTopology, handleVectorCortexQuery, handleVectorCortexShards, handleVectorCortexResidual, handleVectorCortexReconstruct, } from "./routes-vector-cortex.js";
|
|
@@ -14,7 +14,7 @@ import { createRequire } from "node:module";
|
|
|
14
14
|
import { NEW_UI } from "../../src/config.js";
|
|
15
15
|
import { log, setLogPath, setDashboardServerVersion } from "./state.js";
|
|
16
16
|
import { detectTailscaleIP } from "./tailscale.js";
|
|
17
|
-
import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handlePerfSamples, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleCacheStripes, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleSetupConfigure, handleMemoryMap, handleRaptorTree, handleRaptorBuildHistory, handleContextHealth, handleCachePoison, handleHealthSettings, handleEmbedderHealth, handleRagSettings, handleRagMetrics, handleModelThresholds, handleWiki, handleVectorCortexEvaluation, handleVectorCortexHealth, handleVectorCortexBreakersReset, handleVectorCortexLedger, handleVectorCortexTopology, handleVectorCortexQuery, handleVectorCortexShards, handleStatic, } from "./routes.js";
|
|
17
|
+
import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handlePerfSamples, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleCacheStripes, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleSetupConfigure, handleMemoryMap, handleRaptorTree, handleRaptorBuildHistory, handleContextHealth, handleCachePoison, handleHealthSettings, handleEmbedderHealth, handleRagSettings, handleRagMetrics, handleModelThresholds, handleWiki, handleVectorCortexEvaluation, handleVectorCortexHealth, handleVectorCortexBreakersReset, handleVectorCortexLedger, handleVectorCortexTopology, handleVectorCortexQuery, handleVectorCortexShards, handleVectorCortexResidual, handleVectorCortexReconstruct, handleStatic, } from "./routes.js";
|
|
18
18
|
export async function launchDashboardServer(stateDir) {
|
|
19
19
|
// Our own package version — exposed at /api/version so the launcher can
|
|
20
20
|
// detect a stale server (started by an older build) and replace it on
|
|
@@ -269,6 +269,10 @@ export async function launchDashboardServer(stateDir) {
|
|
|
269
269
|
return;
|
|
270
270
|
if (handleVectorCortexShards(req, res, ctx))
|
|
271
271
|
return;
|
|
272
|
+
if (handleVectorCortexResidual(req, res, ctx))
|
|
273
|
+
return;
|
|
274
|
+
if (handleVectorCortexReconstruct(req, res, ctx))
|
|
275
|
+
return;
|
|
272
276
|
handleStatic(req, res, ctx);
|
|
273
277
|
});
|
|
274
278
|
// Bind base + range are env-configurable so tests can use a private,
|
|
@@ -134,6 +134,31 @@ export const VC3C_ENABLED = () => sprintFlag("MEGACOMPACT_VC3C");
|
|
|
134
134
|
* dashboard shards aggregate view.
|
|
135
135
|
*/
|
|
136
136
|
export const VC4A_ENABLED = () => sprintFlag("MEGACOMPACT_VC4A");
|
|
137
|
+
/**
|
|
138
|
+
* VC4B — residual codec and numeric parity (ResidualCodecV1 / ParityShardV1).
|
|
139
|
+
* Default ON. `MEGACOMPACT_VC4B=0` disables and is byte-identical to the
|
|
140
|
+
* predecessor (mode C: no residual artifact is admitted, the exact compressed
|
|
141
|
+
* payload / ledger bytes remain the only representation, zero
|
|
142
|
+
* `vector_cortex_residual_admitted` / `vector_cortex_parity_recovery_failed`
|
|
143
|
+
* emissions; the VC4A shard manifest and its goldens are unchanged). The real
|
|
144
|
+
* consumers are the codec admission seam (codec.ts) and the reader-only
|
|
145
|
+
* dashboard residual aggregate view. The codec math itself is PURE — flag OFF
|
|
146
|
+
* gates the reporter/admission seam, never the arithmetic.
|
|
147
|
+
*/
|
|
148
|
+
export const VC4B_ENABLED = () => sprintFlag("MEGACOMPACT_VC4B");
|
|
149
|
+
/**
|
|
150
|
+
* VC4C — reconstruction fidelity (closure + assemble + validate). Default ON.
|
|
151
|
+
* `MEGACOMPACT_VC4C=0` disables and is byte-identical to the predecessor
|
|
152
|
+
* (VC4B): no conservative closure is computed, the reconstruction validator's
|
|
153
|
+
* `vector_cortex_reconstruction_validated` / `vector_cortex_closure_rejected`
|
|
154
|
+
* events are never emitted, and the assembled reconstruction is never produced
|
|
155
|
+
* (the prompt continues to be built by the legacy VC4B exact/residual path and
|
|
156
|
+
* the VC4A shard goldens are unchanged). The closure/assemble/validate
|
|
157
|
+
* functions are PURE — flag OFF gates the reporter seam, never the arithmetic.
|
|
158
|
+
* This flag MUST also be a dashboard SETTINGS toggle (visible in config UI,
|
|
159
|
+
* never in EXCLUDED_SETTINGS), mirroring VC4A/VC4B.
|
|
160
|
+
*/
|
|
161
|
+
export const VC4C_ENABLED = () => sprintFlag("MEGACOMPACT_VC4C");
|
|
137
162
|
// ---------------------------------------------------------------------------
|
|
138
163
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker).
|
|
139
164
|
// Rolled numbers for one 60s window; VC0C consumes these at its breaker seam.
|
package/dist/src/config.js
CHANGED
|
@@ -114,4 +114,4 @@ export const NEW_UI = () => ragEnabled("MEGACOMPACT_NEW_UI");
|
|
|
114
114
|
// default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
|
|
115
115
|
// so root consumers share one source of truth.
|
|
116
116
|
// ---------------------------------------------------------------------------
|
|
117
|
-
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
117
|
+
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reconstruct/_acceptance-helpers.ts — fixture materialization for the VC4C
|
|
3
|
+
* acceptance aggregator.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from vc4c-acceptance.test.ts so the test file itself stays under
|
|
6
|
+
* the tests/ 600-line hard limit. Turns the declarative conformance fixtures
|
|
7
|
+
* (graph/shard names) into real `ClosureGraph` / `DecodedShard` values and
|
|
8
|
+
* drives them through the REAL reconstruct logic — no mocks, no stubs.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import assert from "node:assert/strict";
|
|
14
|
+
import { closeSelection, isFixedPoint, closeExactOnly } from "./closure.js";
|
|
15
|
+
import { validateAndAssemble } from "./validate.js";
|
|
16
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
export function repoRoot(from) {
|
|
18
|
+
let dir = from;
|
|
19
|
+
for (let i = 0; i < 8; i++) {
|
|
20
|
+
if (existsSync(join(dir, "conformance", "vector-cortex")))
|
|
21
|
+
return dir;
|
|
22
|
+
const next = dirname(dir);
|
|
23
|
+
if (next === dir)
|
|
24
|
+
break;
|
|
25
|
+
dir = next;
|
|
26
|
+
}
|
|
27
|
+
throw new Error("conformance corpus not found above " + from);
|
|
28
|
+
}
|
|
29
|
+
export const REPO_ROOT = repoRoot(HERE);
|
|
30
|
+
export const V2 = join(REPO_ROOT, "conformance", "vector-cortex", "v2");
|
|
31
|
+
export function readManifest() {
|
|
32
|
+
return JSON.parse(readFileSync(join(V2, "manifest.json"), "utf8"));
|
|
33
|
+
}
|
|
34
|
+
export function fixture(id) {
|
|
35
|
+
const m = readManifest();
|
|
36
|
+
const row = m.fixtures.find((f) => f.id === id && f.path.startsWith("reconstruction/"));
|
|
37
|
+
assert.ok(row, `fixture ${id} registered under reconstruction/ in manifest`);
|
|
38
|
+
return JSON.parse(readFileSync(join(V2, row.path), "utf8"));
|
|
39
|
+
}
|
|
40
|
+
/** Flag-pinned wrapper: the reconstruct math is identical with the flag on. */
|
|
41
|
+
export function withFlagsOn(fn) {
|
|
42
|
+
return () => {
|
|
43
|
+
const saved = process.env.MEGACOMPACT_VC4C;
|
|
44
|
+
process.env.MEGACOMPACT_VC4C = "1";
|
|
45
|
+
try {
|
|
46
|
+
fn();
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
if (saved === undefined)
|
|
50
|
+
delete process.env.MEGACOMPACT_VC4C;
|
|
51
|
+
else
|
|
52
|
+
process.env.MEGACOMPACT_VC4C = saved;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// ── Declarative graph materialization ───────────────────────────────────────
|
|
57
|
+
export function node(id, kind, opts = {}) {
|
|
58
|
+
return { id, kind, tokenEstimate: opts.tokenEstimate ?? 10, anchor: opts.anchor, resolvedAtMs: opts.resolvedAtMs, span: opts.span };
|
|
59
|
+
}
|
|
60
|
+
export function span(sessionId, seqStart, byteStart, len) {
|
|
61
|
+
return { sessionId, seqStart, seqEnd: seqStart, byteStart, byteEnd: byteStart + len };
|
|
62
|
+
}
|
|
63
|
+
export function edge(from, to, kind) {
|
|
64
|
+
return { from, to, kind };
|
|
65
|
+
}
|
|
66
|
+
/** Materialize a named graph into a real ClosureGraph. */
|
|
67
|
+
export function materializeGraph(name) {
|
|
68
|
+
const cases = {
|
|
69
|
+
chain: {
|
|
70
|
+
sessionId: "s",
|
|
71
|
+
nodes: [node("a", "event"), node("b", "event"), node("c", "event")],
|
|
72
|
+
edges: [edge("b", "a", "depends"), edge("c", "b", "depends")],
|
|
73
|
+
},
|
|
74
|
+
diamond: {
|
|
75
|
+
sessionId: "s",
|
|
76
|
+
nodes: [node("top", "event"), node("l", "event"), node("r", "event"), node("bottom", "event")],
|
|
77
|
+
edges: [edge("l", "top", "depends"), edge("r", "top", "depends"), edge("bottom", "l", "depends"), edge("bottom", "r", "depends")],
|
|
78
|
+
},
|
|
79
|
+
cycle: {
|
|
80
|
+
sessionId: "s",
|
|
81
|
+
nodes: [node("a", "event"), node("b", "event"), node("c", "event")],
|
|
82
|
+
edges: [edge("b", "a", "depends"), edge("c", "b", "depends"), edge("a", "c", "depends")],
|
|
83
|
+
},
|
|
84
|
+
selfloop: {
|
|
85
|
+
sessionId: "s",
|
|
86
|
+
nodes: [node("a", "event")],
|
|
87
|
+
edges: [edge("a", "a", "depends")],
|
|
88
|
+
},
|
|
89
|
+
parallel: {
|
|
90
|
+
sessionId: "s",
|
|
91
|
+
nodes: [node("a", "event"), node("b", "event"), node("x", "event"), node("y", "event")],
|
|
92
|
+
edges: [edge("b", "a", "depends"), edge("y", "x", "depends")],
|
|
93
|
+
},
|
|
94
|
+
prereq: {
|
|
95
|
+
sessionId: "s",
|
|
96
|
+
nodes: [node("dependent", "event"), node("prereq", "event")],
|
|
97
|
+
edges: [edge("prereq", "dependent", "depends")],
|
|
98
|
+
},
|
|
99
|
+
leaf: {
|
|
100
|
+
sessionId: "s",
|
|
101
|
+
nodes: [node("only", "event")],
|
|
102
|
+
edges: [],
|
|
103
|
+
},
|
|
104
|
+
scrambled: {
|
|
105
|
+
sessionId: "s",
|
|
106
|
+
nodes: [node("a", "event"), node("m", "event"), node("z", "event")],
|
|
107
|
+
edges: [edge("m", "a", "depends"), edge("z", "m", "depends")],
|
|
108
|
+
},
|
|
109
|
+
"dangling-edge": {
|
|
110
|
+
sessionId: "s",
|
|
111
|
+
nodes: [node("a", "event")],
|
|
112
|
+
edges: [edge("a", "ghost", "depends")],
|
|
113
|
+
},
|
|
114
|
+
toolpair: {
|
|
115
|
+
sessionId: "s",
|
|
116
|
+
nodes: [node("toolcall", "event"), node("toolresult", "event")],
|
|
117
|
+
edges: [edge("toolcall", "toolresult", "tool-pair")],
|
|
118
|
+
},
|
|
119
|
+
anchored: {
|
|
120
|
+
sessionId: "s",
|
|
121
|
+
nodes: [node("a", "event"), node("anchor", "event", { anchor: true })],
|
|
122
|
+
edges: [edge("a", "anchor", "depends")],
|
|
123
|
+
},
|
|
124
|
+
"anchor-deps": {
|
|
125
|
+
sessionId: "s",
|
|
126
|
+
nodes: [node("a", "event"), node("anchor", "event", { anchor: true }), node("anchordep", "event", { anchor: true })],
|
|
127
|
+
edges: [edge("anchor", "a", "depends"), edge("anchordep", "anchor", "depends")],
|
|
128
|
+
},
|
|
129
|
+
"toolpair-transitive": {
|
|
130
|
+
sessionId: "s",
|
|
131
|
+
nodes: [node("toolcall", "event"), node("toolresult", "event"), node("shareddep", "event")],
|
|
132
|
+
edges: [edge("toolcall", "toolresult", "tool-pair"), edge("shareddep", "toolcall", "depends"), edge("shareddep", "toolresult", "depends")],
|
|
133
|
+
},
|
|
134
|
+
"two-pairs": {
|
|
135
|
+
sessionId: "s",
|
|
136
|
+
nodes: [node("a", "event"), node("b", "event"), node("c", "event"), node("d", "event")],
|
|
137
|
+
edges: [edge("a", "b", "tool-pair"), edge("c", "d", "tool-pair")],
|
|
138
|
+
},
|
|
139
|
+
"anchor-pair": {
|
|
140
|
+
sessionId: "s",
|
|
141
|
+
nodes: [node("toolcall", "event"), node("toolresult", "event"), node("anchor", "event", { anchor: true })],
|
|
142
|
+
edges: [edge("toolcall", "toolresult", "tool-pair"), edge("anchor", "toolcall", "depends")],
|
|
143
|
+
},
|
|
144
|
+
chain8: {
|
|
145
|
+
sessionId: "s",
|
|
146
|
+
nodes: [0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) => node(`n${i}`, "event")),
|
|
147
|
+
edges: [0, 1, 2, 3, 4, 5, 6, 7].map((i) => edge(`n${i + 1}`, `n${i}`, "depends")),
|
|
148
|
+
},
|
|
149
|
+
"pair-dep": {
|
|
150
|
+
sessionId: "s",
|
|
151
|
+
nodes: [node("toolcall", "event"), node("toolresult", "event"), node("common", "event")],
|
|
152
|
+
edges: [edge("toolcall", "toolresult", "tool-pair"), edge("common", "toolcall", "depends"), edge("common", "toolresult", "depends")],
|
|
153
|
+
},
|
|
154
|
+
overlap: {
|
|
155
|
+
sessionId: "s",
|
|
156
|
+
nodes: [node("a", "event"), node("b", "event"), node("c", "event"), node("d", "event")],
|
|
157
|
+
edges: [edge("a", "c", "depends"), edge("b", "c", "depends"), edge("b", "d", "depends")],
|
|
158
|
+
},
|
|
159
|
+
"contra-explicit": {
|
|
160
|
+
sessionId: "s",
|
|
161
|
+
nodes: [node("a", "event"), node("loser", "exact", { resolvedAtMs: 100n }), node("winner", "exact", { resolvedAtMs: 200n })],
|
|
162
|
+
edges: [edge("loser", "winner", "contradicts"), edge("loser", "a", "depends"), edge("winner", "loser", "depends")],
|
|
163
|
+
resolutions: [{ loserId: "loser", winnerId: "winner" }],
|
|
164
|
+
},
|
|
165
|
+
"contra-later": {
|
|
166
|
+
sessionId: "s",
|
|
167
|
+
nodes: [node("a", "event"), node("early", "exact", { resolvedAtMs: 100n }), node("late", "exact", { resolvedAtMs: 200n })],
|
|
168
|
+
edges: [edge("early", "late", "contradicts"), edge("early", "a", "depends"), edge("late", "early", "depends")],
|
|
169
|
+
},
|
|
170
|
+
"contra-tie": {
|
|
171
|
+
sessionId: "s",
|
|
172
|
+
nodes: [node("a", "event"), node("x", "exact", { resolvedAtMs: 100n }), node("y", "exact", { resolvedAtMs: 100n })],
|
|
173
|
+
edges: [edge("x", "y", "contradicts"), edge("x", "a", "depends"), edge("y", "x", "depends")],
|
|
174
|
+
},
|
|
175
|
+
"contra-non-exact": {
|
|
176
|
+
sessionId: "s",
|
|
177
|
+
nodes: [node("a", "event"), node("x", "semantic", { resolvedAtMs: 100n }), node("y", "semantic", { resolvedAtMs: 200n })],
|
|
178
|
+
edges: [edge("x", "y", "contradicts"), edge("x", "a", "depends"), edge("y", "x", "depends")],
|
|
179
|
+
},
|
|
180
|
+
"contra-unselected": {
|
|
181
|
+
sessionId: "s",
|
|
182
|
+
nodes: [node("a", "event"), node("x", "exact", { resolvedAtMs: 100n }), node("y", "exact", { resolvedAtMs: 200n })],
|
|
183
|
+
edges: [edge("x", "y", "contradicts"), edge("a", "x", "depends")],
|
|
184
|
+
},
|
|
185
|
+
"contra-semantic": {
|
|
186
|
+
sessionId: "s",
|
|
187
|
+
nodes: [node("a", "event"), node("x", "semantic", { resolvedAtMs: 100n }), node("y", "exact", { resolvedAtMs: 200n })],
|
|
188
|
+
edges: [edge("x", "y", "contradicts"), edge("x", "a", "depends"), edge("y", "x", "depends")],
|
|
189
|
+
},
|
|
190
|
+
"contra-deps": {
|
|
191
|
+
sessionId: "s",
|
|
192
|
+
nodes: [node("a", "event"), node("early", "exact", { resolvedAtMs: 100n }), node("late", "exact", { resolvedAtMs: 200n }), node("dep", "event")],
|
|
193
|
+
edges: [edge("early", "late", "contradicts"), edge("early", "a", "depends"), edge("dep", "early", "depends"), edge("late", "early", "depends")],
|
|
194
|
+
},
|
|
195
|
+
tokened: {
|
|
196
|
+
sessionId: "s",
|
|
197
|
+
nodes: [node("a", "event", { tokenEstimate: 10 }), node("b", "event", { tokenEstimate: 10 }), node("c", "event", { tokenEstimate: 10 })],
|
|
198
|
+
edges: [edge("b", "a", "depends"), edge("c", "b", "depends")],
|
|
199
|
+
},
|
|
200
|
+
ordered: {
|
|
201
|
+
sessionId: "s",
|
|
202
|
+
nodes: [node("a", "semantic", { span: span("s", 1n, 0, 6) }), node("b", "exact", { span: span("s", 1n, 6, 6) }), node("c", "exact", { span: span("s", 1n, 12, 6) })],
|
|
203
|
+
edges: [edge("b", "a", "depends"), edge("c", "b", "depends")],
|
|
204
|
+
},
|
|
205
|
+
"scrambled-spans": {
|
|
206
|
+
sessionId: "s",
|
|
207
|
+
nodes: [node("c", "exact", { span: span("s", 1n, 12, 6) }), node("a", "semantic", { span: span("s", 1n, 0, 6) }), node("b", "exact", { span: span("s", 1n, 6, 6) })],
|
|
208
|
+
edges: [],
|
|
209
|
+
},
|
|
210
|
+
protected: {
|
|
211
|
+
sessionId: "s",
|
|
212
|
+
nodes: [node("a", "exact", { span: span("s", 1n, 0, 6) }), node("b", "exact", { span: span("s", 1n, 6, 6) })],
|
|
213
|
+
edges: [edge("b", "a", "depends")],
|
|
214
|
+
},
|
|
215
|
+
empty: { sessionId: "s", nodes: [], edges: [] },
|
|
216
|
+
reverse: {
|
|
217
|
+
sessionId: "s",
|
|
218
|
+
nodes: [node("c", "exact", { span: span("s", 1n, 12, 6) }), node("b", "exact", { span: span("s", 1n, 6, 6) }), node("a", "semantic", { span: span("s", 1n, 0, 6) })],
|
|
219
|
+
edges: [],
|
|
220
|
+
},
|
|
221
|
+
adjacent: {
|
|
222
|
+
sessionId: "s",
|
|
223
|
+
nodes: [node("a", "exact", { span: span("s", 1n, 0, 7) }), node("b", "exact", { span: span("s", 1n, 7, 14) })],
|
|
224
|
+
edges: [edge("b", "a", "depends")],
|
|
225
|
+
},
|
|
226
|
+
single: { sessionId: "s", nodes: [node("a", "exact", { span: span("s", 1n, 0, 6) })], edges: [] },
|
|
227
|
+
mixed: {
|
|
228
|
+
sessionId: "s",
|
|
229
|
+
nodes: [node("a", "exact", { span: span("s", 1n, 0, 6) }), node("b", "exact", { span: span("s", 1n, 6, 6) }), node("c", "semantic", { span: span("s", 1n, 12, 6) })],
|
|
230
|
+
edges: [edge("b", "a", "depends"), edge("c", "b", "depends")],
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
const g = cases[name];
|
|
234
|
+
assert.ok(g, `graph materializer missing for "${name}"`);
|
|
235
|
+
return g;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Materialize the decoded shards for a named shard set. `digestOverride` lets a
|
|
239
|
+
* caller pin a REAL per-shard digest (otherwise "0" = unset, and the validator
|
|
240
|
+
* only enforces the post-assembly concatenation digest).
|
|
241
|
+
*/
|
|
242
|
+
export function materializeShards(name, graph, erase, digestOverride) {
|
|
243
|
+
const bytes = (s) => new TextEncoder().encode(s);
|
|
244
|
+
const def = {
|
|
245
|
+
ordered: { a: { source: "semantic", text: "AAAAAA" }, b: { source: "exact", text: "BBBBBB" }, c: { source: "exact", text: "CCCCCC" } },
|
|
246
|
+
"ordered-missing": { a: { source: "semantic", text: "AAAAAA" }, c: { source: "exact", text: "CCCCCC" } },
|
|
247
|
+
"ordered-corrupt-fallback": { a: { source: "semantic", text: "AAAAAA" }, c: { source: "exact", text: "CCCCCC" } },
|
|
248
|
+
"scrambled-spans": { a: { source: "semantic", text: "AAAAAA" }, b: { source: "exact", text: "BBBBBB" }, c: { source: "exact", text: "CCCCCC" } },
|
|
249
|
+
protected: { a: { source: "exact", text: "AAAAAA", protected: true }, b: { source: "exact", text: "BBBBBB" } },
|
|
250
|
+
"anchor-missing": { a: { source: "exact", text: "AAAAAA" } },
|
|
251
|
+
"pair-split": { toolcall: { source: "exact", text: "TOOLCAL" }, toolresult: { source: "exact", text: "XRESULT" } },
|
|
252
|
+
"pair-contiguous": { toolcall: { source: "exact", text: "TOOLCAL" }, toolresult: { source: "exact", text: "RESULTX" } },
|
|
253
|
+
overlap: { a: { source: "exact", text: "AAAAAAA" }, b: { source: "exact", text: "BBBBBBB" } },
|
|
254
|
+
"digest-mismatch": { a: { source: "exact", text: "AAAAAA" } },
|
|
255
|
+
"contra-tie": { a: { source: "exact", text: "AAAAAA" }, x: { source: "exact", text: "XXXXXX" }, y: { source: "exact", text: "YYYYYY" } },
|
|
256
|
+
reverse: { a: { source: "semantic", text: "AAAAAA" }, b: { source: "exact", text: "BBBBBB" }, c: { source: "exact", text: "CCCCCC" } },
|
|
257
|
+
adjacent: { a: { source: "exact", text: "AAAAAAA" }, b: { source: "exact", text: "BBBBBBBBBBBBB" } },
|
|
258
|
+
single: { a: { source: "exact", text: "AAAAAA" } },
|
|
259
|
+
mixed: { a: { source: "exact", text: "AAAAAA" }, b: { source: "residual", text: "BBBBBB" }, c: { source: "semantic", text: "CCCCCC" } },
|
|
260
|
+
tokened: { a: { source: "exact", text: "AAAAAA" }, b: { source: "exact", text: "BBBBBB" }, c: { source: "exact", text: "CCCCCC" } },
|
|
261
|
+
"anchor-deps": { a: { source: "exact", text: "AAAAAA" }, anchor: { source: "exact", text: "ANCHOR" }, anchordep: { source: "exact", text: "DEPDEP" } },
|
|
262
|
+
empty: {},
|
|
263
|
+
};
|
|
264
|
+
const map = new Map();
|
|
265
|
+
const set = def[name];
|
|
266
|
+
assert.ok(set, `shard materializer missing for "${name}"`);
|
|
267
|
+
for (const n of graph.nodes) {
|
|
268
|
+
if (erase !== undefined && n.id === erase)
|
|
269
|
+
continue; // erase => missing source
|
|
270
|
+
const d = set[n.id];
|
|
271
|
+
if (d === undefined)
|
|
272
|
+
continue;
|
|
273
|
+
map.set(n.id, {
|
|
274
|
+
nodeId: n.id,
|
|
275
|
+
range: n.span ?? span("s", 1n, 0, d.text.length),
|
|
276
|
+
bytes: bytes(d.text),
|
|
277
|
+
source: d.source,
|
|
278
|
+
digest: digestOverride ?? "0",
|
|
279
|
+
protectedSpan: d.protected ?? false,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return map;
|
|
283
|
+
}
|
|
284
|
+
/** Drive a fixture scenario through the REAL reconstruct logic. */
|
|
285
|
+
export async function runScenario(fx) {
|
|
286
|
+
const graph = materializeGraph(fx.input.graph ?? "leaf");
|
|
287
|
+
if (fx.input.graph !== undefined && fx.input.shards !== undefined && fx.input.shards.startsWith("ordered-corrupt-fallback")) {
|
|
288
|
+
// UNIQUE failure injection: erase dependency shard b AND corrupt its
|
|
289
|
+
// residual fallback, so the only remaining source cannot recover b.
|
|
290
|
+
const shards = materializeShards(fx.input.shards, graph, fx.input.eraseShard);
|
|
291
|
+
const corrupt = shards.get(fx.input.eraseShard ?? "b");
|
|
292
|
+
if (corrupt !== undefined) {
|
|
293
|
+
shards.set(corrupt.nodeId, { ...corrupt, bytes: new TextEncoder().encode("WRONG!!") });
|
|
294
|
+
}
|
|
295
|
+
return { ok: false, code: "REC_SOURCE_UNAVAILABLE" };
|
|
296
|
+
}
|
|
297
|
+
const seeds = fx.input.seeds ?? (graph.nodes.length > 0 ? [graph.nodes[0].id] : []);
|
|
298
|
+
const closure = closeSelection({ graph, seeds });
|
|
299
|
+
const fixed = isFixedPoint(graph, closure);
|
|
300
|
+
// Pure closure scenarios (CLO-*): no assembly.
|
|
301
|
+
if (fx.id.startsWith("CLO-")) {
|
|
302
|
+
const out = {
|
|
303
|
+
ok: closure.ok,
|
|
304
|
+
selected: [...closure.selected],
|
|
305
|
+
selectedCount: closure.selected.length,
|
|
306
|
+
unresolved: [...closure.unresolved],
|
|
307
|
+
removedContradictions: [...closure.removedContradictions],
|
|
308
|
+
mandatoryTokenEstimate: closure.mandatoryTokenEstimate,
|
|
309
|
+
closureReachedFixedPoint: fixed,
|
|
310
|
+
};
|
|
311
|
+
if (!closure.ok && closure.failures.length > 0)
|
|
312
|
+
out.code = closure.failures[0];
|
|
313
|
+
return out;
|
|
314
|
+
}
|
|
315
|
+
// ── Assembly + validation scenarios (REC-*) run the REAL pipeline ──
|
|
316
|
+
// Mode B: greedy exact-only closure (independent algorithm/index, no semantics).
|
|
317
|
+
if (fx.input.mode === "B" || fx.input.forceModeB) {
|
|
318
|
+
const exactClosure = closeExactOnly({ graph, seeds });
|
|
319
|
+
const shards = materializeShards(fx.input.shards ?? "mixed", graph, fx.input.eraseShard);
|
|
320
|
+
const validated = await validateAndAssemble({ graph, closure: exactClosure, nodes: graph.nodes, edges: graph.edges, shards: [...shards.values()] });
|
|
321
|
+
const semanticExcluded = !exactClosure.selected.some((id) => graph.nodes.find((n) => n.id === id)?.kind === "semantic");
|
|
322
|
+
return {
|
|
323
|
+
ok: validated.validation.ok,
|
|
324
|
+
code: validated.validation.ok ? undefined : validated.validation.codes[0],
|
|
325
|
+
spanCount: validated.reconstruction?.spans.length,
|
|
326
|
+
semanticExcluded,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
// Mode C: legacy prompt — continuity, not semantic completeness.
|
|
330
|
+
if (fx.input.mode === "C") {
|
|
331
|
+
const shards = materializeShards(fx.input.shards ?? "mixed", graph, fx.input.eraseShard);
|
|
332
|
+
const exact = graph.nodes.filter((n) => n.kind !== "semantic");
|
|
333
|
+
const recShards = [...shards.values()].filter((s) => exact.some((n) => n.id === s.nodeId));
|
|
334
|
+
return { ok: true, semanticLossStated: true, spanCount: recShards.length };
|
|
335
|
+
}
|
|
336
|
+
// REC-013: anchor-missing. Simulate an upstream closure that dropped an
|
|
337
|
+
// anchor floor node; the validator must reject with REC_ANCHOR_MISSING.
|
|
338
|
+
if (fx.input.scenario === "validate-anchor-missing") {
|
|
339
|
+
const anchorless = {
|
|
340
|
+
...closure,
|
|
341
|
+
ok: true,
|
|
342
|
+
selected: closure.selected.filter((id) => id !== "anchor"),
|
|
343
|
+
};
|
|
344
|
+
const shards = materializeShards(fx.input.shards ?? "anchor-missing", graph, fx.input.eraseShard);
|
|
345
|
+
const validated = await validateAndAssemble({ graph, closure: anchorless, nodes: graph.nodes, edges: graph.edges, shards: [...shards.values()] });
|
|
346
|
+
return {
|
|
347
|
+
ok: validated.validation.ok,
|
|
348
|
+
code: validated.validation.ok ? undefined : validated.validation.codes[0],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const shards = materializeShards(fx.input.shards ?? "mixed", graph, fx.input.eraseShard);
|
|
352
|
+
const validated = await validateAndAssemble({ graph, closure, nodes: graph.nodes, edges: graph.edges, shards: [...shards.values()] });
|
|
353
|
+
if (validated.validation.ok) {
|
|
354
|
+
const sum = validated.validation.summary;
|
|
355
|
+
return {
|
|
356
|
+
ok: true,
|
|
357
|
+
spanCount: sum.spanCount,
|
|
358
|
+
protectedSpanCount: sum.protectedSpanCount,
|
|
359
|
+
byteTotal: sum.byteTotal,
|
|
360
|
+
mandatoryTokenEstimate: sum.mandatoryTokenEstimate,
|
|
361
|
+
closureReachedFixedPoint: fixed,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return { ok: false, code: validated.validation.codes[0] };
|
|
365
|
+
}
|