pi-mega-compact 0.20.57 → 0.20.59

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 (82) hide show
  1. package/dist/config/vector-cortex-dash-0a.js +22 -0
  2. package/dist/config/vector-cortex-dash-0b.js +21 -0
  3. package/dist/config/vector-cortex.js +4 -0
  4. package/dist/config.js +1 -1
  5. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
  6. package/dist/src/config/vector-cortex-dash-0a.js +22 -0
  7. package/dist/src/config/vector-cortex-dash-0b.js +21 -0
  8. package/dist/src/config/vector-cortex.js +4 -0
  9. package/dist/src/config.js +1 -1
  10. package/extensions/dashboard-client/dist/assets/{AreaChart-CtJ6dSMT.js → AreaChart-GTwQxOAm.js} +2 -2
  11. package/extensions/dashboard-client/dist/assets/{AreaChart-CtJ6dSMT.js.map → AreaChart-GTwQxOAm.js.map} +1 -1
  12. package/extensions/dashboard-client/dist/assets/{BarChart-DJ3j3xDz.js → BarChart-BFqUD5L4.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{BarChart-DJ3j3xDz.js.map → BarChart-BFqUD5L4.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{CacheTab-CXU1_9lR.js → CacheTab-BLM6_PQQ.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{CacheTab-CXU1_9lR.js.map → CacheTab-BLM6_PQQ.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{EventsTab-DF-Q3o7x.js → EventsTab-BYLh6cud.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{EventsTab-DF-Q3o7x.js.map → EventsTab-BYLh6cud.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/{HealthTab-Dr1HGOkl.js → HealthTab-CkJXEbjn.js} +2 -2
  19. package/extensions/dashboard-client/dist/assets/{HealthTab-Dr1HGOkl.js.map → HealthTab-CkJXEbjn.js.map} +1 -1
  20. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js +5 -0
  21. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js.map +1 -0
  22. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-zKhR18_s.js → MaintenanceTab-Lm3v0nJO.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-zKhR18_s.js.map → MaintenanceTab-Lm3v0nJO.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DekIzfn2.js → MemoryMapTab-C8AeBIQi.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DekIzfn2.js.map → MemoryMapTab-C8AeBIQi.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{MetricsTab-CEKajY38.js → MetricsTab-m410T4vk.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{MetricsTab-CEKajY38.js.map → MetricsTab-m410T4vk.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{OverviewTab-24sG8xiE.js → OverviewTab-BfDfMFXx.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{OverviewTab-24sG8xiE.js.map → OverviewTab-BfDfMFXx.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{ReposTab-70gkV8l9.js → ReposTab-CsFxxqJ6.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{ReposTab-70gkV8l9.js.map → ReposTab-CsFxxqJ6.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js +2 -0
  33. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js.map +1 -0
  34. package/extensions/dashboard-client/dist/assets/{SetupTab-tbPrrfYx.js → SetupTab-DVT4PrH0.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{SetupTab-tbPrrfYx.js.map → SetupTab-DVT4PrH0.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B6mdtCWE.js → TimeSavedCard-BkRzjyRm.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B6mdtCWE.js.map → TimeSavedCard-BkRzjyRm.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js +2 -0
  39. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js.map +1 -0
  40. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-SDThp0R0.js → VcStatusBadge-B8B8RStV.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-SDThp0R0.js.map → VcStatusBadge-B8B8RStV.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/VectorCortexTab-CrGANNd_.js +2 -0
  43. package/extensions/dashboard-client/dist/assets/VectorCortexTab-CrGANNd_.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/{WikiTab-Cki48_8N.js → WikiTab-DyD0yGzI.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{WikiTab-Cki48_8N.js.map → WikiTab-DyD0yGzI.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{button-CojFYd7q.js → button-Bynl3ONj.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{button-CojFYd7q.js.map → button-Bynl3ONj.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{card-Cxeeje9o.js → card-Daf3pQIu.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{card-Cxeeje9o.js.map → card-Daf3pQIu.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{client-extra-DLxyGxW8.js → client-extra-DqAYZBW1.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{client-extra-DLxyGxW8.js.map → client-extra-DqAYZBW1.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DRlqBks2.js → generateCategoricalChart-B-fe5jjr.js} +2 -2
  53. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DRlqBks2.js.map → generateCategoricalChart-B-fe5jjr.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{index-CkbdlPBm.js → index-Bjvv23bp.js} +3 -3
  55. package/extensions/dashboard-client/dist/assets/{index-CkbdlPBm.js.map → index-Bjvv23bp.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{switch-Cx_nl-Ba.js → switch-CivyERPS.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{switch-Cx_nl-Ba.js.map → switch-CivyERPS.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{toggle-CfIFzp6P.js → toggle-qmdkrAgF.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{toggle-CfIFzp6P.js.map → toggle-qmdkrAgF.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{useSSE-B9_N7ccG.js → useSSE-uNuduyGe.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{useSSE-B9_N7ccG.js.map → useSSE-uNuduyGe.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/index.html +1 -1
  63. package/extensions/dashboard-client/src/dash-consolidation/plan.ts +200 -0
  64. package/extensions/dashboard-client/src/tabs/SessionsTab/TurnMemoryView.tsx +383 -0
  65. package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +77 -6
  66. package/extensions/dashboard-client/src/tabs/VectorCortexTab/sections.tsx +201 -0
  67. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +168 -122
  68. package/extensions/dashboard-client/src/tabs/index.ts +30 -0
  69. package/extensions/dashboard-client/src/tabs/registry.ts +17 -0
  70. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
  71. package/extensions/mega-runtime/widget-types.ts +2 -1
  72. package/package.json +1 -1
  73. package/src/config/vector-cortex-dash-0a.ts +24 -0
  74. package/src/config/vector-cortex-dash-0b.ts +23 -0
  75. package/src/config/vector-cortex.ts +4 -0
  76. package/src/config.ts +2 -0
  77. package/extensions/dashboard-client/dist/assets/SessionsTab-B3quvYPZ.js +0 -2
  78. package/extensions/dashboard-client/dist/assets/SessionsTab-B3quvYPZ.js.map +0 -1
  79. package/extensions/dashboard-client/dist/assets/TurnsTab-CmhRJJqr.js +0 -5
  80. package/extensions/dashboard-client/dist/assets/TurnsTab-CmhRJJqr.js.map +0 -1
  81. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DDjCkTjk.js +0 -2
  82. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DDjCkTjk.js.map +0 -1
@@ -1,9 +1,22 @@
1
1
  /**
2
- * dashboard-client/src/tabs/SessionsTab.tsx — Sessions tab (S39).
2
+ * dashboard-client/src/tabs/SessionsTab.tsx — Sessions tab (S39, DASH-0b).
3
3
  *
4
- * Renders: window selector (5/15/30/60 min), sessions summary tiles,
5
- * the stacked-memory graph (SessionsMemoryChart), and the active sessions
6
- * table (ActiveSessionsTable).
4
+ * DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.
5
+ * A `SessionsViews` toggle ("Active Sessions" / "Turn Memory") switches between
6
+ * the existent sessions summary/chart/table body and the turns view (rendered by
7
+ * `SessionsTab/TurnMemoryView.tsx` — the turns body moved VERBATIM from the
8
+ * standalone TurnsTab.tsx, which is left untouched this sprint for flag-off
9
+ * parity).
10
+ *
11
+ * Flag: `MEGACOMPACT_DASH_0B` default ON. The dashboard client is a browser
12
+ * bundle with NO `process` global, so the positive sprint flag cannot be read
13
+ * server-side-style (`process.env`) inside the client. Instead the flag is read
14
+ * from the server-authoritative `/api/rag-settings` state: the server resolves
15
+ * `process.env["MEGACOMPACT_DASH_0B"] ?? default` into the `SettingState.value`
16
+ * boolean. When the flag is OFF (settings confirmed value=false), this surface
17
+ * renders ONLY the existent sessions body — no toggle, no TurnMemoryView branch
18
+ * (byte-identical predecessor). The standalone TurnsTab.tsx top-level surface is
19
+ * untouched and remains reachable for flag-off parity.
7
20
  *
8
21
  * Data sources: fetchSessions() + fetchSessionTimeseries(minutes). Both poll
9
22
  * every 2s for near-real-time updates. useSSE() listens for session_sample
@@ -18,12 +31,19 @@ import type React from "react";
18
31
  import { useCallback, useEffect, useMemo, useState } from "react";
19
32
  import { useApi } from "../hooks/useApi";
20
33
  import { useSSE } from "../hooks/useSSE";
21
- import { fetchSessions, fetchSessionTimeseries } from "../api/client";
22
- import type { SseEvent, SseSessionSample, SessionsResponse, SessionTimeseriesResponse } from "@contracts";
34
+ import { fetchSessions, fetchSessionTimeseries, fetchSettings } from "../api/client";
35
+ import type {
36
+ SseEvent,
37
+ SseSessionSample,
38
+ SessionsResponse,
39
+ SessionTimeseriesResponse,
40
+ SettingsResponse,
41
+ } from "@contracts";
23
42
  import { SessionsMemoryChart } from "../components/SessionsMemoryChart";
24
43
  import { ActiveSessionsTable } from "../components/ActiveSessionsTable";
25
44
  import { Toggle } from "../components/ui/toggle";
26
45
  import { Card, CardContent } from "../components/ui/card";
46
+ import { TurnMemoryView } from "./SessionsTab/TurnMemoryView";
27
47
 
28
48
  /**
29
49
  * Shape of the {@link SseSessionSample} SSE event appended to events.log by
@@ -40,6 +60,21 @@ function isSessionSample(
40
60
  return e.type === "session_sample";
41
61
  }
42
62
 
63
+ const DASH_0B_KEY = "MEGACOMPACT_DASH_0B";
64
+
65
+ /** Resolve the DASH-0b consolidation flag from the server settings state.
66
+ * Absent/not-yet-loaded => false (flag-off posture), so flag-off users never
67
+ * see a toggle flash; the toggle appears only once settings confirm it is ON. */
68
+ function dash0bEnabled(settings: SettingsResponse | null): boolean {
69
+ if (!settings) return false;
70
+ for (const cat of settings.categories) {
71
+ for (const s of cat.settings) {
72
+ if (s.key === DASH_0B_KEY && s.type === "boolean") return s.value === true;
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+
43
78
  const WINDOWS: ReadonlyArray<{ value: number; label: string }> = [
44
79
  { value: 5, label: "5m" },
45
80
  { value: 15, label: "15m" },
@@ -98,8 +133,19 @@ function SummaryTiles({ sessions }: SummaryTilesProps): React.ReactElement {
98
133
  );
99
134
  }
100
135
 
136
+ type SessionsView = "active" | "turns";
137
+
101
138
  export default function SessionsTab(): React.ReactElement {
102
139
  const [minutes, setMinutes] = useState(30);
140
+ const [view, setView] = useState<SessionsView>("active");
141
+
142
+ const {
143
+ data: settingsData,
144
+ } = useApi<SettingsResponse>(
145
+ useCallback(() => fetchSettings(), []),
146
+ { pollInterval: 0, maxRetries: 0 },
147
+ );
148
+ const dash0bOn = dash0bEnabled(settingsData);
103
149
 
104
150
  const {
105
151
  data: sessionsData,
@@ -142,6 +188,10 @@ export default function SessionsTab(): React.ReactElement {
142
188
  refetchTimeseries();
143
189
  }, [lastSampleTs, refetchSessions, refetchTimeseries]);
144
190
 
191
+ if (dash0bOn && view === "turns") {
192
+ return <TurnMemoryView />;
193
+ }
194
+
145
195
  if (sessionsErr && !sessionsData) {
146
196
  return (
147
197
  <div className="tab-stub">
@@ -185,6 +235,27 @@ export default function SessionsTab(): React.ReactElement {
185
235
  </div>
186
236
  </div>
187
237
 
238
+ {dash0bOn && (
239
+ <div
240
+ className="flex items-center gap-2"
241
+ role="tablist"
242
+ aria-label="Sessions views"
243
+ >
244
+ <Toggle
245
+ pressed={view === "active"}
246
+ onClick={() => setView("active")}
247
+ >
248
+ Active Sessions
249
+ </Toggle>
250
+ <Toggle
251
+ pressed={view === "turns"}
252
+ onClick={() => setView("turns")}
253
+ >
254
+ Turn Memory
255
+ </Toggle>
256
+ </div>
257
+ )}
258
+
188
259
  {sessions.length === 0 ? (
189
260
  <div className="text-sm text-muted-foreground">No active sessions.</div>
190
261
  ) : (
@@ -0,0 +1,201 @@
1
+ /**
2
+ * dashboard-client/src/tabs/VectorCortexTab/sections.tsx — DASH-0b sectioned
3
+ * layout for the Vector Cortex tab.
4
+ *
5
+ * Groups the existent flat VectorCortexTab card list under 4 `<section
6
+ * aria-labelledby>` headers — Cortex status / Cortex repair / Cortex cache /
7
+ * Cortex adaptive — without editing any card component file. Every card is
8
+ * imported verbatim by its current path (unchanged prop contract) and appears
9
+ * under EXACTLY one section (bijective assignment).
10
+ *
11
+ * Groups (spec §Goal):
12
+ * - Cortex status — VC0C health card + ModelImprovementCard +
13
+ * VectorCortexTopologyCard + VectorCortexShardsCard
14
+ * (+ embedded Reconstruct)
15
+ * - Cortex repair — VectorCortexClosureCard + VectorCortexRestoreCard +
16
+ * VectorCortexRepairCard
17
+ * - Cortex cache — VectorCortexCrystalsCard + VectorCortexEconomicsCard +
18
+ * VectorCortexDiagnosticsCard
19
+ * - Cortex adaptive— VectorCortexOutcomesCard + VectorCortexPolicyCard +
20
+ * VectorCortexPlansCard + VectorCortexRenderCard +
21
+ * VectorCortexRolloutCard + VectorCortexPlatformCard +
22
+ * VectorCortexLedgerCard
23
+ *
24
+ * The health card (VC0C "Live Safety Envelope") markup is moved here verbatim
25
+ * from the predecessor VectorCortexTab so the sectioned (flag-ON) layout owns
26
+ * all 18 cards. Consumers pass the live poll state + health-reset handlers.
27
+ *
28
+ * PREVENT-PI-004: local reader data only. PREVENT-011: no `any`.
29
+ */
30
+
31
+ import type {
32
+ VectorCortexHealthCard,
33
+ VectorCortexEvaluationSummary,
34
+ } from "../../api/vector-cortex";
35
+ import type { VectorCortexPollState } from "../useVectorCortexPoll";
36
+ import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
37
+ import { Badge } from "../../components/ui/badge";
38
+ import { Metric } from "../VectorCortexMetric";
39
+ import { VectorCortexRenderCard } from "../VectorCortexRenderCard";
40
+ import { VectorCortexRolloutCard } from "../VectorCortexRolloutCard";
41
+ import { VectorCortexClosureCard } from "../VectorCortexClosureCard";
42
+ import { VectorCortexRestoreCard } from "../VectorCortexRestoreCard";
43
+ import { VectorCortexRepairCard } from "../VectorCortexRepairCard";
44
+ import { VectorCortexCrystalsCard } from "../VectorCortexCrystalsCard";
45
+ import { VectorCortexEconomicsCard } from "../VectorCortexEconomicsCard";
46
+ import { VectorCortexDiagnosticsCard } from "../VectorCortexDiagnosticsCard";
47
+ import { VectorCortexOutcomesCard } from "../VectorCortexOutcomesCard";
48
+ import { VectorCortexPolicyCard } from "../VectorCortexPolicyCard";
49
+ import { VectorCortexPlatformCard } from "../VectorCortexPlatformCard";
50
+ import {
51
+ VectorCortexShardsCard,
52
+ VectorCortexReconstructCard,
53
+ } from "../VectorCortexShardsCard";
54
+ import { VectorCortexPlansCard } from "../VectorCortexPlansCard";
55
+ import { VectorCortexTopologyCard } from "../VectorCortexTopologyCard";
56
+ import { VectorCortexLedgerCard } from "../VectorCortexLedgerCard";
57
+ import { ModelImprovementCard } from "../../components/ModelImprovementCard";
58
+
59
+ /** Props the sectioned layout needs from the VectorCortexTab shell. */
60
+ export interface VectorCortexSectionsProps {
61
+ /** The polled evaluation summary (guaranteed non-null by the shell). */
62
+ data: VectorCortexEvaluationSummary;
63
+ /** Live VC0C health envelope (may be null when VC0C is off). */
64
+ health: VectorCortexHealthCard | null;
65
+ /** The full poll state (holds every card's view slice). */
66
+ poll: VectorCortexPollState;
67
+ /** Reset-cooldown handler wired to the VC0C health card. */
68
+ onReset: () => void;
69
+ /** Reset feedback message shown on the VC0C health card. */
70
+ resetMsg: string | null;
71
+ }
72
+
73
+ function StatusHeading({ id, title }: { id: string; title: string }): React.ReactElement {
74
+ return (
75
+ <h2 id={id} className="font-heading text-lg font-semibold">
76
+ {title}
77
+ </h2>
78
+ );
79
+ }
80
+
81
+ /**
82
+ * The VC0C "Live Safety Envelope" health card, moved verbatim from the
83
+ * predecessor VectorCortexTab. It is the 18th card in the sectioned layout.
84
+ */
85
+ function Vc0cHealthCard({
86
+ health,
87
+ onReset,
88
+ resetMsg,
89
+ }: {
90
+ health: VectorCortexHealthCard | null;
91
+ onReset: () => void;
92
+ resetMsg: string | null;
93
+ }): React.ReactElement {
94
+ return (
95
+ <Card>
96
+ <CardHeader>
97
+ <div className="flex items-center justify-between">
98
+ <CardTitle>Live Safety Envelope (VC0C)</CardTitle>
99
+ <div className="flex items-center gap-2">
100
+ {health?.stateSource === "ephemeral" && (
101
+ <Badge variant="outline">EPHEMERAL (non-live)</Badge>
102
+ )}
103
+ <button
104
+ onClick={onReset}
105
+ disabled={!health?.enabled}
106
+ className="rounded border border-border px-2 py-1 text-xs disabled:opacity-50"
107
+ >
108
+ Reset Cooldown
109
+ </button>
110
+ </div>
111
+ </div>
112
+ </CardHeader>
113
+ <CardContent>
114
+ {resetMsg && (
115
+ <div className="mb-2 text-xs text-muted-foreground">{resetMsg}</div>
116
+ )}
117
+ {!health ? (
118
+ <div className="vc-empty">Health unavailable (VC0C off).</div>
119
+ ) : (
120
+ <div className="grid grid-cols-2 gap-4 md:grid-cols-4">
121
+ <Metric label="State" value={health.state} />
122
+ <Metric label="Mode" value={health.mode} />
123
+ <Metric label="Window" value={`${health.windowMs}ms`} />
124
+ <Metric label="Probes" value={String(health.probeCount)} />
125
+ <Metric label="Backoff" value={`${health.backoffDelayMs}ms`} />
126
+ <Metric
127
+ label="Failures"
128
+ value={`${health.failures}/${health.attempts}`}
129
+ />
130
+ <Metric
131
+ label="Frontier"
132
+ value={
133
+ health.stateSource === "ephemeral"
134
+ ? "non-live"
135
+ : health.frontierFrozen
136
+ ? "FROZEN"
137
+ : "LIVE"
138
+ }
139
+ />
140
+ <Metric label="Spool lag" value={String(health.spoolLag)} />
141
+ <Metric label="Encoder mode" value={health.encoderMode} />
142
+ <Metric label="Encoder asset" value={health.encoderAssetDigest ? health.encoderAssetDigest.slice(0, 12) : "none"} />
143
+ </div>
144
+ )}
145
+ </CardContent>
146
+ </Card>
147
+ );
148
+ }
149
+
150
+ /** The four section groups, rendered as `<section aria-labelledby>` blocks. */
151
+ export function VectorCortexSections({
152
+ data,
153
+ health,
154
+ poll,
155
+ onReset,
156
+ resetMsg,
157
+ }: VectorCortexSectionsProps): React.ReactElement {
158
+ return (
159
+ <>
160
+ <section aria-labelledby="cortex-status" className="flex flex-col gap-4">
161
+ <StatusHeading id="cortex-status" title="Cortex status" />
162
+ <Vc0cHealthCard health={health} onReset={onReset} resetMsg={resetMsg} />
163
+ {data.ml5dEnabled && (
164
+ <ModelImprovementCard
165
+ encoderMode={health?.encoderMode ?? "B"}
166
+ encoderAssetDigest={health?.encoderAssetDigest ?? null}
167
+ status={data.status}
168
+ />
169
+ )}
170
+ <VectorCortexTopologyCard topology={poll.topology} query={poll.query} />
171
+ <VectorCortexShardsCard view={poll.shards} />
172
+ <VectorCortexReconstructCard view={poll.reconstruct} />
173
+ </section>
174
+
175
+ <section aria-labelledby="cortex-repair" className="flex flex-col gap-4">
176
+ <StatusHeading id="cortex-repair" title="Cortex repair" />
177
+ <VectorCortexClosureCard view={poll.closureProof} />
178
+ <VectorCortexRestoreCard view={poll.restore} />
179
+ <VectorCortexRepairCard view={poll.repair} />
180
+ </section>
181
+
182
+ <section aria-labelledby="cortex-cache" className="flex flex-col gap-4">
183
+ <StatusHeading id="cortex-cache" title="Cortex cache" />
184
+ <VectorCortexCrystalsCard view={poll.crystals} />
185
+ <VectorCortexEconomicsCard view={poll.economics} />
186
+ <VectorCortexDiagnosticsCard view={poll.diagnostics} />
187
+ </section>
188
+
189
+ <section aria-labelledby="cortex-adaptive" className="flex flex-col gap-4">
190
+ <StatusHeading id="cortex-adaptive" title="Cortex adaptive" />
191
+ <VectorCortexOutcomesCard view={poll.outcomes} />
192
+ <VectorCortexPolicyCard view={poll.policy} />
193
+ <VectorCortexPlansCard view={poll.plans} />
194
+ <VectorCortexRenderCard view={poll.render} />
195
+ <VectorCortexRolloutCard view={poll.rollout} />
196
+ <VectorCortexPlatformCard view={poll.platform} />
197
+ <VectorCortexLedgerCard ledger={poll.ledger} />
198
+ </section>
199
+ </>
200
+ );
201
+ }
@@ -1,13 +1,27 @@
1
1
  /**
2
- * VectorCortexTab.tsx — vector-cortex dashboard tab.
2
+ * VectorCortexTab.tsx — vector-cortex dashboard tab (VC0A, DASH-0b).
3
3
  * VC0A: reader-only aggregate latency histogram + per-mode sample counts from
4
4
  * GET /api/vector-cortex/evaluation. VC0C (task 5): live safety envelope health
5
5
  * card (breaker state, window/probe/backoff, durable spool frontier/lag) from
6
6
  * GET /api/vector-cortex/health plus an admin "reset cooldown" action. Polls
7
7
  * every 5s via useVectorCortexPoll.
8
+ *
9
+ * DASH-0b: delegate-shell. Flag `MEGACOMPACT_DASH_0B` default ON re-groups the
10
+ * flat 18-card layout under 4 `<section aria-labelledby>` headers (rendered by
11
+ * `VectorCortexTab/sections.tsx`). Flag-OFF keeps the original flat card list
12
+ * in this file — byte-identical predecessor layout. No card component file is
13
+ * edited; only their import grouping moves.
14
+ *
15
+ * The client is a browser bundle with no `process` global, so the flag is read
16
+ * from the server-authoritative `/api/rag-settings` state (the server resolves
17
+ * `process.env["MEGACOMPACT_DASH_0B"] ?? default` into a boolean SettingState);
18
+ * see the same pattern in SessionsTab. PREVENT-PI-004: loopback reader calls only.
8
19
  */
9
20
 
10
21
  import { useState } from "react";
22
+ import { useApi } from "../hooks/useApi";
23
+ import { fetchSettings } from "../api/client";
24
+ import type { SettingsResponse } from "@contracts";
11
25
  import {
12
26
  resetVectorCortexBreaker,
13
27
  fetchVectorCortexHealth,
@@ -17,6 +31,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card"
17
31
  import { Badge } from "../components/ui/badge";
18
32
  import { Metric } from "./VectorCortexMetric";
19
33
  import { useVectorCortexPoll } from "./useVectorCortexPoll";
34
+ import { VectorCortexSections } from "./VectorCortexTab/sections";
20
35
  import { VectorCortexRenderCard } from "./VectorCortexRenderCard";
21
36
  import { VectorCortexRolloutCard } from "./VectorCortexRolloutCard";
22
37
  import { VectorCortexClosureCard } from "./VectorCortexClosureCard";
@@ -38,6 +53,19 @@ import { VectorCortexLedgerCard } from "./VectorCortexLedgerCard";
38
53
  import { VcStatusBadge } from "./VcStatusBadge";
39
54
  import { ModelImprovementCard } from "../components/ModelImprovementCard";
40
55
 
56
+ const DASH_0B_KEY = "MEGACOMPACT_DASH_0B";
57
+
58
+ /** Resolve the DASH-0b flag from the server settings state (false unless confirmed). */
59
+ function dash0bEnabled(settings: SettingsResponse | null): boolean {
60
+ if (!settings) return false;
61
+ for (const cat of settings.categories) {
62
+ for (const s of cat.settings) {
63
+ if (s.key === DASH_0B_KEY && s.type === "boolean") return s.value === true;
64
+ }
65
+ }
66
+ return false;
67
+ }
68
+
41
69
  function ModeChip({ mode, count }: { mode: string; count: number }): React.ReactElement {
42
70
  return (
43
71
  <div className="flex items-center justify-between border-b border-border/50 py-1 text-sm">
@@ -51,6 +79,12 @@ export default function VectorCortexTab(): React.ReactElement {
51
79
  const [poll, refetch] = useVectorCortexPoll();
52
80
  const [resetMsg, setResetMsg] = useState<string | null>(null);
53
81
 
82
+ const { data: settingsData } = useApi<SettingsResponse>(
83
+ () => fetchSettings(),
84
+ { pollInterval: 0, maxRetries: 0 },
85
+ );
86
+ const dash0bOn = dash0bEnabled(settingsData);
87
+
54
88
  const { loading, error, data, health } = poll;
55
89
 
56
90
  const onReset = () => {
@@ -85,138 +119,150 @@ export default function VectorCortexTab(): React.ReactElement {
85
119
  </span>
86
120
  </div>
87
121
 
88
- <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
89
- <Card>
90
- <CardHeader>
91
- <CardTitle>Samples</CardTitle>
92
- </CardHeader>
93
- <CardContent>
94
- <div className="text-3xl font-bold">{data.samples}</div>
95
- <div className="mt-2 flex flex-col">
96
- <ModeChip mode="A" count={data.byMode.A} />
97
- <ModeChip mode="B" count={data.byMode.B} />
98
- <ModeChip mode="C" count={data.byMode.C} />
99
- </div>
100
- </CardContent>
101
- </Card>
122
+ {dash0bOn ? (
123
+ <VectorCortexSections
124
+ data={data}
125
+ health={health}
126
+ poll={poll}
127
+ onReset={onReset}
128
+ resetMsg={resetMsg}
129
+ />
130
+ ) : (
131
+ <>
132
+ <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
133
+ <Card>
134
+ <CardHeader>
135
+ <CardTitle>Samples</CardTitle>
136
+ </CardHeader>
137
+ <CardContent>
138
+ <div className="text-3xl font-bold">{data.samples}</div>
139
+ <div className="mt-2 flex flex-col">
140
+ <ModeChip mode="A" count={data.byMode.A} />
141
+ <ModeChip mode="B" count={data.byMode.B} />
142
+ <ModeChip mode="C" count={data.byMode.C} />
143
+ </div>
144
+ </CardContent>
145
+ </Card>
102
146
 
103
- <Card className="md:col-span-2">
104
- <CardHeader>
105
- <CardTitle>Latency Histogram (ms, inclusive edges)</CardTitle>
106
- </CardHeader>
107
- <CardContent>
108
- <div className="flex items-end gap-2" style={{ height: 160 }}>
109
- {data.histogram.edges.map((edge, i) => {
110
- const h = (data.histogram.cells[i] / max) * 140;
111
- return (
112
- <div key={edge} className="flex flex-1 flex-col items-center gap-1">
147
+ <Card className="md:col-span-2">
148
+ <CardHeader>
149
+ <CardTitle>Latency Histogram (ms, inclusive edges)</CardTitle>
150
+ </CardHeader>
151
+ <CardContent>
152
+ <div className="flex items-end gap-2" style={{ height: 160 }}>
153
+ {data.histogram.edges.map((edge, i) => {
154
+ const h = (data.histogram.cells[i] / max) * 140;
155
+ return (
156
+ <div key={edge} className="flex flex-1 flex-col items-center gap-1">
157
+ <span className="text-xs text-muted-foreground">
158
+ {data.histogram.cells[i]}
159
+ </span>
160
+ <div
161
+ className="w-full rounded-t"
162
+ style={{ height: Math.max(2, h), background: "#6366f1" }}
163
+ />
164
+ <span className="text-[10px] text-muted-foreground">&le;{edge}</span>
165
+ </div>
166
+ );
167
+ })}
168
+ <div className="flex flex-1 flex-col items-center gap-1">
113
169
  <span className="text-xs text-muted-foreground">
114
- {data.histogram.cells[i]}
170
+ {data.histogram.overflow}
115
171
  </span>
116
172
  <div
117
173
  className="w-full rounded-t"
118
- style={{ height: Math.max(2, h), background: "#6366f1" }}
174
+ style={{
175
+ height: Math.max(2, (data.histogram.overflow / max) * 140),
176
+ background: "#f87171",
177
+ }}
119
178
  />
120
- <span className="text-[10px] text-muted-foreground">&le;{edge}</span>
179
+ <span className="text-[10px] text-muted-foreground">&gt;250</span>
121
180
  </div>
122
- );
123
- })}
124
- <div className="flex flex-1 flex-col items-center gap-1">
125
- <span className="text-xs text-muted-foreground">
126
- {data.histogram.overflow}
127
- </span>
128
- <div
129
- className="w-full rounded-t"
130
- style={{
131
- height: Math.max(2, (data.histogram.overflow / max) * 140),
132
- background: "#f87171",
133
- }}
134
- />
135
- <span className="text-[10px] text-muted-foreground">&gt;250</span>
136
- </div>
137
- </div>
138
- <div className="mt-1 text-xs text-muted-foreground">
139
- Total: {data.histogram.total} · Rejects: {data.rejects.length}
140
- </div>
141
- </CardContent>
142
- </Card>
143
- </div>
181
+ </div>
182
+ <div className="mt-1 text-xs text-muted-foreground">
183
+ Total: {data.histogram.total} · Rejects: {data.rejects.length}
184
+ </div>
185
+ </CardContent>
186
+ </Card>
187
+ </div>
144
188
 
145
- <Card>
146
- <CardHeader>
147
- <div className="flex items-center justify-between">
148
- <CardTitle>Live Safety Envelope (VC0C)</CardTitle>
149
- <div className="flex items-center gap-2">
150
- {health?.stateSource === "ephemeral" && (
151
- <Badge variant="outline">EPHEMERAL (non-live)</Badge>
189
+ <Card>
190
+ <CardHeader>
191
+ <div className="flex items-center justify-between">
192
+ <CardTitle>Live Safety Envelope (VC0C)</CardTitle>
193
+ <div className="flex items-center gap-2">
194
+ {health?.stateSource === "ephemeral" && (
195
+ <Badge variant="outline">EPHEMERAL (non-live)</Badge>
196
+ )}
197
+ <button
198
+ onClick={onReset}
199
+ disabled={!health?.enabled}
200
+ className="rounded border border-border px-2 py-1 text-xs disabled:opacity-50"
201
+ >
202
+ Reset Cooldown
203
+ </button>
204
+ </div>
205
+ </div>
206
+ </CardHeader>
207
+ <CardContent>
208
+ {resetMsg && (
209
+ <div className="mb-2 text-xs text-muted-foreground">{resetMsg}</div>
152
210
  )}
153
- <button
154
- onClick={onReset}
155
- disabled={!health?.enabled}
156
- className="rounded border border-border px-2 py-1 text-xs disabled:opacity-50"
157
- >
158
- Reset Cooldown
159
- </button>
160
- </div>
161
- </div>
162
- </CardHeader>
163
- <CardContent>
164
- {resetMsg && (
165
- <div className="mb-2 text-xs text-muted-foreground">{resetMsg}</div>
166
- )}
167
- {!health ? (
168
- <div className="vc-empty">Health unavailable (VC0C off).</div>
169
- ) : (
170
- <div className="grid grid-cols-2 gap-4 md:grid-cols-4">
171
- <Metric label="State" value={health.state} />
172
- <Metric label="Mode" value={health.mode} />
173
- <Metric label="Window" value={`${health.windowMs}ms`} />
174
- <Metric label="Probes" value={String(health.probeCount)} />
175
- <Metric label="Backoff" value={`${health.backoffDelayMs}ms`} />
176
- <Metric
177
- label="Failures"
178
- value={`${health.failures}/${health.attempts}`}
179
- />
180
- <Metric
181
- label="Frontier"
182
- value={
183
- health.stateSource === "ephemeral"
184
- ? "non-live"
185
- : health.frontierFrozen
186
- ? "FROZEN"
187
- : "LIVE"
188
- }
189
- />
190
- <Metric label="Spool lag" value={String(health.spoolLag)} />
191
- <Metric label="Encoder mode" value={health.encoderMode} />
192
- <Metric label="Encoder asset" value={health.encoderAssetDigest ? health.encoderAssetDigest.slice(0, 12) : "none"} />
193
- </div>
211
+ {!health ? (
212
+ <div className="vc-empty">Health unavailable (VC0C off).</div>
213
+ ) : (
214
+ <div className="grid grid-cols-2 gap-4 md:grid-cols-4">
215
+ <Metric label="State" value={health.state} />
216
+ <Metric label="Mode" value={health.mode} />
217
+ <Metric label="Window" value={`${health.windowMs}ms`} />
218
+ <Metric label="Probes" value={String(health.probeCount)} />
219
+ <Metric label="Backoff" value={`${health.backoffDelayMs}ms`} />
220
+ <Metric
221
+ label="Failures"
222
+ value={`${health.failures}/${health.attempts}`}
223
+ />
224
+ <Metric
225
+ label="Frontier"
226
+ value={
227
+ health.stateSource === "ephemeral"
228
+ ? "non-live"
229
+ : health.frontierFrozen
230
+ ? "FROZEN"
231
+ : "LIVE"
232
+ }
233
+ />
234
+ <Metric label="Spool lag" value={String(health.spoolLag)} />
235
+ <Metric label="Encoder mode" value={health.encoderMode} />
236
+ <Metric label="Encoder asset" value={health.encoderAssetDigest ? health.encoderAssetDigest.slice(0, 12) : "none"} />
237
+ </div>
238
+ )}
239
+ </CardContent>
240
+ </Card>
241
+ {data.ml5dEnabled && (
242
+ <ModelImprovementCard
243
+ encoderMode={health?.encoderMode ?? "B"}
244
+ encoderAssetDigest={health?.encoderAssetDigest ?? null}
245
+ status={data.status}
246
+ />
194
247
  )}
195
- </CardContent>
196
- </Card>
197
- {data.ml5dEnabled && (
198
- <ModelImprovementCard
199
- encoderMode={health?.encoderMode ?? "B"}
200
- encoderAssetDigest={health?.encoderAssetDigest ?? null}
201
- status={data.status}
202
- />
248
+ <VectorCortexTopologyCard topology={poll.topology} query={poll.query} />
249
+ <VectorCortexShardsCard view={poll.shards} />
250
+ <VectorCortexReconstructCard view={poll.reconstruct} />
251
+ <VectorCortexPlansCard view={poll.plans} />
252
+ <VectorCortexRenderCard view={poll.render} />
253
+ <VectorCortexRolloutCard view={poll.rollout} />
254
+ <VectorCortexClosureCard view={poll.closureProof} />
255
+ <VectorCortexRestoreCard view={poll.restore} />
256
+ <VectorCortexRepairCard view={poll.repair} />
257
+ <VectorCortexCrystalsCard view={poll.crystals} />
258
+ <VectorCortexEconomicsCard view={poll.economics} />
259
+ <VectorCortexDiagnosticsCard view={poll.diagnostics} />
260
+ <VectorCortexOutcomesCard view={poll.outcomes} />
261
+ <VectorCortexPolicyCard view={poll.policy} />
262
+ <VectorCortexPlatformCard view={poll.platform} />
263
+ <VectorCortexLedgerCard ledger={poll.ledger} />
264
+ </>
203
265
  )}
204
- <VectorCortexTopologyCard topology={poll.topology} query={poll.query} />
205
- <VectorCortexShardsCard view={poll.shards} />
206
- <VectorCortexReconstructCard view={poll.reconstruct} />
207
- <VectorCortexPlansCard view={poll.plans} />
208
- <VectorCortexRenderCard view={poll.render} />
209
- <VectorCortexRolloutCard view={poll.rollout} />
210
- <VectorCortexClosureCard view={poll.closureProof} />
211
- <VectorCortexRestoreCard view={poll.restore} />
212
- <VectorCortexRepairCard view={poll.repair} />
213
- <VectorCortexCrystalsCard view={poll.crystals} />
214
- <VectorCortexEconomicsCard view={poll.economics} />
215
- <VectorCortexDiagnosticsCard view={poll.diagnostics} />
216
- <VectorCortexOutcomesCard view={poll.outcomes} />
217
- <VectorCortexPolicyCard view={poll.policy} />
218
- <VectorCortexPlatformCard view={poll.platform} />
219
- <VectorCortexLedgerCard ledger={poll.ledger} />
220
266
  </div>
221
267
  );
222
268
  }