pi-mega-compact 0.20.70 → 0.20.72
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/extensions/dashboard-server/routes-setup-cortex.js +7 -1
- package/dist/extensions/dashboard-server/routes-vector-cortex-crystals.js +45 -30
- package/dist/extensions/dashboard-server/routes-vector-cortex-diagnostics.js +50 -29
- package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +33 -20
- package/dist/extensions/dashboard-server/routes-vector-cortex-helpers.js +54 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-policy.js +33 -16
- package/dist/src/vector-cortex/cache/store.js +25 -2
- package/dist/src/vector-cortex/encoder/asset.js +34 -2
- package/dist/src/vector-cortex/encoder/router.js +31 -3
- package/dist/src/vector-cortex/livewire/livewire-live.js +163 -0
- package/dist/src/vector-cortex/livewire/livewire-registry.js +73 -0
- package/dist/src/vector-cortex/livewire/livewire-runtime.js +107 -0
- package/dist/src/vector-cortex/livewire/livewire-snapshot.js +101 -0
- package/dist/src/vector-cortex/livewire/livewire-types.js +19 -0
- package/dist/src/vector-cortex/provider/registry.js +44 -12
- package/dist/src/vector-cortex/setup-cortex-blockers-compute.js +43 -7
- package/dist/vector-cortex/cache/store.js +25 -2
- package/dist/vector-cortex/encoder/asset.js +34 -2
- package/dist/vector-cortex/encoder/router.js +31 -3
- package/dist/vector-cortex/provider/registry.js +44 -12
- package/dist/vector-cortex/setup-cortex-blockers-compute.js +43 -7
- package/extensions/dashboard-server/routes-setup-cortex.ts +8 -1
- package/extensions/dashboard-server/routes-vector-cortex-crystals.ts +46 -30
- package/extensions/dashboard-server/routes-vector-cortex-diagnostics.ts +52 -29
- package/extensions/dashboard-server/routes-vector-cortex-economics.ts +35 -20
- package/extensions/dashboard-server/routes-vector-cortex-helpers.ts +84 -0
- package/extensions/dashboard-server/routes-vector-cortex-policy.ts +35 -16
- package/package.json +1 -1
- package/src/vector-cortex/cache/store.ts +26 -2
- package/src/vector-cortex/encoder/asset.ts +46 -3
- package/src/vector-cortex/encoder/router.ts +56 -2
- package/src/vector-cortex/encoder/types.ts +3 -0
- package/src/vector-cortex/livewire/livewire-live.ts +223 -0
- package/src/vector-cortex/livewire/livewire-registry.ts +91 -0
- package/src/vector-cortex/livewire/livewire-runtime.ts +117 -0
- package/src/vector-cortex/livewire/livewire-snapshot.ts +108 -0
- package/src/vector-cortex/livewire/livewire-types.ts +84 -0
- package/src/vector-cortex/provider/economics.ts +9 -31
- package/src/vector-cortex/provider/registry.ts +82 -11
- package/src/vector-cortex/provider/types.ts +37 -0
- package/src/vector-cortex/setup-cortex-blockers-compute.ts +48 -7
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-live.ts — LIVEWIRE in-process live state.
|
|
3
|
+
*
|
|
4
|
+
* Holds the LIVE subsystem objects for ONE stateDir: the VC7A `CrystalStore`,
|
|
5
|
+
* the VC7C cache breaker, the per-miss-class tallies, the VC8B shadow metrics,
|
|
6
|
+
* and the VC7B economics computed bit. This is the object the RUNTIME accumulates
|
|
7
|
+
* into (`recordMiss`, `recordServeBlocked`, `recordShadowRun`, ...) and that the
|
|
8
|
+
* reader-only dashboard routes snapshot out of. Kept separate from the registry
|
|
9
|
+
* (which owns the per-stateDir `Map` + persistence) so neither file crosses the
|
|
10
|
+
* 300-line soft-as-hard gate.
|
|
11
|
+
*
|
|
12
|
+
* AGGREGATE-FIRST, COUNTS ONLY. `snapshotOf` projects the live objects down to
|
|
13
|
+
* the SECURITY_PRIVACY-safe `LivewireSnapshot` (counts + codes + triad mode) that
|
|
14
|
+
* gets persisted and rendered. No session id, digest, range, profile id, bytes,
|
|
15
|
+
* or prompt text can pass through ANY of these fields.
|
|
16
|
+
*
|
|
17
|
+
* PREVENT-PI-004: no network. PREVENT-011: no `any`. Non-fatal: every derive is
|
|
18
|
+
* a pure read.
|
|
19
|
+
*/
|
|
20
|
+
import { CrystalStore } from "../cache/store.js";
|
|
21
|
+
import { createCacheBreaker } from "../cache/breaker.js";
|
|
22
|
+
import { validateProfileEconomics } from "../provider/economics.js";
|
|
23
|
+
import { BASE_PROVIDER_PROFILES } from "../provider/registry.js";
|
|
24
|
+
/**
|
|
25
|
+
* Static VC7B economics profile tallies derived from the base provider registry.
|
|
26
|
+
* `profileCount` counts profiles that declare economics; `provenExclusions` /
|
|
27
|
+
* `unprovenExclusions` tally the exclusion sets validated against the fixture
|
|
28
|
+
* rule. This is PURE (no storage/clock/network) and identical regardless of the
|
|
29
|
+
* `MEGACOMPACT_VC7B` flag — only the emission/route seam is flag-gated.
|
|
30
|
+
*/
|
|
31
|
+
function baseEconomicsTallies() {
|
|
32
|
+
let profileCount = 0;
|
|
33
|
+
let provenExclusions = 0;
|
|
34
|
+
let unprovenExclusions = 0;
|
|
35
|
+
for (const bundle of BASE_PROVIDER_PROFILES) {
|
|
36
|
+
const econ = bundle.profile.economics;
|
|
37
|
+
if (econ === null)
|
|
38
|
+
continue;
|
|
39
|
+
profileCount += 1;
|
|
40
|
+
const codes = validateProfileEconomics(bundle.profile, econ);
|
|
41
|
+
const failed = new Set(codes);
|
|
42
|
+
for (const _ex of bundle.profile.excludedJsonPointers) {
|
|
43
|
+
if (failed.has("ECON_EXCLUSION_UNPROVEN")) {
|
|
44
|
+
unprovenExclusions += 1;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
provenExclusions += 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { profileCount, provenExclusions, unprovenExclusions };
|
|
52
|
+
}
|
|
53
|
+
/** A zeroed per-class tally map. */
|
|
54
|
+
function zeroTallies() {
|
|
55
|
+
return {
|
|
56
|
+
profile: 0,
|
|
57
|
+
range: 0,
|
|
58
|
+
dependency: 0,
|
|
59
|
+
request: 0,
|
|
60
|
+
generation: 0,
|
|
61
|
+
unknown: 0,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Build a fresh (empty) live state with real subsystem objects. */
|
|
65
|
+
export function createLiveState() {
|
|
66
|
+
const econTallies = baseEconomicsTallies();
|
|
67
|
+
return {
|
|
68
|
+
crystalStore: new CrystalStore(),
|
|
69
|
+
breaker: createCacheBreaker(),
|
|
70
|
+
diagnostics: {
|
|
71
|
+
tallies: zeroTallies(),
|
|
72
|
+
serveBlocked: 0,
|
|
73
|
+
breakerState: "CLOSED_A",
|
|
74
|
+
lastFailure: null,
|
|
75
|
+
},
|
|
76
|
+
economics: {
|
|
77
|
+
computed: false,
|
|
78
|
+
profileCount: econTallies.profileCount,
|
|
79
|
+
provenExclusions: econTallies.provenExclusions,
|
|
80
|
+
unprovenExclusions: econTallies.unprovenExclusions,
|
|
81
|
+
lastFailure: null,
|
|
82
|
+
},
|
|
83
|
+
shadow: {
|
|
84
|
+
shadowDecisions: 0,
|
|
85
|
+
clampedDecisions: 0,
|
|
86
|
+
rejectedInputs: 0,
|
|
87
|
+
liveMutations: 0,
|
|
88
|
+
pressureVersion: 1,
|
|
89
|
+
lastFailure: null,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Project the live state down to the persisted, reader-only aggregate. */
|
|
94
|
+
export function snapshotOf(state) {
|
|
95
|
+
const crystals = state.crystalStore.stats();
|
|
96
|
+
const diag = {
|
|
97
|
+
profileMisses: state.diagnostics.tallies.profile,
|
|
98
|
+
rangeMisses: state.diagnostics.tallies.range,
|
|
99
|
+
dependencyMisses: state.diagnostics.tallies.dependency,
|
|
100
|
+
requestMisses: state.diagnostics.tallies.request,
|
|
101
|
+
generationMisses: state.diagnostics.tallies.generation,
|
|
102
|
+
unknownMisses: state.diagnostics.tallies.unknown,
|
|
103
|
+
serveBlocked: state.diagnostics.serveBlocked,
|
|
104
|
+
breakerState: state.diagnostics.breakerState,
|
|
105
|
+
lastFailure: state.diagnostics.lastFailure,
|
|
106
|
+
};
|
|
107
|
+
const econ = {
|
|
108
|
+
profileCount: state.economics.profileCount,
|
|
109
|
+
provenExclusions: state.economics.provenExclusions,
|
|
110
|
+
unprovenExclusions: state.economics.unprovenExclusions,
|
|
111
|
+
computed: state.economics.computed,
|
|
112
|
+
lastFailure: state.economics.lastFailure,
|
|
113
|
+
};
|
|
114
|
+
const policy = {
|
|
115
|
+
shadowDecisions: state.shadow.shadowDecisions,
|
|
116
|
+
clampedDecisions: state.shadow.clampedDecisions,
|
|
117
|
+
rejectedInputs: state.shadow.rejectedInputs,
|
|
118
|
+
liveMutations: state.shadow.liveMutations,
|
|
119
|
+
pressureVersion: state.shadow.pressureVersion,
|
|
120
|
+
lastFailure: state.shadow.lastFailure,
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
schema: "vector-cortex-livewire-v1",
|
|
124
|
+
crystals: {
|
|
125
|
+
mode: crystals.mode,
|
|
126
|
+
crystalCount: crystals.crystalCount,
|
|
127
|
+
totalBytes: crystals.totalBytes,
|
|
128
|
+
hits: crystals.hits,
|
|
129
|
+
misses: crystals.misses,
|
|
130
|
+
hitBytes: crystals.hitBytes,
|
|
131
|
+
writes: crystals.writes,
|
|
132
|
+
duplicateWrites: crystals.duplicateWrites,
|
|
133
|
+
collisions: crystals.collisions,
|
|
134
|
+
},
|
|
135
|
+
diagnostics: diag,
|
|
136
|
+
economics: econ,
|
|
137
|
+
policy,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Seed a fresh live state's CUMULATIVE counters from a persisted snapshot. */
|
|
141
|
+
export function rehydrateLive(state, snap) {
|
|
142
|
+
state.crystalStore.rehydrate(snap.crystals);
|
|
143
|
+
state.diagnostics.tallies.profile = snap.diagnostics.profileMisses;
|
|
144
|
+
state.diagnostics.tallies.range = snap.diagnostics.rangeMisses;
|
|
145
|
+
state.diagnostics.tallies.dependency = snap.diagnostics.dependencyMisses;
|
|
146
|
+
state.diagnostics.tallies.request = snap.diagnostics.requestMisses;
|
|
147
|
+
state.diagnostics.tallies.generation = snap.diagnostics.generationMisses;
|
|
148
|
+
state.diagnostics.tallies.unknown = snap.diagnostics.unknownMisses;
|
|
149
|
+
state.diagnostics.serveBlocked = snap.diagnostics.serveBlocked;
|
|
150
|
+
state.diagnostics.breakerState = snap.diagnostics.breakerState;
|
|
151
|
+
state.diagnostics.lastFailure = snap.diagnostics.lastFailure;
|
|
152
|
+
state.economics.computed = snap.economics.computed;
|
|
153
|
+
state.economics.profileCount = snap.economics.profileCount;
|
|
154
|
+
state.economics.provenExclusions = snap.economics.provenExclusions;
|
|
155
|
+
state.economics.unprovenExclusions = snap.economics.unprovenExclusions;
|
|
156
|
+
state.economics.lastFailure = snap.economics.lastFailure;
|
|
157
|
+
state.shadow.shadowDecisions = snap.policy.shadowDecisions;
|
|
158
|
+
state.shadow.clampedDecisions = snap.policy.clampedDecisions;
|
|
159
|
+
state.shadow.rejectedInputs = snap.policy.rejectedInputs;
|
|
160
|
+
state.shadow.liveMutations = snap.policy.liveMutations;
|
|
161
|
+
state.shadow.pressureVersion = snap.policy.pressureVersion;
|
|
162
|
+
state.shadow.lastFailure = snap.policy.lastFailure;
|
|
163
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-registry.ts — per-stateDir LIWIRE registry.
|
|
3
|
+
*
|
|
4
|
+
* The single seam the runtime and the reader-only dashboard routes BOTH access.
|
|
5
|
+
* It owns a `Map<stateDir, LivewireLiveState>` (one live subsystem cluster per
|
|
6
|
+
* repo) and lazily opens a state on first access, rehydrating its cumulative
|
|
7
|
+
* counters from the persisted aggregate snapshot (`livewire-snapshot.ts`) so a
|
|
8
|
+
* freshly-spawned process — e.g. the dashboard server — reports the same counts
|
|
9
|
+
* the runtime has already accumulated.
|
|
10
|
+
*
|
|
11
|
+
* The runtime WRITES through this registry (see `livewire-runtime.ts`): each
|
|
12
|
+
* mutation persists a reduced, count-only snapshot. The routes READ through
|
|
13
|
+
* `livewireOf(stateDir)` and call the pure `snapshotOf`. There is no other path.
|
|
14
|
+
*
|
|
15
|
+
* BEST-EFFORT + NON-FATAL. `openLivewire` never throws: persistence failures are
|
|
16
|
+
* swallowed by the snapshot layer and state is always returned. PREVENT-PI-004
|
|
17
|
+
* (local in-process Map + filesystem only), PREVENT-011 (no `any`).
|
|
18
|
+
*/
|
|
19
|
+
import { createLiveState, rehydrateLive, snapshotOf, } from "./livewire-live.js";
|
|
20
|
+
import { loadLivewireSnapshot, saveLivewireSnapshot, } from "./livewire-snapshot.js";
|
|
21
|
+
/** The per-stateDir registry (process-local; a fresh process starts empty). */
|
|
22
|
+
const REGISTRY = new Map();
|
|
23
|
+
let activeLogger;
|
|
24
|
+
/**
|
|
25
|
+
* Bind the structured logger the snapshot layer uses for its non-fatal write
|
|
26
|
+
* failures. The runtime calls this once at startup with its JSON logger.
|
|
27
|
+
*/
|
|
28
|
+
export function setLivewireLogger(logger) {
|
|
29
|
+
activeLogger = logger;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Open (or return the cached) live state for a stateDir. Lazy: on first access
|
|
33
|
+
* it rehydrates from the persisted aggregate so a separate dashboard process
|
|
34
|
+
* reflects prior runtime work. Never throws.
|
|
35
|
+
*/
|
|
36
|
+
export function livewireOf(stateDir) {
|
|
37
|
+
const cached = REGISTRY.get(stateDir);
|
|
38
|
+
if (cached !== undefined)
|
|
39
|
+
return cached;
|
|
40
|
+
const state = createLiveState();
|
|
41
|
+
const snap = loadLivewireSnapshot(stateDir);
|
|
42
|
+
if (snap !== null)
|
|
43
|
+
rehydrateLive(state, snap);
|
|
44
|
+
REGISTRY.set(stateDir, state);
|
|
45
|
+
return state;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Persist a state's reduced aggregate (counts + codes only). Best-effort and
|
|
49
|
+
* non-fatal. Called by the runtime after every mutation so the snapshot stays
|
|
50
|
+
* fresh for any reader process.
|
|
51
|
+
*/
|
|
52
|
+
export function persistLivewire(state, stateDir) {
|
|
53
|
+
saveLivewireSnapshot(stateDir, snapshotOf(state), activeLogger);
|
|
54
|
+
}
|
|
55
|
+
/** Persist the live state for a stateDir (convenience over open + persist). */
|
|
56
|
+
export function flushLivewire(stateDir) {
|
|
57
|
+
const state = REGISTRY.get(stateDir);
|
|
58
|
+
if (state === undefined)
|
|
59
|
+
return;
|
|
60
|
+
persistLivewire(state, stateDir);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the reader aggregate for one stateDir WITHOUT persisting — the reader
|
|
64
|
+
* seam the dashboard routes call. Reads the live state (rehydrated from disk on
|
|
65
|
+
* first access) and projects it to the count-only snapshot.
|
|
66
|
+
*/
|
|
67
|
+
export function readLivewireSnapshot(stateDir) {
|
|
68
|
+
return snapshotOf(livewireOf(stateDir));
|
|
69
|
+
}
|
|
70
|
+
/** For tests: drop the registry so a fresh stateDir is fully rehydrated. */
|
|
71
|
+
export function _resetLivewireRegistryForTests() {
|
|
72
|
+
REGISTRY.clear();
|
|
73
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-runtime.ts — LIVEWIRE runtime accumulation seam.
|
|
3
|
+
*
|
|
4
|
+
* The WRITE side of LIVEWIRE: the runtime calls these methods wherever the
|
|
5
|
+
* corresponding subsystem path actually runs, and each call accumulates into the
|
|
6
|
+
* per-stateDir live state and persists a reduced count-only snapshot (best-effort,
|
|
7
|
+
* non-fatal). This is the seam that turns the pure VC7A/VC7B/VC7C/VC8B arithmetic
|
|
8
|
+
* into LIVE dashboard state.
|
|
9
|
+
*
|
|
10
|
+
* FLAG SEMANTICS (mirrors every other VC writer): these methods run REGARDLESS of
|
|
11
|
+
* the corresponding `MEGACOMPACT_VC*` flag — the arithmetic is never skipped, and
|
|
12
|
+
* a miss is still classified / a write still stored exactly as before. Only the
|
|
13
|
+
* dashboard REPORT seam (`routes-vector-cortex-*.ts`) is flag-gated: with the
|
|
14
|
+
* flag off a route returns the legacy `deferredReason` (byte-identical to the
|
|
15
|
+
* predecessor). The reporter emit seams in `cache/*-emit.ts` / `controller/
|
|
16
|
+
* policy-emit.ts` remain the event-announcement gate.
|
|
17
|
+
*
|
|
18
|
+
* PREVENT-PI-004: no network. PREVENT-011: no `any`. Every write is best-effort.
|
|
19
|
+
*/
|
|
20
|
+
import { classifyMiss } from "../cache/diagnostics.js";
|
|
21
|
+
import { shouldBlockServe } from "../cache/breaker.js";
|
|
22
|
+
import { livewireOf, persistLivewire } from "./livewire-registry.js";
|
|
23
|
+
/**
|
|
24
|
+
* Record a VC7A crystal WRITE attempt (write-once + collision arithmetic). The
|
|
25
|
+
* caller passes the fully-formed `CrystalV1`; the store returns the write result
|
|
26
|
+
* (first-write / idempotent / collision). The dashboard's `stats()` reflects it.
|
|
27
|
+
*
|
|
28
|
+
* @returns the store's write verdict, forwarded so the runtime can act on a
|
|
29
|
+
* collision without re-deriving it.
|
|
30
|
+
*/
|
|
31
|
+
export function recordCrystalWrite(stateDir, crystal) {
|
|
32
|
+
const state = livewireOf(stateDir);
|
|
33
|
+
const result = state.crystalStore.write(crystal);
|
|
34
|
+
persistLivewire(state, stateDir);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Record a VC7A crystal READ attempt. Returns the stored crystal (or undefined
|
|
39
|
+
* on a miss / mode C), mirroring `CrystalStore.read` so the cache-serve path can
|
|
40
|
+
* use this seam entirely.
|
|
41
|
+
*/
|
|
42
|
+
export function readCrystal(stateDir, keyDigest) {
|
|
43
|
+
const state = livewireOf(stateDir);
|
|
44
|
+
const found = state.crystalStore.read(keyDigest);
|
|
45
|
+
persistLivewire(state, stateDir);
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Record a VC7C miss observation: classify it into its exclusive class and tally
|
|
50
|
+
* it. When the class demands the cache serve be demoted BEFORE answering, the
|
|
51
|
+
* `serveBlocked` counter is also incremented. The live breaker state itself is
|
|
52
|
+
* driven by the real cache-serve path (through `breaker.execute`), not here; this
|
|
53
|
+
* seam only observes and tallies.
|
|
54
|
+
*
|
|
55
|
+
* @returns the exclusive class the observation was tallied under.
|
|
56
|
+
*/
|
|
57
|
+
export function observeCacheMiss(stateDir, observation) {
|
|
58
|
+
const state = livewireOf(stateDir);
|
|
59
|
+
const missClass = classifyMiss(observation).missClass;
|
|
60
|
+
state.diagnostics.tallies[missClass] += 1;
|
|
61
|
+
if (shouldBlockServe(missClass))
|
|
62
|
+
state.diagnostics.serveBlocked += 1;
|
|
63
|
+
persistLivewire(state, stateDir);
|
|
64
|
+
return missClass;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Record a VC7C cache serve that the breaker demoted BEFORE answering. Talls the
|
|
68
|
+
* `serveBlocked` counter the diagnostics card surfaces.
|
|
69
|
+
*/
|
|
70
|
+
export function recordServeBlocked(stateDir) {
|
|
71
|
+
const state = livewireOf(stateDir);
|
|
72
|
+
state.diagnostics.serveBlocked += 1;
|
|
73
|
+
persistLivewire(state, stateDir);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Record a VC8B shadow evaluation run: accumulate its decision metrics so the
|
|
77
|
+
* policy card reports how many shadow decisions were evaluated / clamped /
|
|
78
|
+
* rejected and how many live mutations the shadow proved (structurally 0).
|
|
79
|
+
*/
|
|
80
|
+
export function recordShadowRun(stateDir, result) {
|
|
81
|
+
const state = livewireOf(stateDir);
|
|
82
|
+
state.shadow.shadowDecisions += result.metrics.evaluated;
|
|
83
|
+
state.shadow.clampedDecisions += result.metrics.clamped;
|
|
84
|
+
state.shadow.rejectedInputs += result.metrics.rejected;
|
|
85
|
+
state.shadow.liveMutations += result.metrics.liveMutations;
|
|
86
|
+
persistLivewire(state, stateDir);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Set the active M7 pressure version (1 = legacy, 2 = migrated). The runtime
|
|
90
|
+
* calls this after a successful `migratePressureV2` so the policy card reflects
|
|
91
|
+
* the live migration state rather than a hardcoded 1.
|
|
92
|
+
*/
|
|
93
|
+
export function setPressureVersion(stateDir, version) {
|
|
94
|
+
const state = livewireOf(stateDir);
|
|
95
|
+
state.shadow.pressureVersion = version;
|
|
96
|
+
persistLivewire(state, stateDir);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Mark that VC7B cache economics have actually been computed at runtime (the
|
|
100
|
+
* `computed` bit drives the economics card's `hasData`). The runtime calls this
|
|
101
|
+
* after the first real `computeEconomics` over observed usage.
|
|
102
|
+
*/
|
|
103
|
+
export function markEconomicsComputed(stateDir) {
|
|
104
|
+
const state = livewireOf(stateDir);
|
|
105
|
+
state.economics.computed = true;
|
|
106
|
+
persistLivewire(state, stateDir);
|
|
107
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-snapshot.ts — LIVEWIRE aggregate persistence.
|
|
3
|
+
*
|
|
4
|
+
* The four LV subsytems are in-process live objects, but the dashboard server may
|
|
5
|
+
* run in a SEPARATE process from the runtime that accumulates the counts. To keep
|
|
6
|
+
* the reader-only routes honest when they run in their own process, this module
|
|
7
|
+
* persists a COUNT-ONLY aggregate snapshot (`vector-cortex-livewire.json`) to the
|
|
8
|
+
* per-repo `stateDir`, and `openLivewire` rehydrates a fresh process from it on
|
|
9
|
+
* first access. This is the same DR-snapshot philosophy as the legacy JSON
|
|
10
|
+
* checkpoints, but reduced to counts + codes (SECURITY_PRIVACY — see these types).
|
|
11
|
+
*
|
|
12
|
+
* BEST-EFFORT + NON-FATAL. A failed write is logged as a structured event and
|
|
13
|
+
* never breaks the agent loop; a missing/unreadable snapshot reads as null and
|
|
14
|
+
* the process starts from zero (matches the non-fatal-stores invariant). Every
|
|
15
|
+
* write is atomic-ish: the JSON is fully serialized to a temp name then renamed
|
|
16
|
+
* so a reader never observes a partial snapshot.
|
|
17
|
+
*
|
|
18
|
+
* PREVENT-PI-004: local filesystem read/write only, no network. PREVENT-011: no
|
|
19
|
+
* `any`.
|
|
20
|
+
*/
|
|
21
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
/** The snapshot filename in the per-repo stateDir (counts + codes only). */
|
|
24
|
+
export const LIVEWIRE_SNAPSHOT_FILE = "vector-cortex-livewire.json";
|
|
25
|
+
/** Resolve the snapshot path for a stateDir. */
|
|
26
|
+
export function livewireSnapshotPath(stateDir) {
|
|
27
|
+
return join(stateDir, LIVEWIRE_SNAPSHOT_FILE);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Best-effort type guard over a parsed snapshot. Rejects anything that is not
|
|
31
|
+
* the exact aggregate shape so a corrupted or stale file cannot poison the
|
|
32
|
+
* rehydrated counters.
|
|
33
|
+
*/
|
|
34
|
+
function isSnapshot(value) {
|
|
35
|
+
if (typeof value !== "object" || value === null)
|
|
36
|
+
return false;
|
|
37
|
+
const s = value;
|
|
38
|
+
return (s.schema === "vector-cortex-livewire-v1" &&
|
|
39
|
+
typeof s.crystals === "object" &&
|
|
40
|
+
s.crystals !== null &&
|
|
41
|
+
typeof s.diagnostics === "object" &&
|
|
42
|
+
s.diagnostics !== null &&
|
|
43
|
+
typeof s.economics === "object" &&
|
|
44
|
+
s.economics !== null &&
|
|
45
|
+
typeof s.policy === "object" &&
|
|
46
|
+
s.policy !== null);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the persisted aggregate for a stateDir, or null when absent/unreadable/
|
|
50
|
+
* malformed. Best-effort and non-fatal by construction.
|
|
51
|
+
*/
|
|
52
|
+
export function loadLivewireSnapshot(stateDir) {
|
|
53
|
+
const path = livewireSnapshotPath(stateDir);
|
|
54
|
+
let raw;
|
|
55
|
+
try {
|
|
56
|
+
raw = readFileSync(path, "utf-8");
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(raw);
|
|
63
|
+
return isSnapshot(parsed) ? parsed : null;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Best-effort write of the aggregate snapshot (atomic rename). Never throws to
|
|
71
|
+
* the caller: a persistence failure logs a structured event and is swallowed.
|
|
72
|
+
*
|
|
73
|
+
* @param logger optional structured logger `(line: unknown) => void`; when
|
|
74
|
+
* omitted no event is emitted (tests pass `undefined`).
|
|
75
|
+
*/
|
|
76
|
+
export function saveLivewireSnapshot(stateDir, snapshot, logger) {
|
|
77
|
+
const dir = stateDir;
|
|
78
|
+
try {
|
|
79
|
+
if (!existsSync(dir))
|
|
80
|
+
mkdirSync(dir, { recursive: true });
|
|
81
|
+
const path = livewireSnapshotPath(dir);
|
|
82
|
+
const tmp = `${path}.tmp`;
|
|
83
|
+
writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
|
|
84
|
+
renameSync(tmp, path);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if (logger !== undefined) {
|
|
88
|
+
try {
|
|
89
|
+
logger({
|
|
90
|
+
ts: new Date().toISOString(),
|
|
91
|
+
event: "vector_cortex_livewire_snapshot_write_failed",
|
|
92
|
+
stateDir,
|
|
93
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// A failing logger must not recurse into another failure.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/livewire/livewire-types.ts — LIVEWIRE aggregate snapshot types.
|
|
3
|
+
*
|
|
4
|
+
* LIVEWIRE wires the four complete-but-unwired Vector Cortex subsystems into the
|
|
5
|
+
* runtime so their dashboard routes report LIVE state instead of hardcoded
|
|
6
|
+
* "deferred" zeros. This module is the SINGLE SOURCE OF TRUTH for the persisted
|
|
7
|
+
* aggregate snapshot shape (counts + codes ONLY) and for the per-stateDir
|
|
8
|
+
* live-state records the routes read.
|
|
9
|
+
*
|
|
10
|
+
* SECURITY_PRIVACY: every field here is a count, a code, or a finite triad mode.
|
|
11
|
+
* There is deliberately NO string slot for a session id, a request/crystal
|
|
12
|
+
* digest, a covered range, frozen bytes, a profile id, or ledger content — a
|
|
13
|
+
* crystal IS a frozen rendered prompt, so the card that reports on it must never
|
|
14
|
+
* be able to carry one. The snapshot is the SAME reduced shape, so nothing secret
|
|
15
|
+
* reaches disk either.
|
|
16
|
+
*
|
|
17
|
+
* PREVENT-PI-004: type definitions only, no network code. PREVENT-011: no `any`.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
@@ -45,48 +45,80 @@ function baseCache(stableFields) {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
/** Build a contract-profile shape pinned as a conformance fixture too. */
|
|
48
|
-
function profile(id, version, excludedJsonPointers) {
|
|
48
|
+
function profile(id, version, excludedJsonPointers, economics) {
|
|
49
49
|
return {
|
|
50
50
|
schema: "provider-profile-v1",
|
|
51
51
|
id,
|
|
52
52
|
version,
|
|
53
53
|
hashMode: "entire-canonical-request",
|
|
54
54
|
excludedJsonPointers,
|
|
55
|
+
economics,
|
|
55
56
|
};
|
|
56
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Build integer micro-unit economics for a base profile (VC7B). A cache WRITE
|
|
60
|
+
* costs more than an uncached token, a cache READ costs less — the standard
|
|
61
|
+
* provider-prompt-cache shape. `exclusionFixtureId` mirrors the profile's own
|
|
62
|
+
* exclusion fixture (or null when the profile has none to prove).
|
|
63
|
+
*/
|
|
64
|
+
function econ(id, version, exclusionFixtureId, values) {
|
|
65
|
+
return {
|
|
66
|
+
schema: "provider-economics-v1",
|
|
67
|
+
profileId: id,
|
|
68
|
+
profileVersion: version,
|
|
69
|
+
basePrice: values.basePrice,
|
|
70
|
+
readPrice: values.readPrice,
|
|
71
|
+
writePrice: values.writePrice,
|
|
72
|
+
ttlMs: values.ttlMs,
|
|
73
|
+
minPrefix: values.minPrefix,
|
|
74
|
+
exclusionFixtureId,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Representative integer micro-unit economics for the Anthropic opus base tier. */
|
|
78
|
+
const OPUS_ECON = econ("anthropic-claude-opus", "v1", null, { basePrice: 15, readPrice: 2, writePrice: 19, ttlMs: 300_000, minPrefix: 1024 });
|
|
79
|
+
/** Representative integer micro-unit economics for the Anthropic sonnet base tier. */
|
|
80
|
+
const SONNET_ECON = econ("anthropic-claude-sonnet", "v1", null, { basePrice: 3, readPrice: 0, writePrice: 4, ttlMs: 300_000, minPrefix: 1024 });
|
|
81
|
+
/** Representative integer micro-unit economics for the OpenAI gpt base tier. */
|
|
82
|
+
const GPT_ECON = econ("openai-gpt", "v1", null, { basePrice: 5, readPrice: 1, writePrice: 6, ttlMs: 300_000, minPrefix: 1024 });
|
|
83
|
+
/** The gemini profile's versioned, fixture-proven exclusion. */
|
|
84
|
+
const GEMINI_EXCLUSIONS = [
|
|
85
|
+
{
|
|
86
|
+
pointer: "/requestId",
|
|
87
|
+
fixtureId: "PRO-EXCLUDE-010",
|
|
88
|
+
proofDigest: "sha256:excluded-request-id-proof",
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
/** Representative integer micro-unit economics for the gemini base tier. */
|
|
92
|
+
const GEMINI_ECON = econ("google-gemini", "v1", "PRO-EXCLUDE-010", { basePrice: 3, readPrice: 1, writePrice: 4, ttlMs: 300_000, minPrefix: 1024 });
|
|
57
93
|
/**
|
|
58
94
|
* The fixture-backed base profiles. Each entry is the REAL bundle the renderer
|
|
59
95
|
* resolves; the parallel conformance fixtures prove the cache-identity behavior.
|
|
60
96
|
*/
|
|
61
97
|
const BASE_PROFILES = [
|
|
62
98
|
{
|
|
63
|
-
profile: profile("anthropic-claude-opus", "v1", []),
|
|
99
|
+
profile: profile("anthropic-claude-opus", "v1", [], OPUS_ECON),
|
|
64
100
|
role: BASE_ROLE,
|
|
65
101
|
tool: BASE_TOOL,
|
|
66
102
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
67
103
|
},
|
|
68
104
|
{
|
|
69
|
-
profile: profile("anthropic-claude-sonnet", "v1", []),
|
|
105
|
+
profile: profile("anthropic-claude-sonnet", "v1", [], SONNET_ECON),
|
|
70
106
|
role: BASE_ROLE,
|
|
71
107
|
tool: BASE_TOOL,
|
|
72
108
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
73
109
|
},
|
|
74
110
|
{
|
|
75
|
-
profile: profile("openai-gpt", "v1", []),
|
|
111
|
+
profile: profile("openai-gpt", "v1", [], GPT_ECON),
|
|
76
112
|
role: BASE_ROLE,
|
|
77
113
|
tool: BASE_TOOL,
|
|
78
114
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
79
115
|
},
|
|
80
116
|
{
|
|
81
117
|
// A profile that proves a fixture-excluded pointer: a provider whose
|
|
82
|
-
// request-id header cannot affect cache identity. Excluded + versioned
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
fixtureId: "PRO-EXCLUDE-010",
|
|
87
|
-
proofDigest: "sha256:excluded-request-id-proof",
|
|
88
|
-
},
|
|
89
|
-
]),
|
|
118
|
+
// request-id header cannot affect cache identity. Excluded + versioned, and
|
|
119
|
+
// the exclusion fixture id is carried into economics so the proof is
|
|
120
|
+
// honored (an unproven exclusion would fail economics validation).
|
|
121
|
+
profile: profile("google-gemini", "v1", GEMINI_EXCLUSIONS, GEMINI_ECON),
|
|
90
122
|
role: BASE_ROLE,
|
|
91
123
|
tool: BASE_TOOL,
|
|
92
124
|
cache: baseCache(["systemPromptPrepend", "tools", "nodes"]),
|
|
@@ -14,9 +14,12 @@
|
|
|
14
14
|
* all-open, byte-identical to ENC-0f-era for flag-off). `computeSetupCortexBlockers`
|
|
15
15
|
* is a PURE function over (platform, ENC-0f QualificationV1 record, asset-manifest
|
|
16
16
|
* head-count) that returns the live blocker list: HG-1 closes on a five-head
|
|
17
|
-
* manifest (ENC-0c), HG-5 reflects the measured qualification verdict, HG-4
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* manifest (ENC-0c), HG-5 reflects the measured qualification verdict, HG-4 is
|
|
18
|
+
* superseded (upstream arm64-only darwin binary gap, ENC-0e demotion surface),
|
|
19
|
+
* HG-6 is superseded (4-thread mandate = runtime p95 gate), HG-7 closes (frozen
|
|
20
|
+
* model card / dataset manifest / calibration), HG-3 closes when native
|
|
21
|
+
* onnxruntime-node is installed (ENC-2a/2b). `setupCortexActionBlockers`
|
|
22
|
+
* re-derives VC9B
|
|
20
23
|
* action gating from the live computed blockers (intersects each action's
|
|
21
24
|
* static candidate gate ids with the currently-open blocker ids).
|
|
22
25
|
*
|
|
@@ -26,6 +29,7 @@
|
|
|
26
29
|
* never magic numbers in the computed path.
|
|
27
30
|
*/
|
|
28
31
|
import { ENCODER_HEAD_ORDER, ENCODER_LATENCY_P95_MS, ENCODER_RSS_BUDGET_BYTES, } from "./encoder/types.js";
|
|
32
|
+
import { INSTALL_BUDGET_DEFAULT_MIB } from "./encoder/decision.js";
|
|
29
33
|
const MIB = 1024 * 1024;
|
|
30
34
|
/**
|
|
31
35
|
* Marker threshold-failure emitted by the status route when NO QualificationV1
|
|
@@ -100,14 +104,20 @@ export function setupCortexBlocker(id) {
|
|
|
100
104
|
* - HG-1 → `"closed"` when the asset manifest declares all five projection
|
|
101
105
|
* heads (`headCount === ENCODER_HEAD_ORDER.length`); otherwise stays open.
|
|
102
106
|
* - HG-3 → unchanged (genuinely open — onnxruntime-node budget unresolved).
|
|
103
|
-
* - HG-4 →
|
|
104
|
-
*
|
|
107
|
+
* - HG-4 → `"superseded"` (documented upstream platform gap — onnxruntime-node
|
|
108
|
+
* is arm64-only for darwin; ENC-0e ships the demotion surface, no code fix
|
|
109
|
+
* is possible).
|
|
105
110
|
* - HG-5 → derived from the qualification record: an empty record is
|
|
106
111
|
* `"superseded"` (no measurement on this device); a `failed` verdict closes
|
|
107
112
|
* it with the measured p95/RSS wording; a `qualified` verdict closes it with
|
|
108
113
|
* "measured" wording. Severity stays `"medium"` from the base row.
|
|
114
|
+
* - HG-6 → `"superseded"` (the 4-thread mandate is a runtime p95 gate enforced
|
|
115
|
+
* by the ENC-0f qualification bench — a platform failing the p95 threshold
|
|
116
|
+
* auto-demotes to mode B; no separate code surface needed).
|
|
117
|
+
* - HG-7 → `"closed"` (model card, dataset manifest, and VC2C calibration
|
|
118
|
+
* thresholds are all committed and frozen).
|
|
109
119
|
* `platform` is carried for contract symmetry with Worker B's route input; the
|
|
110
|
-
* HG rules here do not branch on it (
|
|
120
|
+
* HG rules here do not branch on it (the closures are unconditional).
|
|
111
121
|
*/
|
|
112
122
|
export function computeSetupCortexBlockers(input) {
|
|
113
123
|
const { qualification, headCount } = input;
|
|
@@ -117,10 +127,36 @@ export function computeSetupCortexBlockers(input) {
|
|
|
117
127
|
return headCount === ENCODER_HEAD_ORDER.length
|
|
118
128
|
? { ...base, status: "closed" }
|
|
119
129
|
: base;
|
|
130
|
+
case "HG-3":
|
|
131
|
+
// HG-3 is the install-budget gate: closes when native onnxruntime-node is
|
|
132
|
+
// installed (the ~101 MiB tarball fits within the 300 MiB default budget).
|
|
133
|
+
// The runtime p95/RSS qualification is HG-5's domain — this gate only asks
|
|
134
|
+
// "is the binding installed and within budget?".
|
|
135
|
+
if (input.nativeOrtInstalledVersion != null) {
|
|
136
|
+
return {
|
|
137
|
+
...base,
|
|
138
|
+
status: "closed",
|
|
139
|
+
resolution: `Native onnxruntime-node ${input.nativeOrtInstalledVersion} installed (~101 MiB, within the ${INSTALL_BUDGET_DEFAULT_MIB} MiB budget). Runtime qualification is HG-5.`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return base;
|
|
120
143
|
case "HG-4":
|
|
121
144
|
return {
|
|
122
145
|
...base,
|
|
123
|
-
|
|
146
|
+
status: "superseded",
|
|
147
|
+
resolution: "Upstream onnxruntime-node ships arm64-only for darwin. ENC-0e ships the demotion surface: darwin-x64 users use the WASM path (mode B) or lexical fallback (mode C). No code fix is possible — the binary does not exist upstream.",
|
|
148
|
+
};
|
|
149
|
+
case "HG-6":
|
|
150
|
+
return {
|
|
151
|
+
...base,
|
|
152
|
+
status: "superseded",
|
|
153
|
+
resolution: "The 4-thread mandate is a runtime p95 gate enforced by the qualification bench (ENC-0f gate-qualify.mjs). A platform that fails the p95 latency threshold (40ms) is automatically demoted to mode B — no separate code surface needed. Low-core platforms are handled by the same qualification gate.",
|
|
154
|
+
};
|
|
155
|
+
case "HG-7":
|
|
156
|
+
return {
|
|
157
|
+
...base,
|
|
158
|
+
status: "closed",
|
|
159
|
+
resolution: "Model card (training/vector-cortex/model-card.json), dataset manifest (training/vector-cortex/dataset-manifest.json), and VC2C calibration thresholds (EVALUATION_THRESHOLDS in types-vc2c.ts) are all committed and frozen.",
|
|
124
160
|
};
|
|
125
161
|
case "HG-5":
|
|
126
162
|
if (qualification === null) {
|