pi-mega-compact 0.20.13 → 0.20.14

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.
Files changed (95) hide show
  1. package/dist/config/vector-cortex-early.js +89 -0
  2. package/dist/config/vector-cortex-flag.js +25 -0
  3. package/dist/config/vector-cortex.js +23 -83
  4. package/dist/config.js +1 -1
  5. package/dist/extensions/dashboard-server/api-contracts/vector-cortex-economics.js +20 -0
  6. package/dist/extensions/dashboard-server/route-dispatch.js +6 -0
  7. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
  8. package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +59 -0
  9. package/dist/src/config/vector-cortex-early.js +89 -0
  10. package/dist/src/config/vector-cortex-flag.js +25 -0
  11. package/dist/src/config/vector-cortex.js +23 -83
  12. package/dist/src/config.js +1 -1
  13. package/dist/src/vector-cortex/cache/_economics-fixture.js +41 -0
  14. package/dist/src/vector-cortex/cache/compiler.js +201 -0
  15. package/dist/src/vector-cortex/cache/economics-emit.js +85 -0
  16. package/dist/src/vector-cortex/migrations/request-hash-v2.js +161 -0
  17. package/dist/src/vector-cortex/provider/economics-ids.js +29 -0
  18. package/dist/src/vector-cortex/provider/economics.js +176 -0
  19. package/dist/src/vector-cortex/provider/experiments.js +166 -0
  20. package/dist/vector-cortex/cache/_economics-fixture.js +41 -0
  21. package/dist/vector-cortex/cache/compiler.js +201 -0
  22. package/dist/vector-cortex/cache/economics-emit.js +85 -0
  23. package/dist/vector-cortex/migrations/request-hash-v2.js +161 -0
  24. package/dist/vector-cortex/provider/economics-ids.js +29 -0
  25. package/dist/vector-cortex/provider/economics.js +176 -0
  26. package/dist/vector-cortex/provider/experiments.js +166 -0
  27. package/extensions/dashboard-client/dist/assets/{AreaChart-CB-U7ViX.js → AreaChart-VUd_iOtO.js} +2 -2
  28. package/extensions/dashboard-client/dist/assets/{AreaChart-CB-U7ViX.js.map → AreaChart-VUd_iOtO.js.map} +1 -1
  29. package/extensions/dashboard-client/dist/assets/{BarChart-DnLw0fxA.js → BarChart-BoqeJ5mM.js} +2 -2
  30. package/extensions/dashboard-client/dist/assets/{BarChart-DnLw0fxA.js.map → BarChart-BoqeJ5mM.js.map} +1 -1
  31. package/extensions/dashboard-client/dist/assets/{CacheTab-CjyTVDiP.js → CacheTab-1ON7meDK.js} +2 -2
  32. package/extensions/dashboard-client/dist/assets/{CacheTab-CjyTVDiP.js.map → CacheTab-1ON7meDK.js.map} +1 -1
  33. package/extensions/dashboard-client/dist/assets/{EventsTab-Bz3QEWam.js → EventsTab-Dr9eqt1k.js} +2 -2
  34. package/extensions/dashboard-client/dist/assets/{EventsTab-Bz3QEWam.js.map → EventsTab-Dr9eqt1k.js.map} +1 -1
  35. package/extensions/dashboard-client/dist/assets/{HealthTab-CUylEvEY.js → HealthTab-Ciaigd4i.js} +2 -2
  36. package/extensions/dashboard-client/dist/assets/{HealthTab-CUylEvEY.js.map → HealthTab-Ciaigd4i.js.map} +1 -1
  37. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cz_hj_E7.js → MaintenanceTab-DjZRr3Lf.js} +2 -2
  38. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cz_hj_E7.js.map → MaintenanceTab-DjZRr3Lf.js.map} +1 -1
  39. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dh8brIR1.js → MemoryMapTab-BpZXHA7j.js} +2 -2
  40. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dh8brIR1.js.map → MemoryMapTab-BpZXHA7j.js.map} +1 -1
  41. package/extensions/dashboard-client/dist/assets/{MetricsTab-CkqSXc6e.js → MetricsTab-QemocY5k.js} +2 -2
  42. package/extensions/dashboard-client/dist/assets/{MetricsTab-CkqSXc6e.js.map → MetricsTab-QemocY5k.js.map} +1 -1
  43. package/extensions/dashboard-client/dist/assets/{OverviewTab-DGbJcx6d.js → OverviewTab-VtC1F-mO.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{OverviewTab-DGbJcx6d.js.map → OverviewTab-VtC1F-mO.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/{ReposTab-BawS3nfF.js → ReposTab-CJD1cBxp.js} +2 -2
  46. package/extensions/dashboard-client/dist/assets/{ReposTab-BawS3nfF.js.map → ReposTab-CJD1cBxp.js.map} +1 -1
  47. package/extensions/dashboard-client/dist/assets/{SessionsTab-CUVnmYks.js → SessionsTab-Cj0erPR4.js} +2 -2
  48. package/extensions/dashboard-client/dist/assets/{SessionsTab-CUVnmYks.js.map → SessionsTab-Cj0erPR4.js.map} +1 -1
  49. package/extensions/dashboard-client/dist/assets/{SetupTab-cxTuyZNk.js → SetupTab-AOVROZ4G.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{SetupTab-cxTuyZNk.js.map → SetupTab-AOVROZ4G.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cv5SENkE.js → TimeSavedCard-ZliVn8DH.js} +2 -2
  52. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cv5SENkE.js.map → TimeSavedCard-ZliVn8DH.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/{TurnsTab-yl6BBG_F.js → TurnsTab-DsoTWeIh.js} +2 -2
  54. package/extensions/dashboard-client/dist/assets/{TurnsTab-yl6BBG_F.js.map → TurnsTab-DsoTWeIh.js.map} +1 -1
  55. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BBa7rp6C.js +2 -0
  56. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BBa7rp6C.js.map +1 -0
  57. package/extensions/dashboard-client/dist/assets/{WikiTab-DKv-0xCQ.js → WikiTab-CK8fcW1l.js} +2 -2
  58. package/extensions/dashboard-client/dist/assets/{WikiTab-DKv-0xCQ.js.map → WikiTab-CK8fcW1l.js.map} +1 -1
  59. package/extensions/dashboard-client/dist/assets/{button-CVPrO4UU.js → button-DdPcvex1.js} +2 -2
  60. package/extensions/dashboard-client/dist/assets/{button-CVPrO4UU.js.map → button-DdPcvex1.js.map} +1 -1
  61. package/extensions/dashboard-client/dist/assets/{card-BFLnQJEo.js → card-DXFuZph_.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{card-BFLnQJEo.js.map → card-DXFuZph_.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-IUoLd1.js → generateCategoricalChart-BagDVGWn.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-IUoLd1.js.map → generateCategoricalChart-BagDVGWn.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/{index-Do749WlW.js → index-DVdDtRY4.js} +3 -3
  66. package/extensions/dashboard-client/dist/assets/{index-Do749WlW.js.map → index-DVdDtRY4.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/{switch-3uFnZmtq.js → switch-CtdtGyUR.js} +2 -2
  68. package/extensions/dashboard-client/dist/assets/{switch-3uFnZmtq.js.map → switch-CtdtGyUR.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/assets/{toggle-C1rYLeXe.js → toggle-Cvvwlbye.js} +2 -2
  70. package/extensions/dashboard-client/dist/assets/{toggle-C1rYLeXe.js.map → toggle-Cvvwlbye.js.map} +1 -1
  71. package/extensions/dashboard-client/dist/assets/{useSSE-D1qzLzgR.js → useSSE-DvlceHjV.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{useSSE-D1qzLzgR.js.map → useSSE-DvlceHjV.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/index.html +1 -1
  74. package/extensions/dashboard-client/src/api/vector-cortex.ts +9 -0
  75. package/extensions/dashboard-client/src/tabs/VectorCortexEconomicsCard.tsx +41 -0
  76. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +8 -0
  77. package/extensions/dashboard-client/src/types/vector-cortex.ts +14 -0
  78. package/extensions/dashboard-server/api-contracts/vector-cortex-economics.ts +47 -0
  79. package/extensions/dashboard-server/route-dispatch.ts +5 -0
  80. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
  81. package/extensions/dashboard-server/routes-vector-cortex-economics.ts +68 -0
  82. package/package.json +1 -1
  83. package/src/config/vector-cortex-early.ts +99 -0
  84. package/src/config/vector-cortex-flag.ts +24 -0
  85. package/src/config/vector-cortex.ts +34 -89
  86. package/src/config.ts +1 -0
  87. package/src/vector-cortex/cache/_economics-fixture.ts +128 -0
  88. package/src/vector-cortex/cache/compiler.ts +280 -0
  89. package/src/vector-cortex/cache/economics-emit.ts +116 -0
  90. package/src/vector-cortex/migrations/request-hash-v2.ts +228 -0
  91. package/src/vector-cortex/provider/economics-ids.ts +38 -0
  92. package/src/vector-cortex/provider/economics.ts +289 -0
  93. package/src/vector-cortex/provider/experiments.ts +248 -0
  94. package/extensions/dashboard-client/dist/assets/VectorCortexTab-94fqVjat.js +0 -2
  95. package/extensions/dashboard-client/dist/assets/VectorCortexTab-94fqVjat.js.map +0 -1
@@ -0,0 +1,289 @@
1
+ /**
2
+ * vector-cortex/provider/economics.ts — VC7B cache economics (ProviderProfileV1
3
+ * extension).
4
+ *
5
+ * VC7A proved a render can be FROZEN and reused. VC7B answers the question that
6
+ * immediately follows: is reusing it actually WORTH IT? Provider prompt caching
7
+ * is not free — a cache WRITE typically costs MORE than an uncached token, and a
8
+ * cache READ costs less. So a cache is profitable only when a written prefix is
9
+ * read back enough times, before its TTL expires, to repay the write premium.
10
+ * This file is that arithmetic and nothing else.
11
+ *
12
+ * THE NET-SAVINGS MODEL. For a prefix of `cachedTokens` tokens:
13
+ *
14
+ * baseline (no cache) = cachedTokens * basePrice * (writes + hits)
15
+ * actual (cached) = cachedTokens * (writePrice * writes + readPrice * hits)
16
+ * netSavings = baseline - actual
17
+ *
18
+ * A NEGATIVE `netSavings` is a real, expected, and important outcome: it means
19
+ * the cache LOST money (a prefix written once and never re-read always does, by
20
+ * exactly the write premium). We report it rather than clamping it at zero,
21
+ * because a floor at zero would make every rollout look free and would hide the
22
+ * single failure mode this sprint exists to detect.
23
+ *
24
+ * EXACT ARITHMETIC, NO FLOATS IN THE MONEY PATH. Prices are integer
25
+ * MICRO-UNITS per token (1e-6 of the provider's currency unit), never floating
26
+ * point. `0.1 + 0.2 !== 0.3` is not an acceptable property for a cost ledger, and
27
+ * accumulating float error across millions of tokens produces aggregates that
28
+ * silently disagree with the provider's own bill. All money is integer; only the
29
+ * derived RATIO is a float, and it is finite-guarded.
30
+ *
31
+ * EVERY EXCLUSION NEEDS A FIXTURE (the sprint's headline safety rule). A provider
32
+ * profile may declare that some request field does not affect cache identity —
33
+ * but an UNPROVEN exclusion is how you get silent cache poisoning: the renderer
34
+ * folds a field the provider actually keys on, two different requests collapse to
35
+ * one cache entry, and one conversation is served another's prefix. So an
36
+ * exclusion without a `fixtureId` (or with a blank one) is REJECTED here —
37
+ * `ECON_EXCLUSION_UNPROVEN` — rather than trusted. There is no override.
38
+ *
39
+ * ESTIMATE VS MEASURED. Every result is labeled. Only telemetry from a
40
+ * RANDOMIZED live assignment may be called `measured` and fed into a causal
41
+ * interval; shadow or non-randomized numbers are `estimate` and are excluded
42
+ * from causal aggregates (see `experiments.ts`). Mixing the two would let a
43
+ * self-selected population masquerade as a controlled experiment.
44
+ *
45
+ * PURE. No clock, no storage, no console, no network (PREVENT-PI-004 /
46
+ * PREVENT-011). Runs identically with `MEGACOMPACT_VC7B` on or off — the flag
47
+ * gates only the reporter/dashboard seam in `../cache/economics-emit.ts`.
48
+ */
49
+
50
+ import type { ProviderProfileExclusion, ProviderProfileV1 } from "./types.js";
51
+
52
+ /**
53
+ * Cache economics attached to a provider profile.
54
+ *
55
+ * Prices are integer MICRO-UNITS PER TOKEN (1e-6 currency units), so a provider
56
+ * charging $3.00 per million input tokens has `basePrice: 3`. Integers keep the
57
+ * money path exact; see the file header for why floats are refused.
58
+ */
59
+ export interface ProviderEconomicsV1 {
60
+ readonly schema: "provider-economics-v1";
61
+ /** The `ProviderProfileV1.id` these economics belong to. */
62
+ readonly profileId: string;
63
+ /** Profile version — economics are versioned WITH the profile they price. */
64
+ readonly profileVersion: string;
65
+ /** Uncached price per token, integer micro-units. The savings baseline. */
66
+ readonly basePrice: number;
67
+ /** Cache-READ price per token, integer micro-units. Normally < basePrice. */
68
+ readonly readPrice: number;
69
+ /** Cache-WRITE price per token, integer micro-units. Normally > basePrice. */
70
+ readonly writePrice: number;
71
+ /** Cache entry lifetime in ms. A prefix older than this cannot be read back. */
72
+ readonly ttlMs: number;
73
+ /** Minimum cacheable prefix in tokens; a shorter prefix is never cached. */
74
+ readonly minPrefix: number;
75
+ /**
76
+ * Conformance fixture ID proving this profile's exclusion set is safe, or
77
+ * `null` when the profile declares NO exclusions (nothing to prove). A profile
78
+ * WITH exclusions and a null/blank id is rejected — see `validateEconomics`.
79
+ */
80
+ readonly exclusionFixtureId: string | null;
81
+ }
82
+
83
+ /** Observed (or shadow) cache traffic for one economics computation. */
84
+ export interface CacheUsageV1 {
85
+ /** Tokens in the cached prefix. Must be a non-negative safe integer. */
86
+ readonly cachedTokens: number;
87
+ /** Number of cache WRITES (each pays the write premium). */
88
+ readonly writeCount: number;
89
+ /** Number of cache HITS (each pays the discounted read price). */
90
+ readonly hitCount: number;
91
+ }
92
+
93
+ /**
94
+ * Whether a figure may be used as causal evidence.
95
+ *
96
+ * `measured` — from a RANDOMIZED live assignment; admissible in causal
97
+ * intervals.
98
+ * `estimate` — shadow, projected, or non-randomized; reportable but NEVER
99
+ * admissible in a causal interval.
100
+ */
101
+ export type EconomicsEvidence = "measured" | "estimate";
102
+
103
+ /** VC7B economics failure codes. */
104
+ export type EconomicsFailureCode =
105
+ /** A profile declares exclusions but names no proving fixture. */
106
+ | "ECON_EXCLUSION_UNPROVEN"
107
+ /** A price / TTL / prefix is negative, fractional, or not finite. */
108
+ | "ECON_PRICE_INVALID"
109
+ /** A usage count is negative, fractional, or not finite. */
110
+ | "ECON_USAGE_INVALID"
111
+ /** The computed result overflowed the exact-integer safe range. */
112
+ | "ECON_OVERFLOW";
113
+
114
+ /** The computed economics of a cache decision. All money in micro-units. */
115
+ export interface EconomicsResultV1 {
116
+ readonly profileId: string;
117
+ /** What the same traffic would have cost with no cache at all. */
118
+ readonly baselineCost: number;
119
+ /** What it actually cost: write premium on writes, discount on hits. */
120
+ readonly actualCost: number;
121
+ /** `baselineCost - actualCost`. NEGATIVE means the cache lost money. */
122
+ readonly netSavings: number;
123
+ /** Tokens billed at the discounted read price (the cache's token benefit). */
124
+ readonly tokenSavings: number;
125
+ /** `netSavings / baselineCost`, or 0 when the baseline is 0. Always finite. */
126
+ readonly savingsRatio: number;
127
+ /** Hits needed to break even on one write, or null when never profitable. */
128
+ readonly breakEvenHits: number | null;
129
+ /** Whether this figure may enter a causal interval. */
130
+ readonly evidence: EconomicsEvidence;
131
+ }
132
+
133
+ /** The verdict of an economics computation. */
134
+ export type EconomicsResult =
135
+ | { readonly ok: true; readonly result: EconomicsResultV1 }
136
+ | { readonly ok: false; readonly codes: readonly EconomicsFailureCode[] };
137
+
138
+ /** A non-negative safe integer — the only shape money and counts may take. */
139
+ function isCount(n: number): boolean {
140
+ return Number.isSafeInteger(n) && n >= 0;
141
+ }
142
+
143
+ /**
144
+ * Validate a profile's economics, enforcing the exclusion-proof rule.
145
+ *
146
+ * An exclusion claims "this field cannot affect provider cache identity". That
147
+ * claim is only as good as the fixture that proves it, so a profile carrying
148
+ * exclusions MUST name a `exclusionFixtureId`, and every individual exclusion
149
+ * must carry its own `fixtureId` too (VC5B already models that field; VC7B makes
150
+ * a blank one fatal instead of decorative). Returns deduplicated codes in a
151
+ * deterministic order.
152
+ */
153
+ export function validateEconomics(
154
+ econ: ProviderEconomicsV1,
155
+ exclusions: readonly ProviderProfileExclusion[],
156
+ ): readonly EconomicsFailureCode[] {
157
+ const codes = new Set<EconomicsFailureCode>();
158
+
159
+ for (const n of [econ.basePrice, econ.readPrice, econ.writePrice, econ.ttlMs, econ.minPrefix]) {
160
+ if (!isCount(n)) codes.add("ECON_PRICE_INVALID");
161
+ }
162
+
163
+ // The headline rule: exclusions without a proving fixture are never trusted.
164
+ if (exclusions.length > 0) {
165
+ const id = econ.exclusionFixtureId;
166
+ if (id === null || id.trim() === "") codes.add("ECON_EXCLUSION_UNPROVEN");
167
+ for (const ex of exclusions) {
168
+ if (ex.fixtureId.trim() === "") codes.add("ECON_EXCLUSION_UNPROVEN");
169
+ }
170
+ }
171
+
172
+ const order: EconomicsFailureCode[] = ["ECON_EXCLUSION_UNPROVEN", "ECON_PRICE_INVALID"];
173
+ return order.filter((c) => codes.has(c));
174
+ }
175
+
176
+ /**
177
+ * Validate a profile + its economics together. Convenience over
178
+ * `validateEconomics` for callers holding a whole `ProviderProfileV1`: the
179
+ * exclusion list is read from the profile itself, so the two can never disagree.
180
+ */
181
+ export function validateProfileEconomics(
182
+ profile: ProviderProfileV1,
183
+ econ: ProviderEconomicsV1,
184
+ ): readonly EconomicsFailureCode[] {
185
+ return validateEconomics(econ, profile.excludedJsonPointers);
186
+ }
187
+
188
+ /**
189
+ * Hits required for ONE write to break even.
190
+ *
191
+ * One write costs `(writePrice - basePrice)` extra per token; each subsequent
192
+ * hit saves `(basePrice - readPrice)` per token. So break-even is the ceiling of
193
+ * premium/discount. Returns `null` when the cache can NEVER pay for itself
194
+ * (a read that costs at least as much as an uncached token) — reporting a huge
195
+ * number there would imply "just get more hits", which is false.
196
+ * Returns 0 when writing is already free or cheaper than not caching.
197
+ */
198
+ export function breakEvenHits(econ: ProviderEconomicsV1): number | null {
199
+ const premium = econ.writePrice - econ.basePrice;
200
+ const discount = econ.basePrice - econ.readPrice;
201
+ if (premium <= 0) return 0;
202
+ if (discount <= 0) return null;
203
+ return Math.ceil(premium / discount);
204
+ }
205
+
206
+ /**
207
+ * Compute net cache savings for observed (or shadow) usage.
208
+ *
209
+ * Pure integer arithmetic in micro-units. The only float is `savingsRatio`, and
210
+ * it is zero-guarded so a zero baseline yields 0 rather than NaN/Infinity — the
211
+ * sprint invariant is that every reported aggregate is FINITE.
212
+ *
213
+ * `evidence` is supplied by the caller and simply carried through: this function
214
+ * cannot know whether its inputs came from a randomized arm, and guessing would
215
+ * be exactly the mislabeling the causal rules forbid.
216
+ */
217
+ export function computeEconomics(
218
+ econ: ProviderEconomicsV1,
219
+ usage: CacheUsageV1,
220
+ evidence: EconomicsEvidence,
221
+ ): EconomicsResult {
222
+ const codes: EconomicsFailureCode[] = [];
223
+ for (const n of [econ.basePrice, econ.readPrice, econ.writePrice, econ.ttlMs, econ.minPrefix]) {
224
+ if (!isCount(n)) {
225
+ codes.push("ECON_PRICE_INVALID");
226
+ break;
227
+ }
228
+ }
229
+ for (const n of [usage.cachedTokens, usage.writeCount, usage.hitCount]) {
230
+ if (!isCount(n)) {
231
+ codes.push("ECON_USAGE_INVALID");
232
+ break;
233
+ }
234
+ }
235
+ if (codes.length > 0) return { ok: false, codes };
236
+
237
+ const { cachedTokens, writeCount, hitCount } = usage;
238
+ const baselineCost = cachedTokens * econ.basePrice * (writeCount + hitCount);
239
+ const actualCost = cachedTokens * (econ.writePrice * writeCount + econ.readPrice * hitCount);
240
+
241
+ // Exactness is the whole point of the integer model: if any product leaves the
242
+ // safe-integer range the result is silently wrong, so we fail instead.
243
+ if (!Number.isSafeInteger(baselineCost) || !Number.isSafeInteger(actualCost)) {
244
+ return { ok: false, codes: ["ECON_OVERFLOW"] };
245
+ }
246
+
247
+ const netSavings = baselineCost - actualCost;
248
+ // Tokens served at the discounted read price — the cache's token-level benefit,
249
+ // independent of price (a hit re-reads the whole prefix).
250
+ const tokenSavings = cachedTokens * hitCount;
251
+ const savingsRatio = baselineCost === 0 ? 0 : netSavings / baselineCost;
252
+
253
+ return {
254
+ ok: true,
255
+ result: {
256
+ profileId: econ.profileId,
257
+ baselineCost,
258
+ actualCost,
259
+ netSavings,
260
+ tokenSavings,
261
+ savingsRatio,
262
+ breakEvenHits: breakEvenHits(econ),
263
+ evidence,
264
+ },
265
+ };
266
+ }
267
+
268
+ /**
269
+ * Whether a prefix is eligible to be cached at all: it must meet the profile's
270
+ * minimum prefix, and it must still be within TTL. A prefix below `minPrefix` is
271
+ * not "a small win", it is not cacheable by the provider at all.
272
+ */
273
+ export function isCacheEligible(
274
+ econ: ProviderEconomicsV1,
275
+ prefixTokens: number,
276
+ ageMs: number,
277
+ ): boolean {
278
+ if (!isCount(prefixTokens) || !isCount(ageMs)) return false;
279
+ return prefixTokens >= econ.minPrefix && ageMs < econ.ttlMs;
280
+ }
281
+
282
+ // Conformance ID ranges + named rows extracted to economics-ids.ts to keep this
283
+ // file under the 300-line soft limit (soft-as-hard gate). Re-exported here so no
284
+ // consumer import path changes.
285
+ export {
286
+ CACHE_IDS,
287
+ ECONOMICS_PROVIDER_IDS,
288
+ ECONOMICS_NAMED_IDS,
289
+ } from "./economics-ids.js";
@@ -0,0 +1,248 @@
1
+ /**
2
+ * vector-cortex/provider/experiments.ts — VC7B session-level cache experiments.
3
+ *
4
+ * To claim a cache strategy CAUSED a saving you need a randomized comparison,
5
+ * not a before/after. This file assigns each session to an experiment arm and
6
+ * guarantees the two properties that make the resulting telemetry admissible as
7
+ * causal evidence.
8
+ *
9
+ * 1. STABLE, JOURNAL-FREE ASSIGNMENT. The arm is a pure function of
10
+ * `sha256(experimentId, sessionId)` — NOT a random draw recorded in a
11
+ * journal. So the assignment survives anything: process restart, a lost or
12
+ * corrupted journal, a different host, a replay months later. This is the
13
+ * sprint's unique failure-injection case (lose the journal after the first
14
+ * event, restart, and the same arm must come back), and a hash-derived arm
15
+ * passes it by construction rather than by careful recovery code. A journal
16
+ * can still be kept as an audit trail, but nothing DEPENDS on it.
17
+ *
18
+ * The corollary matters just as much: every event in one session shares one
19
+ * arm (CACHE-RANDOM-003). If a session could drift between arms mid-flight,
20
+ * its rows would appear in both arms of the comparison and the contrast would
21
+ * be measuring nothing.
22
+ *
23
+ * 2. RANDOMIZED ⇒ CAUSAL; EVERYTHING ELSE ⇒ ESTIMATE. Hashing a session id is
24
+ * randomization only when the id itself is unpredictable and every session is
25
+ * eligible. A FORCED arm (operator override), a SHADOW arm (computed but not
26
+ * served), and a non-randomized rollout are all labeled `estimate` and are
27
+ * excluded from causal intervals by `isCausallyAdmissible`. Shadow numbers are
28
+ * genuinely useful — they are just not evidence of an effect.
29
+ *
30
+ * WHY 10_000 BUCKETS. Bucket granularity bounds how finely traffic can be split;
31
+ * 10k gives 0.01% resolution, matching VC5C's rollout bucketing so the two
32
+ * subsystems partition traffic on the same scale rather than on quietly
33
+ * different ones.
34
+ *
35
+ * PURE. No clock, no storage, no console, no network (PREVENT-PI-004 /
36
+ * PREVENT-011). `assignedAt` is an INJECTED timestamp, never `Date.now()` read
37
+ * here, so assignment is fully reproducible in tests and replays. Runs
38
+ * identically with `MEGACOMPACT_VC7B` on or off.
39
+ */
40
+
41
+ import { createHash } from "node:crypto";
42
+
43
+ /**
44
+ * Experiment arms.
45
+ *
46
+ * A — control: the predecessor path, no VC7B crystal compiler.
47
+ * B — treatment: provider-safe compiled crystal boundaries.
48
+ * C — holdout: cache bypassed entirely, the uncached baseline that prices what
49
+ * the cache is being compared AGAINST.
50
+ */
51
+ export type ExperimentArm = "A" | "B" | "C";
52
+
53
+ /** The registered arms, in canonical bucket order. */
54
+ export const EXPERIMENT_ARMS: readonly ExperimentArm[] = ["A", "B", "C"] as const;
55
+
56
+ /** Bucket space: 10k buckets = 0.01% resolution (matches VC5C rollout). */
57
+ export const EXPERIMENT_BUCKETS = 10_000;
58
+
59
+ /**
60
+ * How a session came to be in its arm. Only `randomized` is causal evidence.
61
+ *
62
+ * `randomized` — derived from the stable hash over every eligible session.
63
+ * `forced` — an operator/test override; self-selected, never causal.
64
+ * `shadow` — computed for comparison but not served; never causal.
65
+ */
66
+ export type AssignmentSource = "randomized" | "forced" | "shadow";
67
+
68
+ /** A session's experiment assignment (VC7B contract type). */
69
+ export interface CacheExperimentV1 {
70
+ readonly schema: "cache-experiment-v1";
71
+ /** Names the experiment; folded into the hash so arms differ per experiment. */
72
+ readonly experimentId: string;
73
+ /** The session this assignment belongs to. */
74
+ readonly sessionId: string;
75
+ /** The assigned arm. */
76
+ readonly arm: ExperimentArm;
77
+ /** The session's stable bucket in `[0, EXPERIMENT_BUCKETS)`. */
78
+ readonly bucket: number;
79
+ /** How the arm was chosen — gates causal admissibility. */
80
+ readonly source: AssignmentSource;
81
+ /** INJECTED assignment timestamp (epoch ms). Never read from a clock here. */
82
+ readonly assignedAt: number;
83
+ }
84
+
85
+ /** VC7B experiment failure codes. */
86
+ export type ExperimentFailureCode =
87
+ /** A blank experiment id or session id — an unnamed experiment is unanalyzable. */
88
+ | "EXP_ID_INVALID"
89
+ /** An arm split that does not sum to the full bucket space. */
90
+ | "EXP_SPLIT_INVALID"
91
+ /** A forced arm that is not one of the registered arms. */
92
+ | "EXP_ARM_UNKNOWN";
93
+
94
+ /** The verdict of an assignment. */
95
+ export type ExperimentResult =
96
+ | { readonly ok: true; readonly assignment: CacheExperimentV1 }
97
+ | { readonly ok: false; readonly codes: readonly ExperimentFailureCode[] };
98
+
99
+ /**
100
+ * Traffic split across arms, in buckets. Must sum to exactly
101
+ * `EXPERIMENT_BUCKETS`: a split that sums to less would leave sessions
102
+ * unassigned, and one that sums to more would make the last arm unreachable —
103
+ * both silently bias the comparison, so both are rejected.
104
+ */
105
+ export interface ExperimentSplit {
106
+ readonly A: number;
107
+ readonly B: number;
108
+ readonly C: number;
109
+ }
110
+
111
+ /** Even three-way split (the default): 3334 / 3333 / 3333 = 10000. */
112
+ export const EVEN_SPLIT: ExperimentSplit = { A: 3334, B: 3333, C: 3333 };
113
+
114
+ /**
115
+ * Length-prefixed field framing, identical in spirit to the crystal key encoder:
116
+ * `<byteLength>:<value>` makes the concatenation injective, so experiment
117
+ * `"a"` + session `"b:c"` cannot collide with experiment `"a:b"` + session `"c"`.
118
+ * Without it, two different (experiment, session) pairs could share a bucket and
119
+ * a session could appear to switch arms when an experiment is renamed.
120
+ */
121
+ function field(value: string): string {
122
+ return `${Buffer.byteLength(value, "utf8")}:${value}`;
123
+ }
124
+
125
+ /**
126
+ * The stable bucket for a session: the low 32 bits of
127
+ * `sha256(experimentId, sessionId)`, modulo the bucket space.
128
+ *
129
+ * Deterministic and storage-free — this is what makes a lost assignment journal
130
+ * a non-event. Reading 4 bytes (rather than the whole digest) keeps the value in
131
+ * exact integer range; SHA-256's avalanche means any 32 bits are equidistributed.
132
+ */
133
+ export function experimentBucket(experimentId: string, sessionId: string): number {
134
+ const h = createHash("sha256")
135
+ .update(field(experimentId) + field(sessionId), "utf8")
136
+ .digest();
137
+ return h.readUInt32BE(0) % EXPERIMENT_BUCKETS;
138
+ }
139
+
140
+ /** Validate that a split covers the bucket space exactly once. */
141
+ export function validateSplit(split: ExperimentSplit): boolean {
142
+ for (const n of [split.A, split.B, split.C]) {
143
+ if (!Number.isSafeInteger(n) || n < 0) return false;
144
+ }
145
+ return split.A + split.B + split.C === EXPERIMENT_BUCKETS;
146
+ }
147
+
148
+ /**
149
+ * Map a bucket to an arm under a split. Arms occupy contiguous bucket ranges in
150
+ * the fixed order A, B, C, so the mapping is stable: widening arm C's share can
151
+ * never reshuffle a session already sitting in arm A.
152
+ */
153
+ export function armForBucket(bucket: number, split: ExperimentSplit): ExperimentArm {
154
+ if (bucket < split.A) return "A";
155
+ if (bucket < split.A + split.B) return "B";
156
+ return "C";
157
+ }
158
+
159
+ /**
160
+ * Assign a session to an experiment arm.
161
+ *
162
+ * The default path is `randomized`: bucket = stable hash, arm = bucket's range.
163
+ * Passing `forced` overrides the arm and downgrades the source (and therefore
164
+ * causal admissibility) — the bucket is still computed and reported so the
165
+ * override remains auditable against what the session WOULD have got.
166
+ *
167
+ * `assignedAt` is injected by the caller. Assignment is a pure function of its
168
+ * arguments, so the same session always yields the same arm no matter when, or
169
+ * how many times, it is asked.
170
+ */
171
+ export function assignExperiment(input: {
172
+ readonly experimentId: string;
173
+ readonly sessionId: string;
174
+ readonly assignedAt: number;
175
+ readonly split?: ExperimentSplit;
176
+ readonly forced?: ExperimentArm;
177
+ readonly shadow?: boolean;
178
+ }): ExperimentResult {
179
+ const codes: ExperimentFailureCode[] = [];
180
+ if (input.experimentId.trim() === "" || input.sessionId.trim() === "") {
181
+ codes.push("EXP_ID_INVALID");
182
+ }
183
+ const split = input.split ?? EVEN_SPLIT;
184
+ if (!validateSplit(split)) codes.push("EXP_SPLIT_INVALID");
185
+ if (input.forced !== undefined && !EXPERIMENT_ARMS.includes(input.forced)) {
186
+ codes.push("EXP_ARM_UNKNOWN");
187
+ }
188
+ if (codes.length > 0) return { ok: false, codes };
189
+
190
+ const bucket = experimentBucket(input.experimentId, input.sessionId);
191
+ const natural = armForBucket(bucket, split);
192
+ const arm = input.forced ?? natural;
193
+ // Precedence: a forced arm is self-selected, so it is never causal even when
194
+ // it happens to agree with the natural arm. Shadow is likewise non-causal.
195
+ const source: AssignmentSource =
196
+ input.forced !== undefined ? "forced" : input.shadow === true ? "shadow" : "randomized";
197
+
198
+ return {
199
+ ok: true,
200
+ assignment: {
201
+ schema: "cache-experiment-v1",
202
+ experimentId: input.experimentId,
203
+ sessionId: input.sessionId,
204
+ arm,
205
+ bucket,
206
+ source,
207
+ assignedAt: input.assignedAt,
208
+ },
209
+ };
210
+ }
211
+
212
+ /**
213
+ * Whether an assignment's telemetry may enter a causal interval.
214
+ *
215
+ * ONLY `randomized`. This single predicate is what keeps forced and shadow rows
216
+ * out of the causal aggregate; every consumer computing an interval must filter
217
+ * through it rather than re-deriving the rule.
218
+ */
219
+ export function isCausallyAdmissible(a: CacheExperimentV1): boolean {
220
+ return a.source === "randomized";
221
+ }
222
+
223
+ /**
224
+ * Keep only causally admissible assignments. The complement is not discarded by
225
+ * the caller — it is reported as `estimate` — but it never reaches an interval.
226
+ */
227
+ export function causalOnly(
228
+ assignments: readonly CacheExperimentV1[],
229
+ ): readonly CacheExperimentV1[] {
230
+ return assignments.filter(isCausallyAdmissible);
231
+ }
232
+
233
+ /**
234
+ * Whether every assignment for one session agrees on the arm (CACHE-RANDOM-003).
235
+ * A session that appears in two arms would contaminate both sides of the
236
+ * comparison, so this is asserted directly rather than assumed.
237
+ */
238
+ export function sessionArmsConsistent(
239
+ assignments: readonly CacheExperimentV1[],
240
+ ): boolean {
241
+ const bySession = new Map<string, ExperimentArm>();
242
+ for (const a of assignments) {
243
+ const seen = bySession.get(a.sessionId);
244
+ if (seen !== undefined && seen !== a.arm) return false;
245
+ bySession.set(a.sessionId, a.arm);
246
+ }
247
+ return true;
248
+ }
@@ -1,2 +0,0 @@
1
- import{j as e,B as r,r as n}from"./index-Do749WlW.js";import{C as o,a as d,b as i,c as x}from"./card-BFLnQJEo.js";async function K(){const s=await fetch("/api/vector-cortex/evaluation");if(!s.ok)throw new Error(`vector-cortex evaluation: ${s.status}`);return s.json()}async function C(){const s=await fetch("/api/vector-cortex/health");if(!s.ok)throw new Error(`vector-cortex health: ${s.status}`);return s.json()}async function Z(){const s=await fetch("/api/vector-cortex/topology");if(!s.ok)throw new Error(`vector-cortex topology: ${s.status}`);return s.json()}async function J(){const s=await fetch("/api/vector-cortex/query");if(!s.ok)throw new Error(`vector-cortex query: ${s.status}`);return s.json()}async function X(){const s=await fetch("/api/vector-cortex/shards");if(!s.ok)throw new Error(`vector-cortex shards: ${s.status}`);return s.json()}async function ee(){const s=await fetch("/api/vector-cortex/reconstruct");if(!s.ok)throw new Error(`vector-cortex reconstruct: ${s.status}`);return s.json()}async function se(){const s=await fetch("/api/vector-cortex/plans");if(!s.ok)throw new Error(`vector-cortex plans: ${s.status}`);return s.json()}async function te(){const s=await fetch("/api/vector-cortex/render");if(!s.ok)throw new Error(`vector-cortex render: ${s.status}`);return s.json()}async function re(){const s=await fetch("/api/vector-cortex/rollout");if(!s.ok)throw new Error(`vector-cortex rollout: ${s.status}`);return s.json()}async function ae(){const s=await fetch("/api/vector-cortex/closure-proof");if(!s.ok)throw new Error(`vector-cortex closure-proof: ${s.status}`);return s.json()}async function ne(){const s=await fetch("/api/vector-cortex/restore");if(!s.ok)throw new Error(`vector-cortex restore: ${s.status}`);return s.json()}async function le(){const s=await fetch("/api/vector-cortex/repair");if(!s.ok)throw new Error(`vector-cortex repair: ${s.status}`);return s.json()}async function ce(s="default"){const a=await fetch(`/api/vector-cortex/ledger?session=${encodeURIComponent(s)}`);if(!a.ok)throw new Error(`vector-cortex ledger: ${a.status}`);return a.json()}async function oe(s){const a=await fetch("/api/vector-cortex/breakers/reset",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({subsystem:s})});if(!a.ok)throw new Error(`vector-cortex reset: ${a.status}`);return a.json()}async function de(){const s=await fetch("/api/vector-cortex/cache-crystals");if(!s.ok)throw new Error(`vector-cortex cache-crystals: ${s.status}`);return s.json()}function t({label:s,value:a}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:s}),e.jsx("div",{className:"font-mono text-sm",children:a})]})}function ie({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Validated Prompt Renderer (VC5B)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Render fixtures",value:String(s.renderCount)}),e.jsx(t,{label:"Provider profiles",value:String(s.providerCount)}),e.jsx(t,{label:"Known profiles",value:String(s.knownProfiles.length)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only render conformance route — no prompt text or session payloads exposed."})]}):e.jsx("div",{className:"vc-empty",children:"Renderer disabled (VC5B off)."})})]})}function xe({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Live Graduated Rollout (VC5C)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Gate",value:`${s.gatePct}%`}),e.jsx(t,{label:"Exposed buckets",value:String(s.bucketCount)}),e.jsx(t,{label:"Total buckets",value:String(s.buckets)}),e.jsx(t,{label:"Promotion",value:s.promotionBlocked?"FROZEN":"OPEN"}),e.jsx(t,{label:"Events",value:String(s.events)}),e.jsx(t,{label:"Sessions",value:String(s.sessions)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only rollout route — no session payloads or bucket→session mappings exposed."})]}):e.jsx("div",{className:"vc-empty",children:"Rollout disabled (VC5C off)."})})]})}function ue({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Closure Optimization (VC6A)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Mode",value:s.mode}),e.jsx(t,{label:"Optimizations",value:String(s.optimizations)}),e.jsx(t,{label:"Proof rejections",value:String(s.proofRejections)}),e.jsx(t,{label:"Last rejection",value:s.lastRejection??"none"}),e.jsx(t,{label:"Retained edges",value:String(s.retainedEdgeTotal)}),e.jsx(t,{label:"Removed edges",value:String(s.removedEdgeTotal)}),e.jsx(t,{label:"Conservative walks",value:String(s.conservativeTraversalTotal)}),e.jsx(t,{label:"Optimized walks",value:String(s.optimizedTraversalTotal)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only closure diagnostics — aggregate counts only; per-edge proof rows, node ids, and source payloads are never exposed (SECURITY_PRIVACY)."})]}):e.jsx("div",{className:"vc-empty",children:"Closure optimization disabled (VC6A off) — conservative VC4C closure used directly (mode B)."})})]})}function he({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Exact Source Restoration (VC6B)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Mode",value:s.mode}),e.jsx(t,{label:"Restore attempts",value:String(s.restoreAttempts)}),e.jsx(t,{label:"Restored",value:String(s.restoredCount)}),e.jsx(t,{label:"Missing source",value:String(s.missingCount)}),e.jsx(t,{label:"Digest rejections",value:String(s.digestRejections)}),e.jsx(t,{label:"Last rejection",value:s.lastRejection??"none"}),e.jsx(t,{label:"Updated",value:s.updatedAt})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only restore diagnostics — counts and HEAL_RESTORE_* codes only. There is no payload endpoint: restored bytes, span ids, node ids, and ledger text are never exposed (SECURITY_PRIVACY)."})]}):e.jsx("div",{className:"vc-empty",children:"Exact source restoration disabled (VC6B off) — no exact source is restored; omitted context is disclosed as loss (mode C)."})})]})}function je({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Self-Healing Derived State (VC6C)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Mode",value:s.mode}),e.jsx(t,{label:"Repair attempts",value:String(s.repairAttempts)}),e.jsx(t,{label:"Repairs planned",value:String(s.repairsPlanned)}),e.jsx(t,{label:"Pointers switched",value:String(s.pointersSwitched)}),e.jsx(t,{label:"Backoffs",value:String(s.backoffs)}),e.jsx(t,{label:"Last backoff",value:s.lastBackoffMs===null?"none":`${s.lastBackoffMs}ms`}),e.jsx(t,{label:"Last failure",value:s.lastFailure??"none"}),e.jsx(t,{label:"Updated",value:s.updatedAt})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only repair diagnostics — counts and HEAL_REPAIR_* codes only. There is no payload endpoint: subsystem source bytes, gap ranges, high-water marks, root digests, and ledger text are never exposed (SECURITY_PRIVACY)."})]}):e.jsx("div",{className:"vc-empty",children:"Self-healing derived state disabled (VC6C off) — no controller detects gaps or rebuilds derived state; derived state is reported disabled rather than healed (mode C)."})})]})}function me({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Frozen Range Crystals (VC7A)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Mode",value:s.mode}),e.jsx(t,{label:"Crystals",value:String(s.crystalCount)}),e.jsx(t,{label:"Frozen bytes",value:String(s.totalBytes)}),e.jsx(t,{label:"Hits",value:String(s.hits)}),e.jsx(t,{label:"Misses",value:String(s.misses)}),e.jsx(t,{label:"Hit bytes",value:String(s.hitBytes)}),e.jsx(t,{label:"Writes",value:String(s.writes)}),e.jsx(t,{label:"Duplicate writes",value:String(s.duplicateWrites)}),e.jsx(t,{label:"Collisions",value:String(s.collisions)}),e.jsx(t,{label:"Last failure",value:s.lastFailure??"none"}),e.jsx(t,{label:"Updated",value:s.updatedAt})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only crystal diagnostics — counts, byte volumes, and CRY_* codes only. A crystal is a frozen rendered prompt, so frozen bytes, covered ranges, span/covered digests, request digests, and session ids are never exposed (SECURITY_PRIVACY). Keys exclude the global ledger frontier, so an unrelated append does not invalidate a crystal; a covered-byte, dependency, renderer, or profile change does. Collisions mean two renders of one identity disagreed — the stored crystal is never overwritten."})]}):e.jsx("div",{className:"vc-empty",children:"Frozen range crystals disabled (VC7A off) — nothing is served from the crystal cache and every render is produced fresh; the cache is reported bypassed rather than hit (mode C)."})})]})}function ge({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Dual-Tier Shards (VC4A)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Semantic shards",value:String(s.semanticCount)}),e.jsx(t,{label:"Exact shards",value:String(s.exactCount)}),e.jsx(t,{label:"Byte total",value:String(s.byteTotal)}),e.jsx(t,{label:"Protected bytes",value:String(s.protectedByteTotal)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only count/byte aggregate; staged in-memory this sprint."})]}):e.jsx("div",{className:"vc-empty",children:"Dual-tier shards disabled (VC4A off)."})})]})}function fe({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Reconstruction Fidelity (VC4C)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"Closure attempts",value:String(s.closureAttempts)}),e.jsx(t,{label:"Closure rejections",value:String(s.closureRejections)}),e.jsx(t,{label:"Validated",value:String(s.validatedCount)}),e.jsx(t,{label:"Invalidated",value:String(s.invalidatedCount)}),e.jsx(t,{label:"Span total",value:String(s.spanTotal)}),e.jsx(t,{label:"Byte total",value:String(s.byteTotal)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only closure/validation aggregate; staged in-memory this sprint."})]}):e.jsx("div",{className:"vc-empty",children:"Reconstruction fidelity disabled (VC4C off)."})})]})}function ve({view:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Plan Manifests (VC5A)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"DAG fixtures",value:String(s.dagCount)}),e.jsx(t,{label:"Plan fixtures",value:String(s.plannerCount)}),e.jsx(t,{label:"Plans exposed",value:String(s.plans.length)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only plan manifests only — no session payloads or prompt text. Per-run plan outputs are staged in-memory this sprint."})]}):e.jsx("div",{className:"vc-empty",children:"PromptDagV1 + budgeted planner disabled (VC5A off)."})})]})}function pe({topology:s,query:a}){return e.jsxs(e.Fragment,{children:[e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Derived Cortex Store (VC3A)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-3",children:[e.jsx(t,{label:"Generation",value:s.generationId??"—"}),e.jsx(t,{label:"Ordinal",value:s.ordinal??"—"}),e.jsx(t,{label:"Records",value:String(s.recordCount)}),e.jsx(t,{label:"Frontier (HW)",value:s.sourceHighWater}),e.jsx(t,{label:"Root digest",value:s.rootDigest?s.rootDigest.slice(0,16):"—"}),s.nodes!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx(t,{label:"Nodes",value:String(s.nodes?.length??0)}),e.jsx(t,{label:"Edges",value:String(s.edges?.length??0)}),e.jsx(t,{label:"Graph digest",value:s.generationDigest?s.generationDigest.slice(0,16):"—"})]})]}),s.nodes!==void 0&&(s.edges?.length??0)>0&&e.jsxs("div",{className:"mt-4 max-h-56 overflow-y-auto",children:[e.jsx("div",{className:"mb-1 text-xs font-medium text-muted-foreground",children:"Topology edges (VC3B)"}),e.jsxs("table",{className:"w-full text-left text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border/50 text-muted-foreground",children:[e.jsx("th",{className:"py-1 pr-2",children:"source"}),e.jsx("th",{className:"py-1 pr-2",children:"target"}),e.jsx("th",{className:"py-1 pr-2",children:"head"}),e.jsx("th",{className:"py-1 pr-2",children:"dir"}),e.jsx("th",{className:"py-1",children:"score"})]})}),e.jsx("tbody",{children:s.edges?.map((u,h)=>e.jsxs("tr",{className:"border-b border-border/30",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:u.source}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:u.target}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:u.head}),e.jsx("td",{className:"py-1 pr-2",children:u.direction}),e.jsx("td",{className:"py-1 font-mono",children:u.score})]},`${u.source}-${u.target}-${u.head}-${h}`))})]})]})]}):e.jsx("div",{className:"vc-empty",children:"Cortex store disabled (VC3A off)."})})]}),e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Topology Query Diagnostics (VC3C)"}),a?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:a?.enabled?e.jsx("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-3",children:e.jsx(t,{label:"Router version",value:String(a.routerVersion)})}):e.jsx("div",{className:"vc-empty",children:"Query diagnostics unavailable (VC3C off)."})})]})]})}function be({ledger:s}){return e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Occurrence Ledger (VC1B)"}),s?.enabled?e.jsx(r,{variant:"success",children:"ACTIVE"}):e.jsx(r,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:s?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 grid grid-cols-2 gap-4 md:grid-cols-3",children:[e.jsx(t,{label:"Session",value:s.session}),e.jsx(t,{label:"High-water",value:s.highWater}),e.jsx(t,{label:"Occurrences",value:String(s.count)})]}),s.occurrences.length===0?e.jsx("div",{className:"vc-empty",children:"No occurrences recorded."}):e.jsx("div",{className:"max-h-64 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-left text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border/50 text-muted-foreground",children:[e.jsx("th",{className:"py-1 pr-2",children:"seq"}),e.jsx("th",{className:"py-1 pr-2",children:"eventId"}),e.jsx("th",{className:"py-1 pr-2",children:"kind"}),e.jsx("th",{className:"py-1 pr-2",children:"toolCall"}),e.jsx("th",{className:"py-1",children:"digest"})]})}),e.jsx("tbody",{children:s.occurrences.map(a=>e.jsxs("tr",{className:"border-b border-border/30",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:a.seq}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:a.eventId}),e.jsx("td",{className:"py-1 pr-2",children:a.kind}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:a.toolCallId??"—"}),e.jsx("td",{className:"max-w-[180px] truncate font-mono text-muted-foreground",children:a.digest})]},`${a.seq}-${a.eventId}`))})]})})]}):e.jsx("div",{className:"vc-empty",children:"Ledger disabled (VC1B off)."})})]})}function m({mode:s,count:a}){return e.jsxs("div",{className:"flex items-center justify-between border-b border-border/50 py-1 text-sm",children:[e.jsxs("span",{className:"text-muted-foreground",children:["Mode ",s]}),e.jsx("span",{className:"font-mono",children:a})]})}function Ne(){const[s,a]=n.useState(null),[u,h]=n.useState(null),[y,N]=n.useState(!0),[c,g]=n.useState(null),[f,v]=n.useState(null),[S,V]=n.useState(null),[R,E]=n.useState(null),[F,A]=n.useState(null),[k,T]=n.useState(null),[I,$]=n.useState(null),[w,P]=n.useState(null),[O,M]=n.useState(null),[B,L]=n.useState(null),[D,H]=n.useState(null),[z,Y]=n.useState(null),[_,U]=n.useState(null),[G,W]=n.useState(null),j=n.useCallback(()=>{K().then(a).catch(l=>h(l instanceof Error?l.message:String(l))).finally(()=>N(!1)),C().then(g).catch(()=>{}),ce().then(V).catch(()=>{}),Z().then(E).catch(()=>{}),J().then(A).catch(()=>{}),X().then(T).catch(()=>{}),ee().then($).catch(()=>{}),se().then(P).catch(()=>{}),te().then(M).catch(()=>{}),re().then(L).catch(()=>{}),ae().then(H).catch(()=>{}),ne().then(Y).catch(()=>{}),le().then(U).catch(()=>{}),de().then(W).catch(()=>{})},[]);n.useEffect(()=>{j();const l=setInterval(j,5e3);return()=>clearInterval(l)},[j]);const q=()=>{oe("provider").then(l=>(v(`Breaker "${l.subsystem}" ${l.state}; evidence retained: ${l.failures} failures / ${l.attempts} attempts`),C())).then(g).catch(l=>v(l instanceof Error?l.message:String(l)))};if(y&&!s)return e.jsx("div",{className:"vc-loading",children:"Loading vector-cortex evaluation…"});if(u&&!s)return e.jsxs("div",{className:"vc-error",children:["Error: ",u]});if(!s)return e.jsx("div",{className:"vc-empty",children:"No evaluation data available."});const p=Math.max(1,...s.histogram.cells,s.histogram.overflow);return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-lg font-semibold",children:"Vector Cortex Evaluation"}),s.enabled?e.jsx(r,{variant:"warning",children:"OBSERVER PENDING (A)"}):e.jsx(r,{variant:"danger",children:"MODE C (OFF)"})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-3",children:[e.jsxs(o,{children:[e.jsx(d,{children:e.jsx(i,{children:"Samples"})}),e.jsxs(x,{children:[e.jsx("div",{className:"text-3xl font-bold",children:s.samples}),e.jsxs("div",{className:"mt-2 flex flex-col",children:[e.jsx(m,{mode:"A",count:s.byMode.A}),e.jsx(m,{mode:"B",count:s.byMode.B}),e.jsx(m,{mode:"C",count:s.byMode.C})]})]})]}),e.jsxs(o,{className:"md:col-span-2",children:[e.jsx(d,{children:e.jsx(i,{children:"Latency Histogram (ms, inclusive edges)"})}),e.jsxs(x,{children:[e.jsxs("div",{className:"flex items-end gap-2",style:{height:160},children:[s.histogram.edges.map((l,b)=>{const Q=s.histogram.cells[b]/p*140;return e.jsxs("div",{className:"flex flex-1 flex-col items-center gap-1",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s.histogram.cells[b]}),e.jsx("div",{className:"w-full rounded-t",style:{height:Math.max(2,Q),background:"#6366f1"}}),e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["≤",l]})]},l)}),e.jsxs("div",{className:"flex flex-1 flex-col items-center gap-1",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s.histogram.overflow}),e.jsx("div",{className:"w-full rounded-t",style:{height:Math.max(2,s.histogram.overflow/p*140),background:"#f87171"}}),e.jsx("span",{className:"text-[10px] text-muted-foreground",children:">250"})]})]}),e.jsxs("div",{className:"mt-1 text-xs text-muted-foreground",children:["Total: ",s.histogram.total," · Rejects: ",s.rejects.length]})]})]})]}),e.jsxs(o,{children:[e.jsx(d,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(i,{children:"Live Safety Envelope (VC0C)"}),e.jsxs("div",{className:"flex items-center gap-2",children:[c?.stateSource==="ephemeral"&&e.jsx(r,{variant:"outline",children:"EPHEMERAL (non-live)"}),e.jsx("button",{onClick:q,disabled:!c?.enabled,className:"rounded border border-border px-2 py-1 text-xs disabled:opacity-50",children:"Reset Cooldown"})]})]})}),e.jsxs(x,{children:[f&&e.jsx("div",{className:"mb-2 text-xs text-muted-foreground",children:f}),c?e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(t,{label:"State",value:c.state}),e.jsx(t,{label:"Mode",value:c.mode}),e.jsx(t,{label:"Window",value:`${c.windowMs}ms`}),e.jsx(t,{label:"Probes",value:String(c.probeCount)}),e.jsx(t,{label:"Backoff",value:`${c.backoffDelayMs}ms`}),e.jsx(t,{label:"Failures",value:`${c.failures}/${c.attempts}`}),e.jsx(t,{label:"Frontier",value:c.stateSource==="ephemeral"?"non-live":c.frontierFrozen?"FROZEN":"LIVE"}),e.jsx(t,{label:"Spool lag",value:String(c.spoolLag)}),e.jsx(t,{label:"Encoder mode",value:c.encoderMode}),e.jsx(t,{label:"Encoder asset",value:c.encoderAssetDigest?c.encoderAssetDigest.slice(0,12):"none"})]}):e.jsx("div",{className:"vc-empty",children:"Health unavailable (VC0C off)."})]})]}),e.jsx(pe,{topology:R,query:F}),e.jsx(ge,{view:k}),e.jsx(fe,{view:I}),e.jsx(ve,{view:w}),e.jsx(ie,{view:O}),e.jsx(xe,{view:B}),e.jsx(ue,{view:D}),e.jsx(he,{view:z}),e.jsx(je,{view:_}),e.jsx(me,{view:G}),e.jsx(be,{ledger:S})]})}export{Ne as default};
2
- //# sourceMappingURL=VectorCortexTab-94fqVjat.js.map