pi-mega-compact 0.20.9 → 0.20.10

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 (87) hide show
  1. package/dist/config/vector-cortex.js +16 -0
  2. package/dist/config.js +1 -1
  3. package/dist/extensions/dashboard-server/route-dispatch.js +5 -0
  4. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
  5. package/dist/extensions/dashboard-server/routes-vector-cortex-repair.js +63 -0
  6. package/dist/src/config/vector-cortex.js +16 -0
  7. package/dist/src/config.js +1 -1
  8. package/dist/src/vector-cortex/heal/_repair-fixture.js +70 -0
  9. package/dist/src/vector-cortex/heal/controller.js +165 -0
  10. package/dist/src/vector-cortex/heal/rebuild.js +136 -0
  11. package/dist/src/vector-cortex/heal/repair-emit.js +83 -0
  12. package/dist/src/vector-cortex/heal/repair-types.js +74 -0
  13. package/dist/src/vector-cortex/heal/types.js +1 -0
  14. package/dist/vector-cortex/heal/_repair-fixture.js +70 -0
  15. package/dist/vector-cortex/heal/controller.js +165 -0
  16. package/dist/vector-cortex/heal/rebuild.js +136 -0
  17. package/dist/vector-cortex/heal/repair-emit.js +83 -0
  18. package/dist/vector-cortex/heal/repair-types.js +74 -0
  19. package/dist/vector-cortex/heal/types.js +1 -0
  20. package/extensions/dashboard-client/dist/assets/{AreaChart-fxyq2KaH.js → AreaChart-BDMjyRQp.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{AreaChart-fxyq2KaH.js.map → AreaChart-BDMjyRQp.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{BarChart-D5EqAINP.js → BarChart-CqzPzOkj.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{BarChart-D5EqAINP.js.map → BarChart-CqzPzOkj.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{CacheTab-D4UWbzLo.js → CacheTab-Bo8SH9q8.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{CacheTab-D4UWbzLo.js.map → CacheTab-Bo8SH9q8.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{EventsTab-BiXquGrX.js → EventsTab-DIEs6zC-.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{EventsTab-BiXquGrX.js.map → EventsTab-DIEs6zC-.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{HealthTab-D5QvoTjy.js → HealthTab-3a8IjwIK.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{HealthTab-D5QvoTjy.js.map → HealthTab-3a8IjwIK.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cy_-CWgM.js → MaintenanceTab-CdKwAcXo.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cy_-CWgM.js.map → MaintenanceTab-CdKwAcXo.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DrAjgGOR.js → MemoryMapTab-D2hHuNj-.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DrAjgGOR.js.map → MemoryMapTab-D2hHuNj-.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{MetricsTab-BvPHcuFN.js → MetricsTab-CFhIhqrr.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{MetricsTab-BvPHcuFN.js.map → MetricsTab-CFhIhqrr.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{OverviewTab-DsbIigOQ.js → OverviewTab-Dzp5ZoiA.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{OverviewTab-DsbIigOQ.js.map → OverviewTab-Dzp5ZoiA.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{ReposTab-7v_uZX_a.js → ReposTab-CFJT9mDR.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{ReposTab-7v_uZX_a.js.map → ReposTab-CFJT9mDR.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{SessionsTab-BXGrv-6C.js → SessionsTab-BhP1z6_y.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{SessionsTab-BXGrv-6C.js.map → SessionsTab-BhP1z6_y.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/{SetupTab-QRUXa65y.js → SetupTab-2Glh7MKk.js} +2 -2
  43. package/extensions/dashboard-client/dist/assets/{SetupTab-QRUXa65y.js.map → SetupTab-2Glh7MKk.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-p327ZZKT.js → TimeSavedCard-DmwBDhkw.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-p327ZZKT.js.map → TimeSavedCard-DmwBDhkw.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{TurnsTab-BcmBSlik.js → TurnsTab-CYIaOUUZ.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{TurnsTab-BcmBSlik.js.map → TurnsTab-CYIaOUUZ.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD7vGaRS.js +2 -0
  49. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD7vGaRS.js.map +1 -0
  50. package/extensions/dashboard-client/dist/assets/{WikiTab-DLXFMuNy.js → WikiTab-CP-JEd17.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{WikiTab-DLXFMuNy.js.map → WikiTab-CP-JEd17.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/{button-C9CghmRx.js → button-B1RhLsGs.js} +2 -2
  53. package/extensions/dashboard-client/dist/assets/{button-C9CghmRx.js.map → button-B1RhLsGs.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{card-DWU-1y3t.js → card-BLPT2-8G.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{card-DWU-1y3t.js.map → card-BLPT2-8G.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Dayy9dGn.js → generateCategoricalChart-DVOMJzL2.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Dayy9dGn.js.map → generateCategoricalChart-DVOMJzL2.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{index-D9PsW3VZ.js → index-CuLdiHRl.js} +3 -3
  59. package/extensions/dashboard-client/dist/assets/{index-D9PsW3VZ.js.map → index-CuLdiHRl.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{switch-CnLFAmVT.js → switch-C5tqzhcl.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{switch-CnLFAmVT.js.map → switch-C5tqzhcl.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{toggle-HN5C7_vy.js → toggle-HcM6W2Yl.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{toggle-HN5C7_vy.js.map → toggle-HcM6W2Yl.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/{useSSE-DoJfk3Ce.js → useSSE-BtWUs2kL.js} +2 -2
  65. package/extensions/dashboard-client/dist/assets/{useSSE-DoJfk3Ce.js.map → useSSE-BtWUs2kL.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/index.html +1 -1
  67. package/extensions/dashboard-client/src/api/vector-cortex.ts +9 -0
  68. package/extensions/dashboard-client/src/tabs/VectorCortexRepairCard.tsx +43 -0
  69. package/extensions/dashboard-client/src/tabs/VectorCortexShardsCard.tsx +89 -0
  70. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +14 -60
  71. package/extensions/dashboard-client/src/types/vector-cortex.ts +17 -0
  72. package/extensions/dashboard-server/api-contracts/vector-cortex-heal.ts +38 -0
  73. package/extensions/dashboard-server/api-contracts/vector-cortex.ts +1 -0
  74. package/extensions/dashboard-server/route-dispatch.ts +4 -0
  75. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
  76. package/extensions/dashboard-server/routes-vector-cortex-repair.ts +72 -0
  77. package/package.json +1 -1
  78. package/src/config/vector-cortex.ts +17 -0
  79. package/src/config.ts +1 -0
  80. package/src/vector-cortex/heal/_repair-fixture.ts +138 -0
  81. package/src/vector-cortex/heal/controller.ts +189 -0
  82. package/src/vector-cortex/heal/rebuild.ts +200 -0
  83. package/src/vector-cortex/heal/repair-emit.ts +118 -0
  84. package/src/vector-cortex/heal/repair-types.ts +227 -0
  85. package/src/vector-cortex/heal/types.ts +28 -0
  86. package/extensions/dashboard-client/dist/assets/VectorCortexTab-D2fjKNyT.js +0 -2
  87. package/extensions/dashboard-client/dist/assets/VectorCortexTab-D2fjKNyT.js.map +0 -1
@@ -0,0 +1,200 @@
1
+ /**
2
+ * vector-cortex/heal/rebuild.ts — VC6C generation rebuild + atomic pointer switch.
3
+ *
4
+ * Executes what `controller.ts` planned: materialize a NEW generation, verify its
5
+ * root digest, and only then flip the live pointer.
6
+ *
7
+ * COPY, VERIFY, SWITCH — in that order, always.
8
+ *
9
+ * 1. COPY. The rebuild writes into `plan.generation` (always `current + 1`),
10
+ * never into the live generation. The thing currently being served is never
11
+ * the thing being modified, so a crash mid-rebuild leaves a complete old
12
+ * generation and a partial new one — never a torn live one.
13
+ * 2. VERIFY. The new generation's root digest must equal the digest the plan
14
+ * pinned. This is the ONLY gate on the pointer.
15
+ * 3. SWITCH. `switchPointer` moves the pointer iff verification passed.
16
+ *
17
+ * A FAILED VERIFICATION DELETES NO EVIDENCE. On mismatch we keep the old pointer
18
+ * AND leave the new generation on disk. That is deliberate: the corrupt
19
+ * generation is the only artifact that can explain WHY the rebuild was wrong, and
20
+ * a self-healing system that tidies up its failures is a system that cannot be
21
+ * debugged. Cleanup is a separate, explicit operator action.
22
+ *
23
+ * CRASH SAFETY IS A CONSEQUENCE OF THE ORDER, NOT AN EXTRA STEP. The pointer is
24
+ * the single atomic commit point. Kill the process after step 1 or 2 and the old
25
+ * pointer is still live, so the next start serves the prior generation and simply
26
+ * re-plans — the orphaned generation is inert. This is what
27
+ * `rebuild-chaos.test.ts` pins.
28
+ *
29
+ * THE TRIAD (independent algorithms, per TRIAD_RESILIENCE).
30
+ * A — TARGETED: rebuild only `plan.range`, reusing the prior generation for
31
+ * everything outside it. Cheap; needs a healthy prior generation.
32
+ * B — FULL DETERMINISTIC: re-derive the whole subsystem from the byte ledger,
33
+ * reusing NOTHING. Independent of A: it shares no index, no prior
34
+ * generation, and no incremental state, so a bug or corruption that breaks
35
+ * A cannot break B the same way.
36
+ * C — DISABLE DERIVED STATE: no rebuild at all. Mode C is a real outcome, not
37
+ * an error path, and it MUST state its loss of old semantic context — the
38
+ * subsystem serves nothing rather than serving something wrong.
39
+ *
40
+ * PURE. `node:crypto` only — no storage, no console, no clock, no network
41
+ * (PREVENT-PI-004 / PREVENT-011). Callers own persistence; this module owns the
42
+ * decision and the digest arithmetic, which is what makes it fixture-testable.
43
+ */
44
+
45
+ import { createHash } from "node:crypto";
46
+
47
+ import type { Mode, RepairFailureCode, ShardRange } from "./repair-types.js";
48
+
49
+ /**
50
+ * Everything a rebuild needs. `sourceBytes` is the materialized content of the
51
+ * new generation; `expectedDigest` is the root digest the plan pinned and the
52
+ * ONLY thing that authorizes a pointer switch.
53
+ */
54
+ export interface RebuildInput {
55
+ readonly subsystem: string;
56
+ readonly range: ShardRange;
57
+ /** The NEW generation being written (never the live one). */
58
+ readonly generation: number;
59
+ /** The rebuilt generation's content. */
60
+ readonly sourceBytes: Uint8Array;
61
+ /** Root digest, BARE lowercase hex (the ExactShardV1.digest convention). */
62
+ readonly expectedDigest: string;
63
+ }
64
+
65
+ /**
66
+ * The rebuild verdict.
67
+ *
68
+ * The failure arm still carries `generation` so the caller can name the orphaned
69
+ * generation in a log or an operator prompt — the evidence is retained, so its
70
+ * identity must be reportable.
71
+ */
72
+ export type RebuildResult =
73
+ | {
74
+ readonly ok: true;
75
+ readonly generation: number;
76
+ /** The VERIFIED root digest (equals `expectedDigest`). */
77
+ readonly digest: string;
78
+ readonly mode: Mode;
79
+ }
80
+ | {
81
+ readonly ok: false;
82
+ readonly code: RepairFailureCode;
83
+ readonly generation: number;
84
+ readonly mode: Mode;
85
+ /** Set on mode C: the caller MUST be told derived context is gone. */
86
+ readonly semanticLossStated?: boolean;
87
+ };
88
+
89
+ /** The outcome of a pointer switch: which generation is live afterwards. */
90
+ export interface PointerSwitch {
91
+ readonly switched: boolean;
92
+ /** The live generation AFTER the attempt (unchanged when `switched` is false). */
93
+ readonly generation: number;
94
+ }
95
+
96
+ /** Root digest of a generation's bytes: SHA-256, bare lowercase hex. */
97
+ export function rootDigest(bytes: Uint8Array): string {
98
+ return createHash("sha256").update(bytes).digest("hex");
99
+ }
100
+
101
+ /**
102
+ * Materialize + verify one generation.
103
+ *
104
+ * Hashes the rebuilt bytes and compares to the pinned root digest. A mismatch
105
+ * returns `HEAL_REPAIR_DIGEST_MISMATCH` and — critically — the caller must NOT
106
+ * switch the pointer; `switchPointer` enforces that structurally by requiring the
107
+ * verified flag.
108
+ *
109
+ * An EMPTY rebuild is a failure, not an empty success: a generation with no bytes
110
+ * would hash to the digest of nothing, and if a plan ever pinned that digest an
111
+ * empty rebuild would "verify" and the pointer would flip to nothing at all. It
112
+ * is reported as `HEAL_REBUILD_FAILED` because the rebuild produced no artifact.
113
+ */
114
+ export function rebuildGeneration(
115
+ input: RebuildInput,
116
+ mode: Mode = "A",
117
+ ): RebuildResult {
118
+ if (input.sourceBytes.length === 0) {
119
+ return {
120
+ ok: false,
121
+ code: "HEAL_REBUILD_FAILED",
122
+ generation: input.generation,
123
+ mode,
124
+ };
125
+ }
126
+ const digest = rootDigest(input.sourceBytes);
127
+ if (digest !== input.expectedDigest) {
128
+ // Evidence retained: the caller keeps the generation on disk for inspection.
129
+ return {
130
+ ok: false,
131
+ code: "HEAL_REPAIR_DIGEST_MISMATCH",
132
+ generation: input.generation,
133
+ mode,
134
+ };
135
+ }
136
+ return { ok: true, generation: input.generation, digest, mode };
137
+ }
138
+
139
+ /**
140
+ * The atomic commit point: flip the live pointer iff the new generation verified.
141
+ *
142
+ * `verified` is a required argument rather than something re-derived here, so a
143
+ * caller cannot switch the pointer without having gone through
144
+ * `rebuildGeneration` — "switch without verifying" is not expressible.
145
+ *
146
+ * A non-monotonic switch is also refused: the new generation must be strictly
147
+ * greater than the current one. Replaying a stale plan after a restart would
148
+ * otherwise roll the pointer BACKWARDS onto an older generation, silently
149
+ * un-healing the subsystem.
150
+ */
151
+ export function switchPointer(
152
+ currentGen: number,
153
+ newGen: number,
154
+ verified: boolean,
155
+ ): PointerSwitch {
156
+ if (!verified) return { switched: false, generation: currentGen };
157
+ if (newGen <= currentGen) return { switched: false, generation: currentGen };
158
+ return { switched: true, generation: newGen };
159
+ }
160
+
161
+ /**
162
+ * Apply the triad arm for a rebuild.
163
+ *
164
+ * A and B run the same verification (a digest is a digest) but are reached by
165
+ * INDEPENDENT production paths: A reuses the prior generation and rebuilds only
166
+ * the planned range, while B re-derives everything from the byte ledger sharing
167
+ * no index or incremental state with A. C performs no rebuild at all and states
168
+ * its loss.
169
+ */
170
+ export function applyTriad(mode: Mode, input: RebuildInput): RebuildResult {
171
+ if (mode === "C") {
172
+ // Derived state disabled: no rebuild, and the loss of old semantic context
173
+ // is DISCLOSED rather than papered over with a stale or partial generation.
174
+ return {
175
+ ok: false,
176
+ code: "HEAL_REBUILD_FAILED",
177
+ generation: input.generation,
178
+ mode: "C",
179
+ semanticLossStated: true,
180
+ };
181
+ }
182
+ return rebuildGeneration(input, mode);
183
+ }
184
+
185
+ /**
186
+ * Convenience: rebuild then switch, returning both halves.
187
+ *
188
+ * The pointer moves only on a verified rebuild, so a failed verification yields
189
+ * `switched:false` with the ORIGINAL generation still live and the new (corrupt)
190
+ * generation left intact on disk for inspection.
191
+ */
192
+ export function rebuildAndSwitch(
193
+ input: RebuildInput,
194
+ currentGen: number,
195
+ mode: Mode = "A",
196
+ ): { readonly result: RebuildResult; readonly pointer: PointerSwitch } {
197
+ const result = applyTriad(mode, input);
198
+ const pointer = switchPointer(currentGen, input.generation, result.ok);
199
+ return { result, pointer };
200
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * vector-cortex/heal/repair-emit.ts — VC6C event reporter seam.
3
+ *
4
+ * Mirrors `./restore-emit.ts`: a thin `safe()` wrapper around an optional
5
+ * injected `emit`, and the three event names the sprint spec requires verbatim:
6
+ * - `vector_cortex_repair_planned` — a gap was detected, rebuild queued.
7
+ * - `vector_cortex_repair_pointer_switched`— a verified generation went live.
8
+ * - `vector_cortex_repair_backoff` — suppressed (rate limit) or failed.
9
+ *
10
+ * FLAG SEMANTICS. `detectGaps` / `planRebuild` / `rebuildGeneration` /
11
+ * `switchPointer` are PURE arithmetic and run REGARDLESS of `MEGACOMPACT_VC6C`.
12
+ * The flag gates ONLY this reporting + dashboard seam: with the flag off we still
13
+ * detect gaps, still verify digests, and still refuse unverified pointer
14
+ * switches — we just do not announce it under the VC6C event namespace. That is
15
+ * what makes flag-off byte-identical to VC6B: the computation is never skipped,
16
+ * only the emission.
17
+ *
18
+ * PAYLOAD DISCIPLINE. These events carry the SUBSYSTEM NAME, generation numbers,
19
+ * timings, and codes — never rebuilt bytes, never a root digest of user content,
20
+ * never a seq range's contents. The subsystem name is an operator-facing
21
+ * identifier ("topology"), not user data. A repair event is exactly the place
22
+ * where an unguarded `payload` field would leak a rebuilt transcript into a log.
23
+ *
24
+ * No console, no storage, no network (PREVENT-PI-004 / PREVENT-011). Every line
25
+ * is a structured JSON event with `ts` + `event`.
26
+ */
27
+
28
+ import { VC6C_ENABLED } from "../../config/vector-cortex.js";
29
+ import type { Mode, RepairEventName, RepairFailureCode } from "./repair-types.js";
30
+
31
+ /** Optional emit fn injected by the runtime; tests pass `undefined`. */
32
+ export type RepairEmit = (name: string, payload: unknown) => void;
33
+
34
+ /** Run `fn` only when an emit exists; a reporting failure is never fatal. */
35
+ function safe(emit: RepairEmit | undefined, fn: (emit: RepairEmit) => void): void {
36
+ if (emit === undefined) return;
37
+ try {
38
+ fn(emit);
39
+ } catch {
40
+ // Non-fatal: a reporting failure must never break the agent loop.
41
+ }
42
+ }
43
+
44
+ /** The event names VC6C emits, exported for the dashboard seam and tests. */
45
+ export const REPAIR_EVENT_NAMES: readonly RepairEventName[] = [
46
+ "vector_cortex_repair_planned",
47
+ "vector_cortex_repair_pointer_switched",
48
+ "vector_cortex_repair_backoff",
49
+ ] as const;
50
+
51
+ /** Report a planned rebuild: which subsystem, which generation, what delay. */
52
+ export function reportRepairPlanned(
53
+ emit: RepairEmit | undefined,
54
+ payload: {
55
+ readonly subsystem: string;
56
+ readonly generation: number;
57
+ readonly backoffMs: number;
58
+ readonly gapSize: number;
59
+ },
60
+ ): void {
61
+ if (!VC6C_ENABLED()) return;
62
+ safe(emit, (e) =>
63
+ e("vector_cortex_repair_planned", {
64
+ ts: undefined,
65
+ event: "vector_cortex_repair_planned",
66
+ subsystem: payload.subsystem,
67
+ generation: payload.generation,
68
+ backoffMs: payload.backoffMs,
69
+ gapSize: payload.gapSize,
70
+ }),
71
+ );
72
+ }
73
+
74
+ /** Report the atomic commit: a verified generation became live. */
75
+ export function reportRepairPointerSwitched(
76
+ emit: RepairEmit | undefined,
77
+ payload: {
78
+ readonly subsystem: string;
79
+ readonly fromGeneration: number;
80
+ readonly toGeneration: number;
81
+ readonly mode: Mode;
82
+ },
83
+ ): void {
84
+ if (!VC6C_ENABLED()) return;
85
+ safe(emit, (e) =>
86
+ e("vector_cortex_repair_pointer_switched", {
87
+ ts: undefined,
88
+ event: "vector_cortex_repair_pointer_switched",
89
+ subsystem: payload.subsystem,
90
+ fromGeneration: payload.fromGeneration,
91
+ toGeneration: payload.toGeneration,
92
+ mode: payload.mode,
93
+ }),
94
+ );
95
+ }
96
+
97
+ /** Report a suppressed or failed rebuild now waiting out its backoff. */
98
+ export function reportRepairBackoff(
99
+ emit: RepairEmit | undefined,
100
+ payload: {
101
+ readonly subsystem: string;
102
+ readonly code: RepairFailureCode;
103
+ readonly backoffMs: number;
104
+ readonly attempt: number;
105
+ },
106
+ ): void {
107
+ if (!VC6C_ENABLED()) return;
108
+ safe(emit, (e) =>
109
+ e("vector_cortex_repair_backoff", {
110
+ ts: undefined,
111
+ event: "vector_cortex_repair_backoff",
112
+ subsystem: payload.subsystem,
113
+ code: payload.code,
114
+ backoffMs: payload.backoffMs,
115
+ attempt: payload.attempt,
116
+ }),
117
+ );
118
+ }
@@ -0,0 +1,227 @@
1
+ /**
2
+ * vector-cortex/heal/repair-types.ts — VC6C self-healing derived controller.
3
+ *
4
+ * VC6B answered "when a node's bytes are gone, WHERE do they come from?". VC6C
5
+ * answers the question one level up: when a DERIVED subsystem (topology, shards,
6
+ * closure) has fallen BEHIND the durable authority, how do we notice, and how do
7
+ * we catch it up without ever risking the authority itself?
8
+ *
9
+ * THE AUTHORITY IS READ-ONLY, ALWAYS. The controller compares each derived
10
+ * source's high-water to the durable authority high-water and plans work. It has
11
+ * no write path to the authority — not a guarded one, not an admin one. Derived
12
+ * state is disposable and can always be rebuilt from the byte ledger; the
13
+ * authority is not, so the repair path is deliberately one-directional. This is
14
+ * why `RepairState` carries `authorityHighWater` as a plain readonly field and
15
+ * why no function in `controller.ts` returns anything that could be applied to it.
16
+ *
17
+ * NEVER READ PAST THE AUTHORITY (TRIAD_RESILIENCE §frontier). A derived builder
18
+ * may not read beyond the durable CONTIGUOUS authority high-water. During an
19
+ * authority outage that high-water FREEZES even though the spool keeps accepting
20
+ * frames — so a derived subsystem that is "behind" a frozen frontier is CORRECT,
21
+ * not broken, and planning a rebuild against the spool tail would materialize
22
+ * frames that are not yet durable. `detectGaps` therefore treats
23
+ * `authorityFrozen` as a hard stop (`HEAL_REPAIR_AUTHORITY_FROZEN`) rather than
24
+ * as a large gap to chase. After the drain, catch-up resumes from the OLD
25
+ * high-water; it never jumps to the tail.
26
+ *
27
+ * REBUILD IS COPY-THEN-SWITCH, NEVER IN-PLACE. `rebuild.ts` materializes a NEW
28
+ * generation, verifies its root digest, and only then flips the pointer. A failed
29
+ * verification keeps the old pointer and DELETES NO EVIDENCE: the corrupt
30
+ * generation stays on disk to be inspected. An in-place repair would, by
31
+ * construction, destroy the only copy of the thing that was about to be proven
32
+ * wrong.
33
+ *
34
+ * RATE LIMIT + BACKOFF ARE THE BLAST RADIUS. A subsystem that fails to rebuild
35
+ * will fail again, usually instantly, so an unbounded retry loop turns one broken
36
+ * shard into a CPU-saturating rebuild storm. One rebuild per subsystem per 5
37
+ * minutes bounds the steady state, and the deterministic exponential backoff
38
+ * (30s * 2^attempt, capped at 15 min, ±10% jitter derived from the SUBSYSTEM
39
+ * DIGEST rather than `Math.random`) bounds the failure state while keeping the
40
+ * schedule reproducible in a fixture.
41
+ *
42
+ * Pure types + registered conformance IDs: no storage, no console, no clock, no
43
+ * network (PREVENT-PI-004 / PREVENT-011).
44
+ */
45
+
46
+ import type { ShardRange } from "../shards/types.js";
47
+ import type { EventV2 } from "../ledger/types.js";
48
+
49
+ /** The triad mode, mirroring TRIAD_RESILIENCE (A targeted / B full / C disable). */
50
+ export type Mode = "A" | "B" | "C";
51
+
52
+ /**
53
+ * A derived subsystem name (e.g. "topology", "shards", "closure").
54
+ *
55
+ * Deliberately a plain string rather than a closed union: the set of derived
56
+ * subsystems grows every sprint, and a union here would force an unrelated
57
+ * contract edit (and a conformance-corpus regeneration) every time a new derived
58
+ * tier is added. The subsystem name is also the jitter seed, so it must be stable.
59
+ */
60
+ export type RepairSubsystem = string;
61
+
62
+ /**
63
+ * A planned rebuild for ONE subsystem.
64
+ *
65
+ * `range` is the gap to rebuild — derived high-water (exclusive) to authority
66
+ * high-water (inclusive) — so a plan is self-describing: an operator can read the
67
+ * exact seq window that will be materialized. `generation` is the NEW generation
68
+ * the rebuild will write into (never the live one). `backoffMs` is the delay
69
+ * BEFORE the plan may execute, and `scheduledAt` is the monotonic timestamp it
70
+ * becomes eligible.
71
+ */
72
+ export interface RepairPlanV1 {
73
+ readonly schema: "repair-plan-v1";
74
+ readonly subsystem: RepairSubsystem;
75
+ /** The seq/byte window to rebuild (derived high-water .. authority high-water). */
76
+ readonly range: ShardRange;
77
+ /** The NEW generation number the rebuild materializes into. */
78
+ readonly generation: number;
79
+ /** Deterministic delay before this plan is eligible to run. */
80
+ readonly backoffMs: number;
81
+ /** Monotonic ms at which the plan becomes eligible (`now + backoffMs`). */
82
+ readonly scheduledAt: bigint;
83
+ }
84
+
85
+ /**
86
+ * A repair lifecycle record. Emitted as a structured event AND retained for the
87
+ * dashboard's repair state, so it carries identity and counters only — never a
88
+ * rebuilt byte, never a node id, never transcript text (SECURITY_PRIVACY).
89
+ */
90
+ export interface RepairEventV1 {
91
+ readonly schema: "repair-event-v1";
92
+ readonly subsystem: RepairSubsystem;
93
+ /**
94
+ * `planned` — a gap was detected and a rebuild scheduled.
95
+ * `pointer-switched` — a verified generation became live (the ONLY success).
96
+ * `backoff` — a rebuild was suppressed (rate limit) or failed and is
97
+ * now waiting out its exponential delay.
98
+ */
99
+ readonly kind: "planned" | "pointer-switched" | "backoff";
100
+ readonly generation: number;
101
+ /** Monotonic ms of the transition. */
102
+ readonly ts: bigint;
103
+ }
104
+
105
+ /** VC6C failure codes (registered HEAL codes). */
106
+ export type RepairFailureCode =
107
+ /**
108
+ * The authority high-water is frozen (outage). Derived state is CORRECTLY
109
+ * behind and must not chase the spool tail — planning is refused, not delayed.
110
+ */
111
+ | "HEAL_REPAIR_AUTHORITY_FROZEN"
112
+ /** A rebuilt generation's root digest does not match — pointer NOT switched. */
113
+ | "HEAL_REPAIR_DIGEST_MISMATCH"
114
+ /** The rebuild itself could not produce a generation (mode C disable). */
115
+ | "HEAL_REBUILD_FAILED"
116
+ /** A second rebuild for this subsystem inside the 5-minute window. */
117
+ | "HEAL_REPAIR_RATE_LIMITED";
118
+
119
+ /**
120
+ * The controller's view of ONE derived subsystem.
121
+ *
122
+ * `authorityHighWater` is READ, never written (see the file header). `mode`
123
+ * records which triad arm this subsystem is currently served by, so a subsystem
124
+ * already in mode C (derived state disabled) is not repeatedly re-planned.
125
+ */
126
+ export interface RepairState {
127
+ readonly subsystem: RepairSubsystem;
128
+ /** How far the derived source has been built (inclusive seq). */
129
+ readonly derivedHighWater: bigint;
130
+ /** Durable CONTIGUOUS authority high-water (inclusive seq). Read-only. */
131
+ readonly authorityHighWater: bigint;
132
+ /** Monotonic ms of the last rebuild, or null if never rebuilt. */
133
+ readonly lastRebuildAt: bigint | null;
134
+ /** The CURRENT live generation. A plan targets `generation + 1`. */
135
+ readonly generation: number;
136
+ /** Which triad arm currently serves this subsystem. */
137
+ readonly mode: Mode;
138
+ /**
139
+ * Consecutive failed rebuild attempts, the exponent in `30s * 2^attempt`.
140
+ * Reset to 0 on a successful pointer switch.
141
+ */
142
+ readonly failedAttempts?: number;
143
+ /**
144
+ * True while the durable authority frontier is frozen (outage). A frozen
145
+ * authority makes a derived lag EXPECTED, so no plan may be produced.
146
+ */
147
+ readonly authorityFrozen?: boolean;
148
+ }
149
+
150
+ /** The gap-detection + planning surface. Pure: no clock of its own, no I/O. */
151
+ export interface RepairController {
152
+ /** Plan a rebuild for every subsystem with a real, actionable gap. */
153
+ readonly detectGaps: (
154
+ states: readonly RepairState[],
155
+ nowMs: bigint,
156
+ ) => readonly RepairPlanV1[];
157
+ /** Build a single plan for one subsystem's gap. */
158
+ readonly planRebuild: (state: RepairState, nowMs: bigint) => RepairPlanV1;
159
+ }
160
+
161
+ /**
162
+ * One rebuild per subsystem per 5 minutes. Bounds a rebuild storm: a subsystem
163
+ * that fails will fail again immediately, and without this an unhealthy tier
164
+ * would saturate the box re-materializing the same broken generation.
165
+ */
166
+ export const REPAIR_RATE_LIMIT_MS = 5 * 60_000;
167
+
168
+ /**
169
+ * Exponential backoff base/cap, matching the breaker's retry rule
170
+ * (TRIAD_RESILIENCE): `30s * 2^attempt`, capped at 15 minutes.
171
+ */
172
+ export const REPAIR_BACKOFF_BASE_MS = 30_000;
173
+ export const REPAIR_BACKOFF_CAP_MS = 15 * 60_000;
174
+
175
+ /**
176
+ * ±10% deterministic jitter. Derived from the SUBSYSTEM DIGEST, not a PRNG, so
177
+ * two subsystems desynchronize (no thundering herd) while any single subsystem's
178
+ * schedule stays reproducible in a fixture.
179
+ */
180
+ export const REPAIR_BACKOFF_JITTER = 0.1;
181
+
182
+ /**
183
+ * Registered VC6C conformance ID range (HEAL-031..045), continuing VC6B's
184
+ * HEAL-016..030. The acceptance test reads these rows from the v2 manifest and
185
+ * asserts each returns its manifest `ok`/`code`.
186
+ */
187
+ export const REPAIR_IDS: readonly string[] = Array.from(
188
+ { length: 15 },
189
+ (_v, i) => `HEAL-${String(i + 31).padStart(3, "0")}`,
190
+ );
191
+
192
+ /** Named VC6C conformance assertions (the sprint's headline rows). */
193
+ export const REPAIR_NAMED_IDS = [
194
+ "HEAL-GAP-001",
195
+ "HEAL-RATE-002",
196
+ "HEAL-SWITCH-003",
197
+ ] as const;
198
+
199
+ /** The three structured events the VC6C reporter emits. */
200
+ export type RepairEventName =
201
+ | "vector_cortex_repair_planned"
202
+ | "vector_cortex_repair_pointer_switched"
203
+ | "vector_cortex_repair_backoff";
204
+
205
+ /**
206
+ * Reader-only dashboard aggregate. Counters and the runtime mode only — no
207
+ * subsystem payload, no rebuilt bytes, no gap ranges, no high-water marks, no
208
+ * root digests (SECURITY_PRIVACY).
209
+ *
210
+ * Field names mirror `VectorCortexRepairView` in
211
+ * `extensions/dashboard-server/api-contracts/vector-cortex-heal.ts` EXACTLY.
212
+ * The dashboard contract is the shipped shape; keeping a differently-named
213
+ * mirror here would guarantee a silent drift the compiler could never catch,
214
+ * since the route builds its body from the extensions-side type.
215
+ */
216
+ export interface RepairView {
217
+ readonly enabled: boolean;
218
+ readonly mode: Mode;
219
+ readonly repairAttempts: number;
220
+ readonly repairsPlanned: number;
221
+ readonly pointersSwitched: number;
222
+ readonly backoffs: number;
223
+ readonly lastBackoffMs: number | null;
224
+ readonly lastFailure: RepairFailureCode | null;
225
+ }
226
+
227
+ export type { EventV2, ShardRange };
@@ -246,3 +246,31 @@ export {
246
246
  RESTORE_LIMIT_SPANS,
247
247
  RESTORE_LIMIT_BYTES,
248
248
  } from "./restore-types.js";
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // VC6C self-healing derived controller (repair-types.ts). Re-exported here so
252
+ // the heal contract keeps ONE entry point: VC6B restores the BYTES a plan needs,
253
+ // and these types describe rebuilding the DERIVED state that indexes them —
254
+ // detect a gap against durable authority, rebuild into a new generation, verify
255
+ // its root digest, then switch the pointer.
256
+ // ---------------------------------------------------------------------------
257
+
258
+ export type {
259
+ Mode,
260
+ RepairSubsystem,
261
+ RepairPlanV1,
262
+ RepairEventV1,
263
+ RepairEventName,
264
+ RepairFailureCode,
265
+ RepairState,
266
+ RepairController,
267
+ RepairView,
268
+ } from "./repair-types.js";
269
+ export {
270
+ REPAIR_IDS,
271
+ REPAIR_NAMED_IDS,
272
+ REPAIR_RATE_LIMIT_MS,
273
+ REPAIR_BACKOFF_BASE_MS,
274
+ REPAIR_BACKOFF_CAP_MS,
275
+ REPAIR_BACKOFF_JITTER,
276
+ } from "./repair-types.js";
@@ -1,2 +0,0 @@
1
- import{j as e,B as a,r as l}from"./index-D9PsW3VZ.js";import{C as o,a as d,b as i,c as x}from"./card-DWU-1y3t.js";async function U(){const s=await fetch("/api/vector-cortex/evaluation");if(!s.ok)throw new Error(`vector-cortex evaluation: ${s.status}`);return s.json()}async function y(){const s=await fetch("/api/vector-cortex/health");if(!s.ok)throw new Error(`vector-cortex health: ${s.status}`);return s.json()}async function W(){const s=await fetch("/api/vector-cortex/topology");if(!s.ok)throw new Error(`vector-cortex topology: ${s.status}`);return s.json()}async function Y(){const s=await fetch("/api/vector-cortex/query");if(!s.ok)throw new Error(`vector-cortex query: ${s.status}`);return s.json()}async function _(){const s=await fetch("/api/vector-cortex/shards");if(!s.ok)throw new Error(`vector-cortex shards: ${s.status}`);return s.json()}async function Z(){const s=await fetch("/api/vector-cortex/reconstruct");if(!s.ok)throw new Error(`vector-cortex reconstruct: ${s.status}`);return s.json()}async function J(){const s=await fetch("/api/vector-cortex/plans");if(!s.ok)throw new Error(`vector-cortex plans: ${s.status}`);return s.json()}async function K(){const s=await fetch("/api/vector-cortex/render");if(!s.ok)throw new Error(`vector-cortex render: ${s.status}`);return s.json()}async function X(){const s=await fetch("/api/vector-cortex/rollout");if(!s.ok)throw new Error(`vector-cortex rollout: ${s.status}`);return s.json()}async function ee(){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 se(){const s=await fetch("/api/vector-cortex/restore");if(!s.ok)throw new Error(`vector-cortex restore: ${s.status}`);return s.json()}async function te(s="default"){const r=await fetch(`/api/vector-cortex/ledger?session=${encodeURIComponent(s)}`);if(!r.ok)throw new Error(`vector-cortex ledger: ${r.status}`);return r.json()}async function re(s){const r=await fetch("/api/vector-cortex/breakers/reset",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({subsystem:s})});if(!r.ok)throw new Error(`vector-cortex reset: ${r.status}`);return r.json()}function t({label:s,value:r}){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:r})]})}function ae({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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 ne({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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 le({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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 ce({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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 oe({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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 de({topology:s,query:r}){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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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,m)=>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}-${m}`))})]})]})]}):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)"}),r?.enabled?e.jsx(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:r?.enabled?e.jsx("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-3",children:e.jsx(t,{label:"Router version",value:String(r.routerVersion)})}):e.jsx("div",{className:"vc-empty",children:"Query diagnostics unavailable (VC3C off)."})})]})]})}function ie({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(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{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(r=>e.jsxs("tr",{className:"border-b border-border/30",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:r.seq}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:r.eventId}),e.jsx("td",{className:"py-1 pr-2",children:r.kind}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:r.toolCallId??"—"}),e.jsx("td",{className:"max-w-[180px] truncate font-mono text-muted-foreground",children:r.digest})]},`${r.seq}-${r.eventId}`))})]})})]}):e.jsx("div",{className:"vc-empty",children:"Ledger disabled (VC1B off)."})})]})}function v({mode:s,count:r}){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:r})]})}function he(){const[s,r]=l.useState(null),[u,m]=l.useState(null),[S,V]=l.useState(!0),[c,f]=l.useState(null),[p,b]=l.useState(null),[E,R]=l.useState(null),[w,F]=l.useState(null),[T,k]=l.useState(null),[j,A]=l.useState(null),[h,$]=l.useState(null),[I,O]=l.useState(null),[P,M]=l.useState(null),[B,D]=l.useState(null),[L,H]=l.useState(null),[z,G]=l.useState(null),g=l.useCallback(()=>{U().then(r).catch(n=>m(n instanceof Error?n.message:String(n))).finally(()=>V(!1)),y().then(f).catch(()=>{}),te().then(R).catch(()=>{}),W().then(F).catch(()=>{}),Y().then(k).catch(()=>{}),_().then(A).catch(()=>{}),Z().then($).catch(()=>{}),J().then(O).catch(()=>{}),K().then(M).catch(()=>{}),X().then(D).catch(()=>{}),ee().then(H).catch(()=>{}),se().then(G).catch(()=>{})},[]);l.useEffect(()=>{g();const n=setInterval(g,5e3);return()=>clearInterval(n)},[g]);const q=()=>{re("provider").then(n=>(b(`Breaker "${n.subsystem}" ${n.state}; evidence retained: ${n.failures} failures / ${n.attempts} attempts`),y())).then(f).catch(n=>b(n instanceof Error?n.message:String(n)))};if(S&&!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 C=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(a,{variant:"warning",children:"OBSERVER PENDING (A)"}):e.jsx(a,{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(v,{mode:"A",count:s.byMode.A}),e.jsx(v,{mode:"B",count:s.byMode.B}),e.jsx(v,{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((n,N)=>{const Q=s.histogram.cells[N]/C*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[N]}),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:["≤",n]})]},n)}),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/C*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(a,{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:[p&&e.jsx("div",{className:"mb-2 text-xs text-muted-foreground",children:p}),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(de,{topology:w,query:T}),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)"}),j?.enabled?e.jsx(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:j?.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(j.semanticCount)}),e.jsx(t,{label:"Exact shards",value:String(j.exactCount)}),e.jsx(t,{label:"Byte total",value:String(j.byteTotal)}),e.jsx(t,{label:"Protected bytes",value:String(j.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)."})})]}),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)"}),h?.enabled?e.jsx(a,{variant:"success",children:"ACTIVE"}):e.jsx(a,{variant:"danger",children:"OFF"})]})}),e.jsx(x,{children:h?.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(h.closureAttempts)}),e.jsx(t,{label:"Closure rejections",value:String(h.closureRejections)}),e.jsx(t,{label:"Validated",value:String(h.validatedCount)}),e.jsx(t,{label:"Invalidated",value:String(h.invalidatedCount)}),e.jsx(t,{label:"Span total",value:String(h.spanTotal)}),e.jsx(t,{label:"Byte total",value:String(h.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)."})})]}),e.jsx(oe,{view:I}),e.jsx(ae,{view:P}),e.jsx(ne,{view:B}),e.jsx(le,{view:L}),e.jsx(ce,{view:z}),e.jsx(ie,{ledger:E})]})}export{he as default};
2
- //# sourceMappingURL=VectorCortexTab-D2fjKNyT.js.map