pi-mega-compact 0.16.3 → 0.17.0
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 +81 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +30 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +4 -14
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex.js +12 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +10 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex.js +292 -0
- package/dist/extensions/dashboard-server/routes.js +1 -0
- package/dist/extensions/dashboard-server/server.js +9 -1
- package/dist/extensions/mega-events/context-handler.js +11 -0
- package/dist/extensions/mega-runtime/vector-cortex-ledger.js +131 -0
- package/dist/extensions/mega-runtime/vector-cortex-safety.js +100 -0
- package/dist/src/config/vector-cortex.js +81 -0
- package/dist/src/config.js +6 -0
- package/dist/src/vector-cortex/eval/annotations.js +41 -0
- package/dist/src/vector-cortex/eval/metrics.js +86 -0
- package/dist/src/vector-cortex/eval/observer.js +61 -0
- package/dist/src/vector-cortex/eval/persist.js +67 -0
- package/dist/src/vector-cortex/eval/reader.js +29 -0
- package/dist/src/vector-cortex/eval/types.js +33 -0
- package/dist/src/vector-cortex/ledger/adapter.js +55 -0
- package/dist/src/vector-cortex/ledger/compat-journal.js +206 -0
- package/dist/src/vector-cortex/ledger/emit.js +53 -0
- package/dist/src/vector-cortex/ledger/event-codec.js +72 -0
- package/dist/src/vector-cortex/ledger/event-codecB.js +76 -0
- package/dist/src/vector-cortex/ledger/sqlite.js +200 -0
- package/dist/src/vector-cortex/ledger/store.js +184 -0
- package/dist/src/vector-cortex/ledger/types.js +52 -0
- package/dist/src/vector-cortex/ledger/validator.js +117 -0
- package/dist/src/vector-cortex/migrations/effective-cut-v2.js +103 -0
- package/dist/src/vector-cortex/migrations/occurrence-v2.js +139 -0
- package/dist/src/vector-cortex/replay/cut.js +123 -0
- package/dist/src/vector-cortex/replay/emit.js +58 -0
- package/dist/src/vector-cortex/replay/replay.js +260 -0
- package/dist/src/vector-cortex/replay/replayB.js +73 -0
- package/dist/src/vector-cortex/replay/types.js +52 -0
- package/dist/src/vector-cortex/resilience/breaker-core.js +359 -0
- package/dist/src/vector-cortex/resilience/breaker.js +12 -0
- package/dist/src/vector-cortex/resilience/emit.js +56 -0
- package/dist/src/vector-cortex/resilience/spool-core.js +347 -0
- package/dist/src/vector-cortex/resilience/spool.js +12 -0
- package/dist/src/vector-cortex/resilience/types.js +32 -0
- package/dist/vector-cortex/eval/annotations.js +41 -0
- package/dist/vector-cortex/eval/metrics.js +86 -0
- package/dist/vector-cortex/eval/observer.js +61 -0
- package/dist/vector-cortex/eval/persist.js +67 -0
- package/dist/vector-cortex/eval/reader.js +29 -0
- package/dist/vector-cortex/eval/types.js +33 -0
- package/dist/vector-cortex/ledger/adapter.js +55 -0
- package/dist/vector-cortex/ledger/compat-journal.js +206 -0
- package/dist/vector-cortex/ledger/emit.js +53 -0
- package/dist/vector-cortex/ledger/event-codec.js +72 -0
- package/dist/vector-cortex/ledger/event-codecB.js +76 -0
- package/dist/vector-cortex/ledger/sqlite.js +200 -0
- package/dist/vector-cortex/ledger/store.js +184 -0
- package/dist/vector-cortex/ledger/types.js +52 -0
- package/dist/vector-cortex/ledger/validator.js +117 -0
- package/dist/vector-cortex/migrations/effective-cut-v2.js +103 -0
- package/dist/vector-cortex/migrations/occurrence-v2.js +139 -0
- package/dist/vector-cortex/replay/cut.js +123 -0
- package/dist/vector-cortex/replay/emit.js +58 -0
- package/dist/vector-cortex/replay/replay.js +260 -0
- package/dist/vector-cortex/replay/replayB.js +73 -0
- package/dist/vector-cortex/replay/types.js +52 -0
- package/dist/vector-cortex/resilience/breaker-core.js +359 -0
- package/dist/vector-cortex/resilience/breaker.js +12 -0
- package/dist/vector-cortex/resilience/emit.js +56 -0
- package/dist/vector-cortex/resilience/spool-core.js +347 -0
- package/dist/vector-cortex/resilience/spool.js +12 -0
- package/dist/vector-cortex/resilience/types.js +32 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js → AreaChart-CAnWomhw.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js.map → AreaChart-CAnWomhw.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js → BarChart-lZ2-s71k.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js.map → BarChart-lZ2-s71k.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js → CacheTab-BL2Thh66.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js.map → CacheTab-BL2Thh66.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js → EventsTab-DEh2Z9fp.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js.map → EventsTab-DEh2Z9fp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js → HealthTab-DTwKclxk.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js.map → HealthTab-DTwKclxk.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js → MaintenanceTab-DDfBEdbX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js.map → MaintenanceTab-DDfBEdbX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js → MemoryMapTab-Dgfmg-0Q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js.map → MemoryMapTab-Dgfmg-0Q.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js → MetricsTab-DOcMm0Tx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js.map → MetricsTab-DOcMm0Tx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js → OverviewTab-DHT5aoHg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js.map → OverviewTab-DHT5aoHg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js → ReposTab-CGAmtR_c.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js.map → ReposTab-CGAmtR_c.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js → SessionsTab-BIgx6iKT.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js.map → SessionsTab-BIgx6iKT.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js → SetupTab-ADghKuEI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js.map → SetupTab-ADghKuEI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js → TimeSavedCard-C33UiiOM.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js.map → TimeSavedCard-C33UiiOM.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js → TurnsTab-DdbL9wPN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js.map → TurnsTab-DdbL9wPN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Cl1pbEdR.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Cl1pbEdR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js → WikiTab-Ch00OFKs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js.map → WikiTab-Ch00OFKs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js → button-ByeEdo2g.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js.map → button-ByeEdo2g.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js → card-DesoLXvc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js.map → card-DesoLXvc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js → generateCategoricalChart-CCAB7Iz4.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js.map → generateCategoricalChart-CCAB7Iz4.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-B93cewiX.js → index-B6cgyAPr.js} +34 -29
- package/extensions/dashboard-client/dist/assets/index-B6cgyAPr.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CfvziyBi.css +1 -0
- package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js → switch-DIZC-oe-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js.map → switch-DIZC-oe-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js → toggle-CIoWaH2e.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js.map → toggle-CIoWaH2e.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js → useSSE-Bv4943l1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js.map → useSSE-Bv4943l1.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +2 -0
- package/extensions/dashboard-client/src/api/vector-cortex.ts +54 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +272 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +4 -1
- package/extensions/dashboard-client/src/types/vector-cortex.ts +84 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +67 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +4 -21
- package/extensions/dashboard-server/api-contracts/index.ts +3 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex.ts +136 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +35 -0
- package/extensions/dashboard-server/routes-vector-cortex.ts +332 -0
- package/extensions/dashboard-server/routes.ts +6 -0
- package/extensions/dashboard-server/server.ts +8 -0
- package/extensions/mega-events/context-handler.ts +16 -0
- package/extensions/mega-runtime/vector-cortex-ledger.ts +165 -0
- package/extensions/mega-runtime/vector-cortex-safety.ts +181 -0
- package/package.json +2 -1
- package/src/config/vector-cortex.ts +87 -0
- package/src/config.ts +27 -0
- package/src/vector-cortex/eval/annotations.ts +70 -0
- package/src/vector-cortex/eval/metrics.ts +113 -0
- package/src/vector-cortex/eval/observer.ts +86 -0
- package/src/vector-cortex/eval/persist.ts +73 -0
- package/src/vector-cortex/eval/reader.ts +45 -0
- package/src/vector-cortex/eval/types.ts +89 -0
- package/src/vector-cortex/ledger/adapter.ts +71 -0
- package/src/vector-cortex/ledger/compat-journal.ts +234 -0
- package/src/vector-cortex/ledger/emit.ts +86 -0
- package/src/vector-cortex/ledger/event-codec.ts +79 -0
- package/src/vector-cortex/ledger/event-codecB.ts +87 -0
- package/src/vector-cortex/ledger/sqlite.ts +265 -0
- package/src/vector-cortex/ledger/store.ts +380 -0
- package/src/vector-cortex/ledger/types.ts +141 -0
- package/src/vector-cortex/ledger/validator.ts +124 -0
- package/src/vector-cortex/migrations/effective-cut-v2.ts +149 -0
- package/src/vector-cortex/migrations/occurrence-v2.ts +192 -0
- package/src/vector-cortex/replay/cut.ts +169 -0
- package/src/vector-cortex/replay/emit.ts +89 -0
- package/src/vector-cortex/replay/replay.ts +308 -0
- package/src/vector-cortex/replay/replayB.ts +97 -0
- package/src/vector-cortex/replay/types.ts +145 -0
- package/src/vector-cortex/resilience/breaker-core.ts +444 -0
- package/src/vector-cortex/resilience/breaker.ts +22 -0
- package/src/vector-cortex/resilience/emit.ts +99 -0
- package/src/vector-cortex/resilience/spool-core.ts +411 -0
- package/src/vector-cortex/resilience/spool.ts +22 -0
- package/src/vector-cortex/resilience/types.ts +158 -0
- package/extensions/dashboard-client/dist/assets/index-B93cewiX.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-C_tCbOI0.css +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex-safety.ts — VC0C live safety envelope (VC0C, task 4 + 5).
|
|
3
|
+
*
|
|
4
|
+
* Owns the live triad selection BEFORE provider invocation: select mode A
|
|
5
|
+
* (optimized/learned), then independent mode B (deterministic local spool
|
|
6
|
+
* deriving directly from authority), then unchanged mode C (continuity, not
|
|
7
|
+
* semantic completeness — C uses only the exact current transcript and reports
|
|
8
|
+
* that limitation). A manual reset clears cooldown but NEVER evidence.
|
|
9
|
+
*
|
|
10
|
+
* This adapter composes the resilience seams (`resilience/breaker.ts`,
|
|
11
|
+
* `resilience/spool.ts`, `resilience/emit.ts`) into the health/reset API the
|
|
12
|
+
* dashboard owns (`GET /api/vector-cortex/health`, admin
|
|
13
|
+
* `POST /api/vector-cortex/breakers/reset`). It is the pi-runtime-adjacent shell;
|
|
14
|
+
* all durable state is owned by the src/ resilience modules. Non-fatal: any
|
|
15
|
+
* breaker/spool noise degrades to mode C (unchanged host transcript), and the
|
|
16
|
+
* agent loop is never broken.
|
|
17
|
+
*
|
|
18
|
+
* Local-only (PREVENT-PI-004); no `any` (PREVENT-011); no console.log — events
|
|
19
|
+
* go through the injected resilience reporter / Logger.
|
|
20
|
+
*
|
|
21
|
+
* LIVENESS HONESTY (VC0C-Q01/Q06): the breaker composed here is PER-PROCESS /
|
|
22
|
+
* IN-MEMORY and EPHEMERAL — `createVectorCortexSafety` builds a fresh instance on
|
|
23
|
+
* every dashboard request (GET /health, POST /reset). There is NO persistent
|
|
24
|
+
* breaker runtime and NO live producer wiring (the real circuit-breaker that runs
|
|
25
|
+
* around the actual compaction loop is DEFERRED to the producer-wiring sprint,
|
|
26
|
+
* carried VC0B-I08 -> VC0D). Consequently GET /health always reflects a brand-new
|
|
27
|
+
* CLOSED_A instance and POST /reset mutates an instance that vanishes when the
|
|
28
|
+
* request returns: the endpoints are ILLUSTRATIVE until VC0D wires a persistent
|
|
29
|
+
* instance. The health payload therefore carries `stateSource:"ephemeral"` so the
|
|
30
|
+
* dashboard/README never present it as a live breaker. Frontier-frozen / spool-lag
|
|
31
|
+
* are owned by the DURABLE spool but have no live per-session handle here, so they
|
|
32
|
+
* are surfaced as static/non-live until VC0D (with authorityOutage mirrored from
|
|
33
|
+
* the host context when supplied).
|
|
34
|
+
*/
|
|
35
|
+
import { join } from "node:path";
|
|
36
|
+
import { createResilienceReporter } from "../../src/vector-cortex/resilience/emit.js";
|
|
37
|
+
import { createBreaker } from "../../src/vector-cortex/resilience/breaker.js";
|
|
38
|
+
import { createSpool } from "../../src/vector-cortex/resilience/spool.js";
|
|
39
|
+
import { BREAKER_WINDOW_MS, VC0C_ENABLED } from "../../src/config/vector-cortex.js";
|
|
40
|
+
/** Build the live safety envelope, wiring the emit seam into the breaker. */
|
|
41
|
+
export function createVectorCortexSafety(ctx, emit) {
|
|
42
|
+
const reporter = createResilienceReporter(emit);
|
|
43
|
+
const wallNow = ctx.wallNow ?? (() => new Date().toISOString());
|
|
44
|
+
const breaker = createBreaker({ now: ctx.now, reporter, wallNow });
|
|
45
|
+
const spool = createSpool({
|
|
46
|
+
dir: join(ctx.stateDir, "spool"),
|
|
47
|
+
authorityOutage: ctx.authorityOutage,
|
|
48
|
+
// Wire the resilience emit seam (incl. vector_cortex_frontier_frozen) into
|
|
49
|
+
// the mode-B spool so a real authority-frontier freeze is observable.
|
|
50
|
+
reporter,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
spool,
|
|
54
|
+
select(provider) {
|
|
55
|
+
const { subsystem, inputDigest, runA, runB, runC, validate } = provider;
|
|
56
|
+
// Thin delegation to the breaker: it selects the highest healthy mode
|
|
57
|
+
// (A, else independent B, else unchanged C) BEFORE provider invocation and
|
|
58
|
+
// records the attempt/trip. Across invocations A-failure demotes to B and
|
|
59
|
+
// B-failure demotes to C (continuity — unchanged transcript).
|
|
60
|
+
return breaker.execute(subsystem, inputDigest, { A: runA, B: runB, C: runC }, validate);
|
|
61
|
+
},
|
|
62
|
+
health() {
|
|
63
|
+
const rec = breaker.snapshot("provider");
|
|
64
|
+
const enabled = VC0C_ENABLED();
|
|
65
|
+
// LIVENESS HONESTY (VC0C-Q01/Q06): this breaker is created fresh per request
|
|
66
|
+
// and is ephemeral — declare it explicitly so the dashboard never presents it
|
|
67
|
+
// as a live breaker. `authorityOutage` is mirrored from the host context when
|
|
68
|
+
// supplied (otherwise false). `frontierFrozen` (rec.frozenFrontier) and
|
|
69
|
+
// `spoolLag` are owned by the DURABLE spool, which has no live per-session
|
|
70
|
+
// handle here — they stay static/no-op until VC0D wires a persistent breaker
|
|
71
|
+
// instance; stateSource:"ephemeral" is the signal that they are not live.
|
|
72
|
+
return {
|
|
73
|
+
enabled,
|
|
74
|
+
mode: rec.state === "MANUAL_HALT" ? "C" : rec.state === "CLOSED_A" ? "A" : "B",
|
|
75
|
+
state: rec.state,
|
|
76
|
+
subsystem: "provider",
|
|
77
|
+
sinceMs: rec.transitionedAtMs,
|
|
78
|
+
reason: rec.manualReason,
|
|
79
|
+
windowMs: BREAKER_WINDOW_MS,
|
|
80
|
+
probeCount: rec.probeCount,
|
|
81
|
+
backoffDelayMs: rec.retryDelayMs,
|
|
82
|
+
frontierFrozen: rec.frozenFrontier,
|
|
83
|
+
authorityOutage: ctx.authorityOutage?.() ?? false,
|
|
84
|
+
spoolLag: 0,
|
|
85
|
+
attempts: rec.attempts,
|
|
86
|
+
failures: rec.failures,
|
|
87
|
+
p95Ms: rec.p95Ms,
|
|
88
|
+
failureRate: rec.failureRate,
|
|
89
|
+
updatedAt: wallNow(),
|
|
90
|
+
stateSource: "ephemeral",
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
reset(subsystem) {
|
|
94
|
+
return breaker.reset(subsystem);
|
|
95
|
+
},
|
|
96
|
+
halt(reason) {
|
|
97
|
+
return breaker.manualHalt(reason);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex.ts — vector-cortex feature flags + breaker/triad constants.
|
|
3
|
+
*
|
|
4
|
+
* Every sprint ships one positive `MEGACOMPACT_<SPRINT>` flag, default ON and
|
|
5
|
+
* `=0`/`_DISABLED` off. Flag-OFF is byte-identical to the predecessor sprint's
|
|
6
|
+
* behavior (for VC0A: mode C — observer absent, zero evaluation writes).
|
|
7
|
+
*
|
|
8
|
+
* The breaker/triad constants (TRIAD_RESILIENCE.md) live here so VC0C consumes
|
|
9
|
+
* them without re-declaring the ownership boundary. Pi-agnostic, dependency-free.
|
|
10
|
+
*/
|
|
11
|
+
/** Positive sprint flag: `=0` or `_DISABLED=true` disables (default ON). */
|
|
12
|
+
function sprintFlag(name) {
|
|
13
|
+
const v = process.env[name];
|
|
14
|
+
if (v === "0" || v === "false")
|
|
15
|
+
return false;
|
|
16
|
+
const disabled = process.env[name + "_DISABLED"];
|
|
17
|
+
if (disabled === "true" || disabled === "1")
|
|
18
|
+
return false;
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
/** VC0A — baseline observability (MetricEventV1 / AnnotationV1). Default ON. */
|
|
22
|
+
export const VC0A_ENABLED = () => sprintFlag("MEGACOMPACT_VC0A");
|
|
23
|
+
/**
|
|
24
|
+
* VC0B — replay correctness (ReplayCutV2 / ReplayReportV2, M3 effective-cut-v2).
|
|
25
|
+
* Default ON. `MEGACOMPACT_VC0B=0` disables and is byte-identical to the
|
|
26
|
+
* predecessor (legacy capped-replay behavior preserved; the v2 cut/replay is
|
|
27
|
+
* only consulted on the vector-cortex path).
|
|
28
|
+
*/
|
|
29
|
+
export const VC0B_ENABLED = () => sprintFlag("MEGACOMPACT_VC0B");
|
|
30
|
+
/**
|
|
31
|
+
* VC1A — canonical byte events (EventV2 / EventCodec).
|
|
32
|
+
* Default ON. `MEGACOMPACT_VC1A=0` disables and is byte-identical to the
|
|
33
|
+
* predecessor (mode C: ledger absent, current transcript codec unchanged).
|
|
34
|
+
* The single real consumer is the ledger emit seam (`ledger/emit.ts`): flag OFF
|
|
35
|
+
* gates zero observability writes.
|
|
36
|
+
*/
|
|
37
|
+
export const VC1A_ENABLED = () => sprintFlag("MEGACOMPACT_VC1A");
|
|
38
|
+
/**
|
|
39
|
+
* VC1B — occurrence ledger + tool identity + compat journal (LedgerReader/
|
|
40
|
+
* Writer/Admin, CompatJournalV1, M2 occurrence-v2 migration).
|
|
41
|
+
* Default ON. `MEGACOMPACT_VC1B=0` disables and is byte-identical to the
|
|
42
|
+
* predecessor (mode C: the neutral occurrence ledger is not written, no
|
|
43
|
+
* journal rows, zero `vector_cortex_occurrence_appended` emissions). The real
|
|
44
|
+
* consumers are the ledger write integration seam and the compat-journal
|
|
45
|
+
* switch seam.
|
|
46
|
+
*/
|
|
47
|
+
export const VC1B_ENABLED = () => sprintFlag("MEGACOMPACT_VC1B");
|
|
48
|
+
/**
|
|
49
|
+
* VC0C — live safety envelope (TriadResult / Breaker / KillDecision + durable
|
|
50
|
+
* spool). Default ON. `MEGACOMPACT_VC0C=0` disables and is byte-identical to
|
|
51
|
+
* the predecessor (mode C: selected before provider invocation, unchanged host
|
|
52
|
+
* transcript, breaker/spool idle and emitting nothing). The single real
|
|
53
|
+
* consumer is the resilience emit seam + the safety adapter's triad selection.
|
|
54
|
+
*/
|
|
55
|
+
export const VC0C_ENABLED = () => sprintFlag("MEGACOMPACT_VC0C");
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker).
|
|
58
|
+
// Rolled numbers for one 60s window; VC0C consumes these at its breaker seam.
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
/** Rolling eligibility window (milliseconds). */
|
|
61
|
+
export const BREAKER_WINDOW_MS = 60_000;
|
|
62
|
+
/** Minimum attempts before a breaker may trip or promote. */
|
|
63
|
+
export const BREAKER_MIN_ATTEMPTS = 20;
|
|
64
|
+
/** Performance trip: ≥ this many failures in window, or ≥ this fraction. */
|
|
65
|
+
export const BREAKER_PERF_FAILURES = 5;
|
|
66
|
+
export const BREAKER_PERF_FAILURE_RATE = 0.1;
|
|
67
|
+
/** Correctness trip trips on the first correctness failure. */
|
|
68
|
+
export const BREAKER_CORRECTNESS_FAILURES = 1;
|
|
69
|
+
/** Cooldown before an open breaker may probe (milliseconds). */
|
|
70
|
+
export const BREAKER_COOLDOWN_MS = 30_000;
|
|
71
|
+
/** Consecutive successful probes required to advance a state. */
|
|
72
|
+
export const BREAKER_PROBE_COUNT = 3;
|
|
73
|
+
/** Exponential retry base: 30s * 2^attempt, capped, ±10% jitter. */
|
|
74
|
+
export const BREAKER_RETRY_BASE_MS = 30_000;
|
|
75
|
+
export const BREAKER_RETRY_CAP_MS = 15 * 60_000;
|
|
76
|
+
export const BREAKER_RETRY_JITTER = 0.1;
|
|
77
|
+
/** Promotion hysteresis: failure rate must be < this and p95 within budget. */
|
|
78
|
+
export const BREAKER_HYSTERESIS_FAILURE_RATE = 0.02;
|
|
79
|
+
export const BREAKER_HYSTERESIS_BUDGET_P95_MS = 50;
|
|
80
|
+
/** Minimum healthy residence before a further promotion (milliseconds). */
|
|
81
|
+
export const BREAKER_MIN_HEALTHY_RESIDENCE_MS = 5 * 60_000;
|
package/dist/src/config.js
CHANGED
|
@@ -109,3 +109,9 @@ export const RAG_MEMORY_GRAPH = () => ragEnabled("MEGACOMPACT_MEMORY_GRAPH");
|
|
|
109
109
|
export const RAG_HYDE_ENABLED = () => ragEnabled("MEGACOMPACT_HYDE");
|
|
110
110
|
/** Spec 1: vbrainstorm visual design migration for the dashboard. */
|
|
111
111
|
export const NEW_UI = () => ragEnabled("MEGACOMPACT_NEW_UI");
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Vector-cortex flags + breaker constants (VC0A+). Positive sprint flags,
|
|
114
|
+
// default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
|
|
115
|
+
// so root consumers share one source of truth.
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_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,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/annotations.ts — redaction metadata + JSONL serialization.
|
|
3
|
+
*
|
|
4
|
+
* Payload bytes, prompts, and exact ledger text are NEVER serialized. Before a
|
|
5
|
+
* JSONL line is written, each such field is replaced by a SHA-256 digest + byte
|
|
6
|
+
* count + redaction kind (EVAL-REDACT-002: prompt bytes never appear in JSONL).
|
|
7
|
+
* The redaction journal is itself the AnnotationV1 output.
|
|
8
|
+
*
|
|
9
|
+
* Uses node:crypto for the digest (pure local math, PREVENT-PI-004 safe).
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
/** SHA-256 over bytes, unpadded base64 (conformance canonical binary form). */
|
|
13
|
+
export function digestBytes(bytes) {
|
|
14
|
+
return createHash("sha256").update(bytes).digest("base64");
|
|
15
|
+
}
|
|
16
|
+
/** Replace every raw content field with its digest/count metadata. */
|
|
17
|
+
export function redactAnnotation(itemId, contents) {
|
|
18
|
+
const redactions = contents.map((c) => ({
|
|
19
|
+
field: c.field,
|
|
20
|
+
digest: digestBytes(c.bytes),
|
|
21
|
+
bytes: c.bytes.byteLength,
|
|
22
|
+
kind: c.kind,
|
|
23
|
+
}));
|
|
24
|
+
return {
|
|
25
|
+
itemId,
|
|
26
|
+
redactions,
|
|
27
|
+
redactedCount: redactions.length,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Serialize one set of raw contents to a single redacted JSONL line. Returns
|
|
32
|
+
* the annotation with its digest metadata and the JSONL text; the raw bytes
|
|
33
|
+
* never appear in the returned string.
|
|
34
|
+
*/
|
|
35
|
+
export function serializeRedactedJsonl(itemId, contents) {
|
|
36
|
+
const annotation = redactAnnotation(itemId, contents);
|
|
37
|
+
return {
|
|
38
|
+
annotation,
|
|
39
|
+
jsonl: `${JSON.stringify(annotation)}\n`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/metrics.ts — canonical metric ordering + fixed histogram.
|
|
3
|
+
*
|
|
4
|
+
* 1. Stable sort rows by `(session, seq, event)` — session string byte order,
|
|
5
|
+
* then integer seq ascending, then event-name byte order as tiebreak
|
|
6
|
+
* (EVAL-ORDER-003: equal seq rows use event-name order).
|
|
7
|
+
* 2. Bucket latency values at exactly 1/5/10/25/50/100/250ms with inclusive
|
|
8
|
+
* boundaries (EVAL-BUCKET-001); values past 250ms kept in a separate
|
|
9
|
+
* overflow bucket. Histogram totals are permutation-stable.
|
|
10
|
+
*
|
|
11
|
+
* Pure/no side effects (PREVENT-PI-004).
|
|
12
|
+
*/
|
|
13
|
+
import { LATENCY_BUCKETS } from "./types.js";
|
|
14
|
+
/** Inclusive-boundary bucket edges, with a sentinel past the largest edge. */
|
|
15
|
+
const EDGES = LATENCY_BUCKETS;
|
|
16
|
+
const OVERFLOW_INDEX = EDGES.length;
|
|
17
|
+
/** Histogram cell counts aligned to EDGES, plus a trailing overflow cell. */
|
|
18
|
+
export function emptyHistogram() {
|
|
19
|
+
return new Array(EDGES.length + 1).fill(0);
|
|
20
|
+
}
|
|
21
|
+
/** True when a sample carries a latency (`unit === "ms"`) datum. */
|
|
22
|
+
export function isLatencySample(m) {
|
|
23
|
+
return m.unit === "ms";
|
|
24
|
+
}
|
|
25
|
+
/** Bucket a latency ms value into a cell index (0..EDGES.length, last=overflow). */
|
|
26
|
+
export function bucketIndex(value) {
|
|
27
|
+
if (!Number.isFinite(value) || value < 0)
|
|
28
|
+
return OVERFLOW_INDEX;
|
|
29
|
+
for (let i = 0; i < EDGES.length; i++) {
|
|
30
|
+
if (value <= EDGES[i])
|
|
31
|
+
return i; // inclusive upper boundary
|
|
32
|
+
}
|
|
33
|
+
return OVERFLOW_INDEX;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Bucket latency sample values across all rows into the fixed histogram.
|
|
37
|
+
* Overflow is kept separate (counted in `overflow` and the trailing cell).
|
|
38
|
+
*/
|
|
39
|
+
export function bucketHistogram(rows) {
|
|
40
|
+
const cells = emptyHistogram();
|
|
41
|
+
let overflow = 0;
|
|
42
|
+
for (const m of rows) {
|
|
43
|
+
if (!isLatencySample(m))
|
|
44
|
+
continue;
|
|
45
|
+
const idx = bucketIndex(m.value);
|
|
46
|
+
cells[idx] += 1;
|
|
47
|
+
if (idx === EDGES.length)
|
|
48
|
+
overflow += 1;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
cells,
|
|
52
|
+
edges: [...EDGES],
|
|
53
|
+
overflow,
|
|
54
|
+
total: cells.reduce((a, b) => a + b, 0),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Stable sort MetricEventV1 rows by `(session, seq, event)`:
|
|
59
|
+
* - session: UTF-8 / JS string byte order;
|
|
60
|
+
* - seq: ascending numeric;
|
|
61
|
+
* - event: ascending string byte order (tiebreak for equal seq).
|
|
62
|
+
* Equal content stays separate occurrences (never deduplicated here).
|
|
63
|
+
*/
|
|
64
|
+
export function sortCanonical(rows) {
|
|
65
|
+
const out = [...rows];
|
|
66
|
+
out.sort((a, b) => {
|
|
67
|
+
const s = a.session < b.session ? -1 : a.session > b.session ? 1 : 0;
|
|
68
|
+
if (s !== 0)
|
|
69
|
+
return s;
|
|
70
|
+
if (a.seq !== b.seq)
|
|
71
|
+
return a.seq - b.seq;
|
|
72
|
+
return a.event < b.event ? -1 : a.event > b.event ? 1 : 0;
|
|
73
|
+
});
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Assisted sort plus histogram, returning both under one result.
|
|
78
|
+
* The observer (mode A) calls this before JSONL serialization.
|
|
79
|
+
*/
|
|
80
|
+
export function buildMetrics(rows) {
|
|
81
|
+
return {
|
|
82
|
+
rows: sortCanonical(rows),
|
|
83
|
+
histogram: bucketHistogram(rows),
|
|
84
|
+
rejects: [],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/observer.ts — VC0A structured observer (triad mode A).
|
|
3
|
+
*
|
|
4
|
+
* Connects to the evaluation reader: accepts MetricEventV1 samples, maintains
|
|
5
|
+
* the canonical `(session, seq, event)` ordered set plus the fixed latency
|
|
6
|
+
* histogram, and emits two structured local events:
|
|
7
|
+
* - vector_cortex_eval_sample_recorded (one per accepted sample)
|
|
8
|
+
* - vector_cortex_eval_redaction_rejected (when a redaction fails)
|
|
9
|
+
*
|
|
10
|
+
* Mode C (observer absent) is the responsibility of the caller: no observes(),
|
|
11
|
+
* no writes, byte-identical to the predecessor. This module never touches the
|
|
12
|
+
* network (PREVENT-PI-004) — it only manipulates in-memory rows and emits
|
|
13
|
+
* structured log lines through an injected logging callback so it stays
|
|
14
|
+
* pi-agnostic and deterministically testable.
|
|
15
|
+
*/
|
|
16
|
+
import { buildMetrics, sortCanonical } from "./metrics.js";
|
|
17
|
+
/**
|
|
18
|
+
* Build a structured observer (mode A). Best-effort: emitting never throws
|
|
19
|
+
* into the extension path (non-fatal observability).
|
|
20
|
+
*/
|
|
21
|
+
export function createEvalObserver(opts) {
|
|
22
|
+
const rows = [];
|
|
23
|
+
function emit(event, fields) {
|
|
24
|
+
try {
|
|
25
|
+
opts.emit(event, fields);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
/* non-fatal observability — never break the agent loop */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
record(sample) {
|
|
33
|
+
rows.push(sample);
|
|
34
|
+
if (opts.persist) {
|
|
35
|
+
try {
|
|
36
|
+
opts.persist(sample);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* non-fatal observability */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
emit("vector_cortex_eval_sample_recorded", {
|
|
43
|
+
session: sample.session,
|
|
44
|
+
seq: sample.seq,
|
|
45
|
+
event: sample.event,
|
|
46
|
+
unit: sample.unit,
|
|
47
|
+
mode: sample.mode,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
rejectRedaction(field, reason) {
|
|
51
|
+
emit("vector_cortex_eval_redaction_rejected", { field, reason });
|
|
52
|
+
},
|
|
53
|
+
rows() {
|
|
54
|
+
return sortCanonical(rows);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Aggregate metrics result from an observer's rows (canonical + histogram). */
|
|
59
|
+
export function observerMetrics(result) {
|
|
60
|
+
return buildMetrics(result.rows());
|
|
61
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/persist.ts — redacted eval JSONL persistence (VC0A).
|
|
3
|
+
*
|
|
4
|
+
* Bridges the in-memory observer (mode A) and the dashboard reader (separate
|
|
5
|
+
* process) via a disk JSONL under the state dir. Writes are append-only and
|
|
6
|
+
* hold only MetricEventV1 metric rows plus redaction metadata — never payloads,
|
|
7
|
+
* prompts, or exact ledger text (EVAL-REDACT-002). Best-effort and non-fatal
|
|
8
|
+
* (PREVENT-PI-004: local filesystem only; no network).
|
|
9
|
+
*
|
|
10
|
+
* PREVENT-011: no `any` type.
|
|
11
|
+
*/
|
|
12
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
/** Location of the redacted evaluation JSONL under a state dir. */
|
|
15
|
+
export function evalJsonlPath(stateDir) {
|
|
16
|
+
return join(stateDir, "vector-cortex", "evaluation.jsonl");
|
|
17
|
+
}
|
|
18
|
+
/** Append one redacted metric row as a canonical JSON line (append-only). */
|
|
19
|
+
export function appendEvalRow(stateDir, row) {
|
|
20
|
+
try {
|
|
21
|
+
const path = evalJsonlPath(stateDir);
|
|
22
|
+
mkdirSync(join(stateDir, "vector-cortex"), { recursive: true, mode: 0o700 });
|
|
23
|
+
// PER_EVAL_PERMISSION: 0600 file inherits state-dir permission policy.
|
|
24
|
+
writeFileSync(path, row.map((r) => `${JSON.stringify(r)}\n`).join(""), {
|
|
25
|
+
flag: "a",
|
|
26
|
+
mode: 0o600,
|
|
27
|
+
});
|
|
28
|
+
// guardrails-allow PREVENT-PI-004: local filesystem eval JSONL (no network)
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
/* non-fatal observability — never break the agent loop */
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Read every redacted metric row from the JSONL. Malformed or truncated final
|
|
36
|
+
* lines are skipped (callers surface EVAL_JSONL_TRUNCATED); the caller decides
|
|
37
|
+
* whether that is fatal. Returns an empty array when the file is absent.
|
|
38
|
+
*/
|
|
39
|
+
export function readEvalRows(stateDir) {
|
|
40
|
+
const out = [];
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = readFileSync(evalJsonlPath(stateDir), "utf8");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
for (const line of raw.split("\n")) {
|
|
49
|
+
if (line.trim().length === 0)
|
|
50
|
+
continue;
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(line);
|
|
53
|
+
if (typeof parsed.session === "string" &&
|
|
54
|
+
typeof parsed.seq === "number" &&
|
|
55
|
+
typeof parsed.event === "string" &&
|
|
56
|
+
typeof parsed.value === "number" &&
|
|
57
|
+
typeof parsed.unit === "string" &&
|
|
58
|
+
(parsed.mode === "A" || parsed.mode === "B" || parsed.mode === "C")) {
|
|
59
|
+
out.push(parsed);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* malformed line — skip; EVAL_JSONL_TRUNCATED surfaced by caller */
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/reader.ts — evaluation reader (aggregate-only).
|
|
3
|
+
*
|
|
4
|
+
* Reader-only capability: `summarizeEvalRows` collapses a set of MetricEventV1
|
|
5
|
+
* rows into an aggregate summary for the dashboard `GET /api/vector-cortex/
|
|
6
|
+
* evaluation` endpoint. No writable capability — the observer writes via its
|
|
7
|
+
* own path; this reader never mutates. Predecessor (flag-off / mode C) emits
|
|
8
|
+
* an empty summary byte-identical to "no data".
|
|
9
|
+
*
|
|
10
|
+
* Pure + local, zero network (PREVENT-PI-004).
|
|
11
|
+
*/
|
|
12
|
+
import { buildMetrics } from "./metrics.js";
|
|
13
|
+
/** Aggregate rows into a reader-only summary (histogram + per-mode counts). */
|
|
14
|
+
export function summarizeEvalRows(rows) {
|
|
15
|
+
const byMode = { A: 0, B: 0, C: 0 };
|
|
16
|
+
for (const r of rows)
|
|
17
|
+
byMode[r.mode] += 1;
|
|
18
|
+
const metrics = buildMetrics(rows);
|
|
19
|
+
return {
|
|
20
|
+
samples: rows.length,
|
|
21
|
+
byMode,
|
|
22
|
+
histogram: {
|
|
23
|
+
edges: metrics.histogram.edges,
|
|
24
|
+
cells: metrics.histogram.cells,
|
|
25
|
+
overflow: metrics.histogram.overflow,
|
|
26
|
+
total: metrics.histogram.total,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/eval/types.ts — MetricEventV1 / AnnotationV1 contract types
|
|
3
|
+
* and the registered EVAL conformance ID range (EVAL-001..010).
|
|
4
|
+
*
|
|
5
|
+
* Owned by VC0A (baseline observability). Consumes reviewer-accepted predecessor
|
|
6
|
+
* contracts and common contracts only. These are pure type/schema definitions —
|
|
7
|
+
* no runtime network, no side effects (PREVENT-PI-004 / PREVENT-011).
|
|
8
|
+
*/
|
|
9
|
+
/** Units the evaluator understands. Unknown units reject as EVAL_UNIT_UNKNOWN. */
|
|
10
|
+
export const UNITS = ["ms", "bytes", "count", "ratio"];
|
|
11
|
+
/**
|
|
12
|
+
* Histogram bucket edges for latency, in milliseconds, inclusive on both
|
|
13
|
+
* boundaries (EVAL-BUCKET-001): values at exactly 1ms and 250ms land in
|
|
14
|
+
* those buckets. Overflow (value > largest edge) is kept separate.
|
|
15
|
+
*/
|
|
16
|
+
export const LATENCY_BUCKETS = [1, 5, 10, 25, 50, 100, 250];
|
|
17
|
+
/**
|
|
18
|
+
* Registered EVAL conformance ID range (EVAL-001..010). The acceptance test
|
|
19
|
+
* reads these rows from the v2 manifest and asserts their expected bytes/results.
|
|
20
|
+
* Registered BEFORE evaluation logic so the manifest/fixture seam is stable.
|
|
21
|
+
*/
|
|
22
|
+
export const EVAL_IDS = [
|
|
23
|
+
"EVAL-001",
|
|
24
|
+
"EVAL-002",
|
|
25
|
+
"EVAL-003",
|
|
26
|
+
"EVAL-004",
|
|
27
|
+
"EVAL-005",
|
|
28
|
+
"EVAL-006",
|
|
29
|
+
"EVAL-007",
|
|
30
|
+
"EVAL-008",
|
|
31
|
+
"EVAL-009",
|
|
32
|
+
"EVAL-010",
|
|
33
|
+
];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/ledger/adapter.ts — EventV2 ledger adapter (VC1A, task 5).
|
|
3
|
+
*
|
|
4
|
+
* A thin, pi-agnostic adapter combining the Mode-A codec, the canonical
|
|
5
|
+
* validator, and the VC1A emit seam so `vector_cortex_event_decoded` and
|
|
6
|
+
* `vector_cortex_event_validation_failed` are emitted by REAL code paths (not a
|
|
7
|
+
* hand-invoked reporter), gated by `VC1A_ENABLED()` inside `createLedgerReporter`.
|
|
8
|
+
*
|
|
9
|
+
* The live producer (wiring this into `extensions/mega-compact.ts` /
|
|
10
|
+
* `src/engine.ts`) is deferred to VC1C/VC1B (mirroring VC0B-I08); this sprint
|
|
11
|
+
* ships the seam + adapter as the clean single surface, with the acceptance
|
|
12
|
+
* aggregator exercising the real gated-emission path.
|
|
13
|
+
*
|
|
14
|
+
* Pure orchestration — no storage, no network, no side effects (PREVENT-PI-004).
|
|
15
|
+
*/
|
|
16
|
+
import { createEventCodec } from "./event-codec.js";
|
|
17
|
+
import { validateEvents } from "./validator.js";
|
|
18
|
+
import { createLedgerReporter } from "./emit.js";
|
|
19
|
+
/** Build the ledger adapter over an injected emit callback (optional). */
|
|
20
|
+
export function createLedgerAdapter(emit) {
|
|
21
|
+
const codec = createEventCodec();
|
|
22
|
+
const reporter = createLedgerReporter(emit);
|
|
23
|
+
return {
|
|
24
|
+
encode: (input) => codec.encode(input),
|
|
25
|
+
decode(event) {
|
|
26
|
+
const bytes = codec.decode(event);
|
|
27
|
+
reporter.eventDecoded({
|
|
28
|
+
session: event.sessionId,
|
|
29
|
+
seq: event.seq.toString(),
|
|
30
|
+
eventId: event.eventId,
|
|
31
|
+
bytes: bytes.length,
|
|
32
|
+
utf8Valid: event.utf8.valid,
|
|
33
|
+
});
|
|
34
|
+
return bytes;
|
|
35
|
+
},
|
|
36
|
+
validate(events) {
|
|
37
|
+
const result = validateEvents(events);
|
|
38
|
+
if (!result.ok) {
|
|
39
|
+
// Emit one event per failing occurrence with its REAL locator — a
|
|
40
|
+
// consumer of the feed can identify WHICH event failed (VC1A-I05).
|
|
41
|
+
for (const issue of result.issues) {
|
|
42
|
+
reporter.validationFailed({
|
|
43
|
+
session: issue.sessionId,
|
|
44
|
+
seq: issue.seq.toString(),
|
|
45
|
+
eventId: issue.eventId,
|
|
46
|
+
code: issue.code,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
},
|
|
52
|
+
codec,
|
|
53
|
+
reporter,
|
|
54
|
+
};
|
|
55
|
+
}
|