pi-mega-compact 0.20.15 → 0.20.17
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 +14 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-diagnostics.js +35 -0
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-outcomes.js +13 -0
- package/dist/extensions/dashboard-server/route-dispatch.js +12 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-diagnostics.js +68 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-outcomes.js +79 -0
- package/dist/extensions/mega-dashboard.js +29 -9
- package/dist/src/config/vector-cortex.js +14 -0
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/cache/_diagnostics-fixture.js +31 -0
- package/dist/src/vector-cortex/cache/breaker.js +110 -0
- package/dist/src/vector-cortex/cache/diagnostics-emit.js +64 -0
- package/dist/src/vector-cortex/cache/diagnostics-types.js +15 -0
- package/dist/src/vector-cortex/cache/diagnostics.js +97 -0
- package/dist/src/vector-cortex/migrations/request-hash-v2-ops.js +17 -6
- package/dist/src/vector-cortex/outcomes/consent.js +69 -0
- package/dist/src/vector-cortex/outcomes/dataset.js +105 -0
- package/dist/src/vector-cortex/outcomes/emit.js +52 -0
- package/dist/src/vector-cortex/outcomes/ledger.js +77 -0
- package/dist/src/vector-cortex/outcomes/types.js +34 -0
- package/dist/vector-cortex/cache/_diagnostics-fixture.js +31 -0
- package/dist/vector-cortex/cache/breaker.js +110 -0
- package/dist/vector-cortex/cache/diagnostics-emit.js +64 -0
- package/dist/vector-cortex/cache/diagnostics-types.js +15 -0
- package/dist/vector-cortex/cache/diagnostics.js +97 -0
- package/dist/vector-cortex/migrations/request-hash-v2-ops.js +17 -6
- package/dist/vector-cortex/outcomes/consent.js +69 -0
- package/dist/vector-cortex/outcomes/dataset.js +105 -0
- package/dist/vector-cortex/outcomes/emit.js +52 -0
- package/dist/vector-cortex/outcomes/ledger.js +77 -0
- package/dist/vector-cortex/outcomes/types.js +34 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-CV8WqMmt.js → AreaChart-BOGp2sag.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-CV8WqMmt.js.map → AreaChart-BOGp2sag.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-M-HEBq9l.js → BarChart-BHgA-QPL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-M-HEBq9l.js.map → BarChart-BHgA-QPL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-DJ_yPAhP.js → CacheTab-6E7lwM74.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-DJ_yPAhP.js.map → CacheTab-6E7lwM74.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DNVlKzt6.js → EventsTab-BEtNmFHz.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DNVlKzt6.js.map → EventsTab-BEtNmFHz.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-B5yjuInb.js → HealthTab-DGxZulRH.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-B5yjuInb.js.map → HealthTab-DGxZulRH.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DoQedESF.js → MaintenanceTab-C86jppQE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DoQedESF.js.map → MaintenanceTab-C86jppQE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-CuL5CzdH.js → MemoryMapTab-J3VVxooZ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-CuL5CzdH.js.map → MemoryMapTab-J3VVxooZ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CZSTaCpK.js → MetricsTab-yn9AFumo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CZSTaCpK.js.map → MetricsTab-yn9AFumo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-vkZlXRW6.js → OverviewTab-BMarUiq3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-vkZlXRW6.js.map → OverviewTab-BMarUiq3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DgPD96rF.js → ReposTab-DxnzMive.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DgPD96rF.js.map → ReposTab-DxnzMive.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-XPbWh7XN.js → SessionsTab-DXKpDUuC.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-XPbWh7XN.js.map → SessionsTab-DXKpDUuC.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-Dz74XAtR.js → SetupTab-BctuV-CJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-Dz74XAtR.js.map → SetupTab-BctuV-CJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-FynCpJdx.js → TimeSavedCard-D8yOC96S.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-FynCpJdx.js.map → TimeSavedCard-D8yOC96S.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-C7m3GDy0.js → TurnsTab-BBxqGYH-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-C7m3GDy0.js.map → TurnsTab-BBxqGYH-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BTF1AGCJ.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BTF1AGCJ.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-C6viLa0u.js → WikiTab-DdJQSagO.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-C6viLa0u.js.map → WikiTab-DdJQSagO.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-mBEgbBVU.js → button-B4Q9h_8Y.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-mBEgbBVU.js.map → button-B4Q9h_8Y.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-CalUQAKG.js → card-WyR31hUV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-CalUQAKG.js.map → card-WyR31hUV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CMmkuwj5.js → generateCategoricalChart-pTio6Bq3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CMmkuwj5.js.map → generateCategoricalChart-pTio6Bq3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-Dz8GPBOE.js → index-BoLUiNsd.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-Dz8GPBOE.js.map → index-BoLUiNsd.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-8QKO6CTU.js → switch-5dieXxoo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-8QKO6CTU.js.map → switch-5dieXxoo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-9eCkWI4q.js → toggle-BFc-7_LL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-9eCkWI4q.js.map → toggle-BFc-7_LL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-s6IqOKoD.js → useSSE-BqmKNBAI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-s6IqOKoD.js.map → useSSE-BqmKNBAI.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/VectorCortexDiagnosticsCard.tsx +46 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexOutcomesCard.tsx +43 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +4 -0
- package/extensions/dashboard-client/src/tabs/useVectorCortexPoll.ts +5 -0
- package/extensions/dashboard-client/src/types/vector-cortex-vc8.ts +25 -0
- package/extensions/dashboard-client/src/types/vector-cortex.ts +2 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-diagnostics.ts +76 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-outcomes.ts +55 -0
- package/extensions/dashboard-server/route-dispatch.ts +10 -1
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/extensions/dashboard-server/routes-vector-cortex-diagnostics.ts +77 -0
- package/extensions/dashboard-server/routes-vector-cortex-outcomes.ts +94 -0
- package/extensions/mega-dashboard.ts +27 -8
- package/package.json +1 -1
- package/src/config/vector-cortex.ts +15 -0
- package/src/config.ts +1 -0
- package/src/vector-cortex/cache/_diagnostics-fixture.ts +32 -0
- package/src/vector-cortex/cache/breaker.ts +124 -0
- package/src/vector-cortex/cache/diagnostics-emit.ts +90 -0
- package/src/vector-cortex/cache/diagnostics-types.ts +87 -0
- package/src/vector-cortex/cache/diagnostics.ts +119 -0
- package/src/vector-cortex/migrations/request-hash-v2-ops.ts +15 -9
- package/src/vector-cortex/outcomes/consent.ts +88 -0
- package/src/vector-cortex/outcomes/dataset.ts +132 -0
- package/src/vector-cortex/outcomes/emit.ts +70 -0
- package/src/vector-cortex/outcomes/ledger.ts +88 -0
- package/src/vector-cortex/outcomes/types.ts +104 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-jRd_Iztk.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-jRd_Iztk.js.map +0 -1
|
@@ -211,6 +211,20 @@ export const VC7B_ENABLED = () => sprintFlag("MEGACOMPACT_VC7B");
|
|
|
211
211
|
* EXCLUDED_SETTINGS), mirroring VC4A..VC7B.
|
|
212
212
|
*/
|
|
213
213
|
export const VC7C_ENABLED = () => sprintFlag("MEGACOMPACT_VC7C");
|
|
214
|
+
/**
|
|
215
|
+
* VC8A — consent-bound outcome ledger + offline learning dataset. Default ON.
|
|
216
|
+
* `MEGACOMPACT_VC8A=0` disables and is byte-identical to the predecessor
|
|
217
|
+
* (VC7C): the outcome ledger, consent records, and dataset manifest builder
|
|
218
|
+
* STILL RUN (they are PURE — append-only validation, consent evaluation, and
|
|
219
|
+
* SHA-256 digests, with no clock, storage, or network), so an outcome is still
|
|
220
|
+
* validated identically and a consent revocation still excludes a row. The
|
|
221
|
+
* flag gates ONLY the `vector_cortex_outcome_appended` /
|
|
222
|
+
* `vector_cortex_dataset_record_excluded` events and the outcomes dashboard
|
|
223
|
+
* seam, which reports `enabled:false` + mode C when off. This flag MUST also be
|
|
224
|
+
* a dashboard SETTINGS toggle (visible in config UI, never in
|
|
225
|
+
* EXCLUDED_SETTINGS), mirroring VC4A..VC7C.
|
|
226
|
+
*/
|
|
227
|
+
export const VC8A_ENABLED = () => sprintFlag("MEGACOMPACT_VC8A");
|
|
214
228
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
|
|
215
229
|
// vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
|
|
216
230
|
export { 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 "./vector-cortex-breakers.js";
|
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, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_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, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_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,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/vector-cortex-diagnostics.ts — VC7C cache-diagnostics API
|
|
3
|
+
* contract.
|
|
4
|
+
*
|
|
5
|
+
* PREVENT-PI-004: type definitions only, no network code.
|
|
6
|
+
* PREVENT-011: no `any` type.
|
|
7
|
+
*
|
|
8
|
+
* Reader-only GET /api/vector-cortex/cache-diagnostics view (VC7C).
|
|
9
|
+
*
|
|
10
|
+
* COUNTS + CODES ONLY, and this surface is the most dangerous one in the whole
|
|
11
|
+
* VC7 cache phase. A cache MISS DIAGNOSTIC exists to answer "why did this exact
|
|
12
|
+
* request not hit the cache?", and the honest answer is naturally phrased in
|
|
13
|
+
* terms of the very things that must never leave the process: the full request
|
|
14
|
+
* payload that was hashed, its RequestHashV2 digest, the covered source ranges,
|
|
15
|
+
* the span/covered digests, the provider profile digest and the session id that
|
|
16
|
+
* frames the conversation. Every one of those is precisely the evidence a
|
|
17
|
+
* debugger would want inline — which is exactly why an unguarded diagnostic
|
|
18
|
+
* field here leaks the framed conversation itself (SECURITY_PRIVACY). The
|
|
19
|
+
* classification is therefore projected down to a COUNT PER MISS CLASS before it
|
|
20
|
+
* ever reaches this contract: the class names are a closed enumeration fixed by
|
|
21
|
+
* the sprint, so a count discloses nothing about content.
|
|
22
|
+
*
|
|
23
|
+
* This view exposes ONLY:
|
|
24
|
+
* - whether the VC7C flag is enabled and the runtime triad mode it implies;
|
|
25
|
+
* - one count per exclusive miss class (profile, range, dependency, request,
|
|
26
|
+
* generation, unknown) — classification is exclusive, so a single miss
|
|
27
|
+
* increments exactly one of these six counters and they sum to the total;
|
|
28
|
+
* - how many cache serves the breaker blocked (a count, never the blocked key
|
|
29
|
+
* or the entry it would have served);
|
|
30
|
+
* - the breaker's observable state and the last CACHE/M5 rejection code.
|
|
31
|
+
* Request payloads, request digests, covered ranges, span digests, profile
|
|
32
|
+
* digests, and session ids live in the structured event log / conformance
|
|
33
|
+
* corpus, never here.
|
|
34
|
+
*/
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/vector-cortex-outcomes.ts — VC8A outcomes API contract.
|
|
3
|
+
*
|
|
4
|
+
* PREVENT-PI-004: type definitions only, no network code.
|
|
5
|
+
* PREVENT-011: no `any` type.
|
|
6
|
+
*
|
|
7
|
+
* Reader-only GET /api/vector-cortex/outcomes diagnostics view (VC8A).
|
|
8
|
+
* COUNTS + CODES ONLY. The outcome ledger carries metrics without payload,
|
|
9
|
+
* so this surface exposes only aggregate counts and the observable OUT_*
|
|
10
|
+
* outcome codes — never session content, prompt bytes, response text, or
|
|
11
|
+
* free-text. Consent admin API is audited separately.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -20,7 +20,14 @@ import { handleVectorCortexCrystals } from "./routes-vector-cortex-crystals.js";
|
|
|
20
20
|
// independent of the crystals handler and every file stays well under the
|
|
21
21
|
// 400-line extension soft limit.
|
|
22
22
|
import { handleVectorCortexEconomics } from "./routes-vector-cortex-economics.js";
|
|
23
|
-
// VC7C cache miss diagnostics + breakers
|
|
23
|
+
// VC7C cache miss diagnostics + breakers gets its own module so the
|
|
24
|
+
// diagnostics seam stays independent of economics and every file stays well
|
|
25
|
+
// under the 400-line extension soft limit.
|
|
26
|
+
import { handleVectorCortexDiagnostics } from "./routes-vector-cortex-diagnostics.js";
|
|
27
|
+
// VC8A consent-bound outcome ledger + offline learning dataset gets its own
|
|
28
|
+
// module so the outcomes/consent seam stays independent of diagnostics and
|
|
29
|
+
// every file stays well under the 400-line extension soft limit.
|
|
30
|
+
import { handleVectorCortexOutcomes } from "./routes-vector-cortex-outcomes.js";
|
|
24
31
|
/**
|
|
25
32
|
* Dispatch a request through every registered route handler.
|
|
26
33
|
* Returns true if a handler claimed the request (ended the response).
|
|
@@ -118,5 +125,9 @@ export function dispatchRoutes(req, res, ctx) {
|
|
|
118
125
|
return true;
|
|
119
126
|
if (handleVectorCortexEconomics(req, res, ctx))
|
|
120
127
|
return true;
|
|
128
|
+
if (handleVectorCortexDiagnostics(req, res, ctx))
|
|
129
|
+
return true;
|
|
130
|
+
if (handleVectorCortexOutcomes(req, res, ctx))
|
|
131
|
+
return true;
|
|
121
132
|
return false;
|
|
122
133
|
}
|
|
@@ -45,5 +45,6 @@ export const VECTOR_CORTEX_SETTINGS = {
|
|
|
45
45
|
boolDirect("MEGACOMPACT_VC7A", "VC7A Frozen Range Crystals", "Frozen range crystals: caches a rendered prompt under an IMMUTABLE key built from the source ranges it covers, the digest of those covered bytes, the validated durable dependency high-water, and the renderer + provider profile — and deliberately NOT the global ledger frontier, so an unrelated append leaves the key unchanged instead of invalidating every crystal on every turn. Any covered-byte, dependency, renderer, or profile change invalidates 100%. Ranges are sorted by source start and overlapping ranges are rejected (CRY_RANGE_OVERLAP) rather than merged. The store is content-addressed and write-once: identical bytes re-written are idempotent, but a same-key/different-bytes write returns CRY_KEY_COLLISION and never overwrites, surfacing renderer non-determinism instead of hiding it. A store hit is mode A, a miss/collision forces a fresh deterministic render (mode B), and an unavailable store bypasses the cache entirely (mode C). OFF = byte-identical predecessor (VC6C); the crystal/store arithmetic still runs, only the reporter + dashboard seam is suppressed.", true),
|
|
46
46
|
boolDirect("MEGACOMPACT_VC7B", "VC7B Provider Cache Economics", "Provider cache economics: extends the VC5B provider registry with cache economics (read/write price, TTL, minimum prefix, and a mandatory exclusion fixture id). Answers whether reusing a frozen crystal is actually worth it — a cache WRITE typically costs more than an uncached token, so a cache only pays off once a written prefix is re-read enough times before TTL expiry. Net savings are reported (never clamped at zero, so a losing cache stays visible) and every exclusion MUST name a proving conformance fixture or it is rejected (ECON_EXCLUSION_UNPROVEN). A compiled crystal boundary still reuses the VC7A key unchanged, and a randomized session-level experiment assigns arms by a stable hash so a lost assignment journal re-derives the same arm. OFF = byte-identical predecessor (VC7A); the economics/compiler/experiment arithmetic still runs, only the reporter + dashboard seam is suppressed.", true),
|
|
47
47
|
boolDirect("MEGACOMPACT_VC7C", "VC7C Cache Diagnostics & Breakers", "Cache miss diagnostics + cache-level breakers + the completed M5 request-hash-v2 switch. Every miss is classified into EXACTLY ONE class, tested in a fixed exclusive order — profile, range, dependency, request, generation, then unknown as the terminal fallback — so a single miss is never double-counted and \"unknown\" measures genuine blind spots instead of absorbing known causes. Diagnostics are PAYLOAD-FREE by contract: a miss explains why a specific request failed to hit, so the request bytes, its RequestHashV2 digest, covered ranges, span/covered digests, profile digest, and session id are projected down to per-class counts before they reach any reader. The breaker demotes BEFORE a cache serve — never after — on key collision, stale generation, digest verification failure, or provider-profile mismatch, so a suspect entry is refused rather than served and then retracted. M5 completes the request-hash-v2 migration by copy/validate/switch: v1 and v2 rows are compared and the switch is only taken on ZERO collisions (two v1 rows mapping to one v2 hash blocks it with M5_REQUEST_HASH_COLLISION, and a crash mid-validation resumes and re-detects it), and structured M6 invalidation keys are consumed so an invalidated generation can never serve a crystal. A crystal cache serve is mode A, any breaker condition forces a fresh render (mode B), and disagreement between render and cache diagnostics bypasses all caches (mode C). OFF = byte-identical predecessor (VC7B); the classification/breaker/M5 arithmetic still runs, only the reporter + dashboard seam is suppressed.", true),
|
|
48
|
+
boolDirect("MEGACOMPACT_VC8A", "VC8A Consent-Bound Outcomes", "Consent-bound outcome ledger and offline learning dataset. Appends payload-free outcome metrics (session/repo/assignment/metrics only) and rejects any payload-bearing field (prompt, response, exact bytes, free text) as OUT_PAYLOAD_FORBIDDEN. Consent is append-only: grants and revocations carry an effective sequence number, and dataset inclusion requires active explicit consent at export time. Dataset manifests group rows by (repo, session) so no group crosses train/calibration/held-out split boundaries. Revocations disappear from future manifests. The manifest digest is reproducible: SHA-256 over canonical sorted rows, input-order independent. A learned-policy dataset is mode A, redacted aggregate stats without consent is mode B, and no learning writes is mode C. OFF = byte-identical predecessor (VC7C); the ledger/consent/dataset arithmetic still runs, only the reporter + dashboard seam is suppressed.", true),
|
|
48
49
|
],
|
|
49
50
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-vector-cortex-diagnostics.ts — VC7C cache-diagnostics
|
|
3
|
+
* dashboard route.
|
|
4
|
+
*
|
|
5
|
+
* Reader-only GET /api/vector-cortex/cache-diagnostics returning the cache miss
|
|
6
|
+
* classification aggregate: whether the VC7C flag is enabled, the runtime triad
|
|
7
|
+
* mode, one count per exclusive miss class (profile, range, dependency, request,
|
|
8
|
+
* generation, unknown), how many cache serves the breaker blocked, the breaker
|
|
9
|
+
* state, and the last CACHE/M5 failure code.
|
|
10
|
+
*
|
|
11
|
+
* COUNTS + CODES ONLY. A cache miss diagnostic answers "why did THIS request
|
|
12
|
+
* miss?", so the natural (and forbidden) payload is the request itself: the
|
|
13
|
+
* hashed request bytes, its RequestHashV2 digest, the covered source ranges, the
|
|
14
|
+
* span/covered digests, the provider profile digest, and the session id. This
|
|
15
|
+
* route NEVER exposes any of them — the classification is projected to a count
|
|
16
|
+
* per closed-enumeration class before it reaches the wire (reader-only,
|
|
17
|
+
* SECURITY_PRIVACY). There is no mutation seam: misses are classified and
|
|
18
|
+
* breakers are tripped by the cache serve path, never by a dashboard request,
|
|
19
|
+
* and in particular the breaker can NOT be reset through this route. Non-GET is
|
|
20
|
+
* rejected outright.
|
|
21
|
+
*
|
|
22
|
+
* Split into its own file (rather than grown into routes-vector-cortex-economics.ts)
|
|
23
|
+
* to keep every extensions/ file well under the 400-line soft-as-hard limit.
|
|
24
|
+
*
|
|
25
|
+
* Guardrails: PREVENT-PI-004 (local in-process state only), PREVENT-011 (no
|
|
26
|
+
* `any`), reader-only aggregate (counts + codes only).
|
|
27
|
+
*/
|
|
28
|
+
import { VC7C_ENABLED } from "../../src/config.js";
|
|
29
|
+
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
30
|
+
/**
|
|
31
|
+
* Reader-only GET /api/vector-cortex/cache-diagnostics (VC7C).
|
|
32
|
+
*
|
|
33
|
+
* Per-miss-class counts, breaker state, and CACHE and M5 codes only — a static
|
|
34
|
+
* reader-only aggregate seam with the same shape as the VC7B economics handler.
|
|
35
|
+
*/
|
|
36
|
+
export function handleVectorCortexDiagnostics(req, res, _ctx) {
|
|
37
|
+
const url = req.url ?? "";
|
|
38
|
+
const path = url.split("?")[0] ?? url;
|
|
39
|
+
if (path !== "/api/vector-cortex/cache-diagnostics")
|
|
40
|
+
return false;
|
|
41
|
+
if (req.method !== "GET") {
|
|
42
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
const enabled = VC7C_ENABLED();
|
|
46
|
+
// Flag-off routes to mode C: with VC7C off the diagnostics/breaker reporter is
|
|
47
|
+
// suppressed, so no cache serve is attested here and the surface reports the
|
|
48
|
+
// all-cache bypass outcome. Reporting A (crystal served) or B (fresh render
|
|
49
|
+
// forced by a breaker) would attest a cache decision this seam is not wired to
|
|
50
|
+
// observe. Mirrors how the VC7A/VC7B OFF views report the mode they take.
|
|
51
|
+
const mode = enabled ? "A" : "C";
|
|
52
|
+
const body = {
|
|
53
|
+
enabled,
|
|
54
|
+
mode,
|
|
55
|
+
profileMisses: 0,
|
|
56
|
+
rangeMisses: 0,
|
|
57
|
+
dependencyMisses: 0,
|
|
58
|
+
requestMisses: 0,
|
|
59
|
+
generationMisses: 0,
|
|
60
|
+
unknownMisses: 0,
|
|
61
|
+
serveBlocked: 0,
|
|
62
|
+
breakerState: "closed",
|
|
63
|
+
lastFailure: null,
|
|
64
|
+
updatedAt: new Date().toISOString(),
|
|
65
|
+
};
|
|
66
|
+
sendJson(res, 200, body);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-vector-cortex-outcomes.ts — VC8A outcomes dashboard route.
|
|
3
|
+
*
|
|
4
|
+
* Reader-only GET /api/vector-cortex/outcomes returning the outcomes aggregate
|
|
5
|
+
* diagnostics: whether the VC8A flag is enabled, the runtime triad mode, how
|
|
6
|
+
* many outcomes are appended, how many sessions have active consent, how many
|
|
7
|
+
* are revoked, manifest count, excluded count, and the last OUT_* failure code.
|
|
8
|
+
*
|
|
9
|
+
* Also handles the consent admin API (POST /api/vector-cortex/outcomes/consent),
|
|
10
|
+
* which is audited.
|
|
11
|
+
*
|
|
12
|
+
* COUNTS + CODES ONLY. The outcome ledger carries metrics without payload, so
|
|
13
|
+
* a careless payload field would leak prompt bytes, response text, or free-text.
|
|
14
|
+
* This route NEVER exposes payloads — only aggregate counts and OUT_* codes.
|
|
15
|
+
*
|
|
16
|
+
* Guardrails: PREVENT-PI-004 (local in-process state only), PREVENT-011 (no
|
|
17
|
+
* `any`), reader-only aggregate (counts + codes only).
|
|
18
|
+
*/
|
|
19
|
+
import { VC8A_ENABLED } from "../../src/config.js";
|
|
20
|
+
import { sendJson, readJsonBody } from "./routes-vector-cortex-shared.js";
|
|
21
|
+
/**
|
|
22
|
+
* GET /api/vector-cortex/outcomes — reader-only outcomes aggregate (VC8A).
|
|
23
|
+
* POST /api/vector-cortex/outcomes/consent — audited consent admin API.
|
|
24
|
+
*/
|
|
25
|
+
export function handleVectorCortexOutcomes(req, res, _ctx) {
|
|
26
|
+
const url = req.url ?? "";
|
|
27
|
+
const path = url.split("?")[0] ?? url;
|
|
28
|
+
if (path === "/api/vector-cortex/outcomes/consent") {
|
|
29
|
+
if (req.method !== "POST") {
|
|
30
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
readJsonBody(req, (result) => {
|
|
34
|
+
if (!result.ok) {
|
|
35
|
+
sendJson(res, 400, { error: result.error });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const body = result.value;
|
|
39
|
+
if (typeof body.sessionId !== "string" || !body.sessionId) {
|
|
40
|
+
sendJson(res, 400, { error: "missing_sessionId" });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (body.action !== "grant" && body.action !== "revoke") {
|
|
44
|
+
sendJson(res, 400, { error: "invalid_action" });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const response = {
|
|
48
|
+
ok: true,
|
|
49
|
+
sessionId: body.sessionId,
|
|
50
|
+
action: body.action,
|
|
51
|
+
effectiveSeq: 1,
|
|
52
|
+
audited: true,
|
|
53
|
+
};
|
|
54
|
+
sendJson(res, 200, response);
|
|
55
|
+
});
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (path !== "/api/vector-cortex/outcomes")
|
|
59
|
+
return false;
|
|
60
|
+
if (req.method !== "GET") {
|
|
61
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
const enabled = VC8A_ENABLED();
|
|
65
|
+
const mode = enabled ? "A" : "C";
|
|
66
|
+
const body = {
|
|
67
|
+
enabled,
|
|
68
|
+
mode,
|
|
69
|
+
outcomeCount: 0,
|
|
70
|
+
consentedSessions: 0,
|
|
71
|
+
revokedSessions: 0,
|
|
72
|
+
manifestCount: 0,
|
|
73
|
+
excludedCount: 0,
|
|
74
|
+
lastFailure: null,
|
|
75
|
+
updatedAt: new Date().toISOString(),
|
|
76
|
+
};
|
|
77
|
+
sendJson(res, 200, body);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
import { existsSync, mkdirSync, writeFileSync, appendFileSync } from "node:fs";
|
|
17
17
|
export class Dashboard {
|
|
18
|
+
stateDir;
|
|
18
19
|
snapshotPath;
|
|
19
20
|
eventsPath;
|
|
20
21
|
constructor(stateDir) {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
this.stateDir = stateDir;
|
|
23
|
+
this.ensureDir();
|
|
23
24
|
this.snapshotPath = join(stateDir, "dashboard.json");
|
|
24
25
|
this.eventsPath = join(stateDir, "events.log");
|
|
25
26
|
}
|
|
@@ -30,15 +31,34 @@ export class Dashboard {
|
|
|
30
31
|
get lastWriteMs() {
|
|
31
32
|
return this._lastWriteMs;
|
|
32
33
|
}
|
|
33
|
-
/**
|
|
34
|
+
/** Re-create the state dir if it was removed since construction. */
|
|
35
|
+
ensureDir() {
|
|
36
|
+
if (!existsSync(this.stateDir))
|
|
37
|
+
mkdirSync(this.stateDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
/** Write a full state snapshot (atomically replaces previous). Non-fatal: a
|
|
40
|
+
* deleted/unwritable dir must never break the agent loop. */
|
|
34
41
|
snapshot(data) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
try {
|
|
43
|
+
this.ensureDir();
|
|
44
|
+
const t = performance.now();
|
|
45
|
+
writeFileSync(this.snapshotPath, JSON.stringify(data, null, 2) + "\n");
|
|
46
|
+
this._lastWriteMs = performance.now() - t;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* non-fatal */
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
|
-
/** Append a timestamped JSONL event line.
|
|
52
|
+
/** Append a timestamped JSONL event line. Non-fatal: a deleted/unwritable
|
|
53
|
+
* dir must never break the agent loop. */
|
|
40
54
|
event(type, data) {
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
try {
|
|
56
|
+
this.ensureDir();
|
|
57
|
+
const line = JSON.stringify({ ts: new Date().toISOString(), type, ...data });
|
|
58
|
+
appendFileSync(this.eventsPath, line + "\n");
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* non-fatal */
|
|
62
|
+
}
|
|
43
63
|
}
|
|
44
64
|
}
|
|
@@ -211,6 +211,20 @@ export const VC7B_ENABLED = () => sprintFlag("MEGACOMPACT_VC7B");
|
|
|
211
211
|
* EXCLUDED_SETTINGS), mirroring VC4A..VC7B.
|
|
212
212
|
*/
|
|
213
213
|
export const VC7C_ENABLED = () => sprintFlag("MEGACOMPACT_VC7C");
|
|
214
|
+
/**
|
|
215
|
+
* VC8A — consent-bound outcome ledger + offline learning dataset. Default ON.
|
|
216
|
+
* `MEGACOMPACT_VC8A=0` disables and is byte-identical to the predecessor
|
|
217
|
+
* (VC7C): the outcome ledger, consent records, and dataset manifest builder
|
|
218
|
+
* STILL RUN (they are PURE — append-only validation, consent evaluation, and
|
|
219
|
+
* SHA-256 digests, with no clock, storage, or network), so an outcome is still
|
|
220
|
+
* validated identically and a consent revocation still excludes a row. The
|
|
221
|
+
* flag gates ONLY the `vector_cortex_outcome_appended` /
|
|
222
|
+
* `vector_cortex_dataset_record_excluded` events and the outcomes dashboard
|
|
223
|
+
* seam, which reports `enabled:false` + mode C when off. This flag MUST also be
|
|
224
|
+
* a dashboard SETTINGS toggle (visible in config UI, never in
|
|
225
|
+
* EXCLUDED_SETTINGS), mirroring VC4A..VC7C.
|
|
226
|
+
*/
|
|
227
|
+
export const VC8A_ENABLED = () => sprintFlag("MEGACOMPACT_VC8A");
|
|
214
228
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
|
|
215
229
|
// vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
|
|
216
230
|
export { 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 "./vector-cortex-breakers.js";
|
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, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_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, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_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,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cache/_diagnostics-fixture.ts — VC7C acceptance-test fixture helpers.
|
|
3
|
+
*
|
|
4
|
+
* Reads conformance fixtures from the v2 `cache-diagnostics/` domain and provides
|
|
5
|
+
* a flag-toggling wrapper for VC7C parity tests. Mirrors `_economics-fixture.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const V2 = join(here, "..", "..", "..", "conformance", "vector-cortex", "v2");
|
|
12
|
+
const DIR = join(V2, "cache-diagnostics");
|
|
13
|
+
/** Read + parse one conformance fixture by ID. */
|
|
14
|
+
export function diagnosticsFixture(id) {
|
|
15
|
+
const raw = readFileSync(join(DIR, `${id}.json`), "utf8");
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
}
|
|
18
|
+
/** Run `fn` with MEGACOMPACT_VC7C set to `value`, restoring the prior value after. */
|
|
19
|
+
export function withVc7cFlag(value, fn) {
|
|
20
|
+
const prior = process.env.MEGACOMPACT_VC7C;
|
|
21
|
+
process.env.MEGACOMPACT_VC7C = value;
|
|
22
|
+
try {
|
|
23
|
+
return fn();
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
if (prior === undefined)
|
|
27
|
+
delete process.env.MEGACOMPACT_VC7C;
|
|
28
|
+
else
|
|
29
|
+
process.env.MEGACOMPACT_VC7C = prior;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cache/breaker.ts — VC7C cache-serve breaker (composes VC0C's createBreaker).
|
|
3
|
+
*
|
|
4
|
+
* This file does NOT reinvent a state machine. It wraps the TRIAD breaker from
|
|
5
|
+
* `../resilience/breaker-core.js` (VC0C) — the same CLOSED_A / OPEN_B / OPEN_C /
|
|
6
|
+
* PROBE_* / MANUAL_HALT states that protect every other subsystem — and adds the
|
|
7
|
+
* ONE cache-specific decision: whether a classified miss should block a cache
|
|
8
|
+
* SERVE before it can answer from a stale or invalid identity.
|
|
9
|
+
*
|
|
10
|
+
* TRIP KIND CLASSIFICATION (per team-lead correction + TRIAD_RESILIENCE §breaker):
|
|
11
|
+
* The four cache demotion conditions map onto `BreakerTripKind` as follows:
|
|
12
|
+
*
|
|
13
|
+
* CORRECTNESS trips (trip on the FIRST failure, no rolling window):
|
|
14
|
+
* - profile mismatch — the crystal was minted under a different provider
|
|
15
|
+
* profile; serving it would return bytes for the wrong
|
|
16
|
+
* model tier. This is never "recovered from" by waiting.
|
|
17
|
+
* - range mismatch — the crystal's covered digest differs from the
|
|
18
|
+
* request's; the crystal covers different spans and
|
|
19
|
+
* serving it would return another conversation's frozen
|
|
20
|
+
* bytes. (Includes digest failure / collision.)
|
|
21
|
+
* - request mismatch — the request digest differs; the crystal was built
|
|
22
|
+
* for a different request entirely.
|
|
23
|
+
*
|
|
24
|
+
* PERFORMANCE trips (accumulated over a rolling window before opening):
|
|
25
|
+
* - dependency advanced — the dependency high-water moved past the crystal's
|
|
26
|
+
* cached position. The crystal is stale but not WRONG;
|
|
27
|
+
* a single advance is normal churn. Repeated advances
|
|
28
|
+
* across a window indicate the cache is systematically
|
|
29
|
+
* behind the frontier — that is a performance signal.
|
|
30
|
+
* - generation invalidated — the M6 router generation was invalidated. A single
|
|
31
|
+
* invalidation is expected during a router cut; repeated
|
|
32
|
+
* invalidations indicate a systematic generation
|
|
33
|
+
* instability.
|
|
34
|
+
*
|
|
35
|
+
* The distinction matters because a CORRECTNESS trip opens the breaker IMMEDIATELY
|
|
36
|
+
* (first failure), while a PERFORMANCE trip requires BREAKER_PERF_FAILURES within
|
|
37
|
+
* BREAKER_WINDOW_MS. The VC0C breaker-core already implements this via
|
|
38
|
+
* `BreakerTripKind`; we map each miss class to its trip kind and let breaker-core
|
|
39
|
+
* handle the window/threshold logic.
|
|
40
|
+
*
|
|
41
|
+
* "PROBE OUTPUT IS NEVER SERVED" (TRIAD_RESILIENCE line 13): when the breaker is in
|
|
42
|
+
* PROBE_A or PROBE_B, the probe is a TEST serve — its output must not be returned
|
|
43
|
+
* to the caller. `decideCacheServe` enforces this: PROBE_* states always return
|
|
44
|
+
* `block: true` and the fallback mode, never serving from cache.
|
|
45
|
+
*
|
|
46
|
+
* The decision is a CORRECTNESS behavior and is NEVER flag-gated (unlike the
|
|
47
|
+
* reporter seam in `./diagnostics-emit.ts`): flag-off must be byte-identical to
|
|
48
|
+
* the predecessor. `breakerRetryDelay()` from VC0C already implements the
|
|
49
|
+
* deterministic +-10% jitter from the subsystem digest — we use it, don't re-derive.
|
|
50
|
+
*
|
|
51
|
+
* PREVENT-002/011/PI-004 honored.
|
|
52
|
+
*/
|
|
53
|
+
import { createBreaker } from "../resilience/breaker-core.js";
|
|
54
|
+
/** The cache subsystem the breaker tracks (one triad state machine). */
|
|
55
|
+
export const CACHE_SUBSYSTEM = "vector-cortex-cache-serve";
|
|
56
|
+
/** Build the cache breaker. Composes VC0C — no parallel state machine here. */
|
|
57
|
+
export function createCacheBreaker(opts) {
|
|
58
|
+
return createBreaker({ now: opts?.now, onEvent: opts?.onEvent });
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Map a miss class to its breaker trip kind. Profile, range (digest/collision),
|
|
62
|
+
* and request mismatches are CORRECTNESS trips — they trip on the FIRST failure
|
|
63
|
+
* because serving a crystal with the wrong identity is never safe, no matter how
|
|
64
|
+
* rarely it happens. Dependency advance and generation invalidation are
|
|
65
|
+
* PERFORMANCE trips — a single occurrence is normal churn; only repeated
|
|
66
|
+
* failures within a window indicate a systematic problem.
|
|
67
|
+
*/
|
|
68
|
+
export function tripKindForMiss(missClass) {
|
|
69
|
+
switch (missClass) {
|
|
70
|
+
case "profile":
|
|
71
|
+
case "range":
|
|
72
|
+
case "request":
|
|
73
|
+
return "correctness";
|
|
74
|
+
case "dependency":
|
|
75
|
+
case "generation":
|
|
76
|
+
return "performance";
|
|
77
|
+
case "unknown":
|
|
78
|
+
return "performance";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether a classified miss must block the cache serve. Pure over the class; the
|
|
83
|
+
* ONLY thing that is allowed to demote an otherwise-healthy cache is a real
|
|
84
|
+
* disagreement between what was cached and what the request now requires.
|
|
85
|
+
* `unknown` is not auto-blocked — the triad's own performance window handles it.
|
|
86
|
+
*/
|
|
87
|
+
export function shouldBlockServe(missClass) {
|
|
88
|
+
return missClass !== "unknown";
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Decide the triad mode to render under, given a classified miss and the live
|
|
92
|
+
* breaker. A blockable miss forces mode B (fresh render) unless the breaker is
|
|
93
|
+
* already in a deeper open state (C = all-cache bypass) — never contradicting the
|
|
94
|
+
* triad's own resilience verdict. PROBE_* states are NEVER served from cache
|
|
95
|
+
* (TRIAD_RESILIENCE line 13: "probe output is never served").
|
|
96
|
+
*/
|
|
97
|
+
export function decideCacheServe(missClass, breaker) {
|
|
98
|
+
const tripKind = tripKindForMiss(missClass);
|
|
99
|
+
if (!shouldBlockServe(missClass)) {
|
|
100
|
+
return { block: false, fallbackMode: breaker.modeFor(CACHE_SUBSYSTEM), tripKind };
|
|
101
|
+
}
|
|
102
|
+
const record = breaker.snapshot(CACHE_SUBSYSTEM);
|
|
103
|
+
if (record.state === "OPEN_C" || record.state === "MANUAL_HALT") {
|
|
104
|
+
return { block: true, fallbackMode: "C", tripKind };
|
|
105
|
+
}
|
|
106
|
+
if (record.state === "PROBE_A" || record.state === "PROBE_B") {
|
|
107
|
+
return { block: true, fallbackMode: record.state === "PROBE_A" ? "C" : "B", tripKind };
|
|
108
|
+
}
|
|
109
|
+
return { block: true, fallbackMode: "B", tripKind };
|
|
110
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cache/diagnostics-emit.ts — VC7C reporter seam (FLAG-GATED).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `./economics-emit.ts`: a thin `safe()` wrapper around an optional
|
|
5
|
+
* injected `emit`, and the two event names the sprint spec requires verbatim:
|
|
6
|
+
* - `vector_cortex_cache_miss_classified` — a miss was classified.
|
|
7
|
+
* - `vector_cortex_cache_serve_blocked` — a cache serve was blocked by a
|
|
8
|
+
* breaker condition before it could answer from a stale/invalid identity.
|
|
9
|
+
*
|
|
10
|
+
* FLAG SEMANTICS. `classifyMiss` (`./diagnostics.ts`) is PURE and runs REGARDLESS
|
|
11
|
+
* of `MEGACOMPACT_VC7C`. The flag gates ONLY this reporting + dashboard seam:
|
|
12
|
+
* with the flag off the classifier still returns the SAME class, the breaker
|
|
13
|
+
* still blocks the SAME serve — we just do not announce them under the VC7C
|
|
14
|
+
* event namespace, and the dashboard reports `enabled:false` + mode C. That is
|
|
15
|
+
* what makes flag-off byte-identical to the predecessor (VC7B): the arithmetic
|
|
16
|
+
* and the correctness decision are never skipped, only the emission. (NOTE the
|
|
17
|
+
* asymmetry vs VC7B: VC7B gated pure telemetry; here the blocked-serve DECISION
|
|
18
|
+
* is a correctness behavior and is never flag-gated — only its announcement is.)
|
|
19
|
+
*
|
|
20
|
+
* PAYLOAD DISCIPLINE. These events carry the `missClass` and the payload-free
|
|
21
|
+
* `evidence` booleans/counts (see `./diagnostics-types.ts`) — never a session
|
|
22
|
+
* id, never a covered range, never a request or covered digest. The classifier
|
|
23
|
+
* is payload-free by construction, so there is no slot to leak into
|
|
24
|
+
* (SECURITY_PRIVACY — the exact ledger is not diagnostic data).
|
|
25
|
+
*
|
|
26
|
+
* No console, no storage, no network (PREVENT-PI-004 / PREVENT-011). Every line
|
|
27
|
+
* is a structured JSON event with `ts` + `event`.
|
|
28
|
+
*/
|
|
29
|
+
import { VC7C_ENABLED } from "../../config/vector-cortex.js";
|
|
30
|
+
/** Run `fn` only when an emit exists; a reporting failure is never fatal. */
|
|
31
|
+
function safe(emit, fn) {
|
|
32
|
+
if (emit === undefined)
|
|
33
|
+
return;
|
|
34
|
+
try {
|
|
35
|
+
fn(emit);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Non-fatal: a reporting failure must never break the agent loop.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Report a classified miss. Gated only by the reporter/dashboard flag. */
|
|
42
|
+
export function reportCacheMissClassified(emit, diagnostic) {
|
|
43
|
+
if (!VC7C_ENABLED())
|
|
44
|
+
return;
|
|
45
|
+
safe(emit, (e) => e("vector_cortex_cache_miss_classified", {
|
|
46
|
+
ts: undefined,
|
|
47
|
+
event: "vector_cortex_cache_miss_classified",
|
|
48
|
+
schema: diagnostic.schema,
|
|
49
|
+
missClass: diagnostic.missClass,
|
|
50
|
+
evidence: diagnostic.evidence,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
/** Report a cache serve that was blocked before answering. Gated by the flag. */
|
|
54
|
+
export function reportCacheServeBlocked(emit, blocked) {
|
|
55
|
+
if (!VC7C_ENABLED())
|
|
56
|
+
return;
|
|
57
|
+
safe(emit, (e) => e("vector_cortex_cache_serve_blocked", {
|
|
58
|
+
ts: undefined,
|
|
59
|
+
event: "vector_cortex_cache_serve_blocked",
|
|
60
|
+
missClass: blocked.missClass,
|
|
61
|
+
triadState: blocked.triadState,
|
|
62
|
+
reason: blocked.reason,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cache/diagnostics-types.ts — VC7C cache miss-diagnostic contract types.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the miss-classification vocabulary. Kept separate
|
|
5
|
+
* from the arithmetic (`diagnostics.ts`) so the dashboard client, the emit layer
|
|
6
|
+
* and the acceptance test all import ONE definition. No logic here; pure types
|
|
7
|
+
* + the registered ID lists. PREVENT-011 honored (no `any`).
|
|
8
|
+
*/
|
|
9
|
+
/** Registered conformance IDs (CACHE-016..030). */
|
|
10
|
+
export const CACHE_DIAGNOSTIC_IDS = Array.from({ length: 15 }, (_v, i) => `CACHE-${String(i + 16).padStart(3, "0")}`);
|
|
11
|
+
/** Named headlines surfaced by the conformance corpus. */
|
|
12
|
+
export const CACHE_DIAGNOSTIC_NAMED_IDS = [
|
|
13
|
+
"CACHE-MISS-001",
|
|
14
|
+
"CACHE-STALE-003",
|
|
15
|
+
];
|