pi-mega-compact 0.20.26 → 0.20.28

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 (99) hide show
  1. package/dist/config/vector-cortex-vc9a.js +29 -0
  2. package/dist/config/vector-cortex-vc9b.js +29 -0
  3. package/dist/config/vector-cortex-vc9c.js +34 -0
  4. package/dist/config/vector-cortex.js +4 -0
  5. package/dist/config.js +1 -1
  6. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +20 -0
  7. package/dist/extensions/dashboard-server/api-contracts/setup-cortex.js +13 -0
  8. package/dist/extensions/dashboard-server/route-dispatch.js +7 -1
  9. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +3 -0
  10. package/dist/extensions/dashboard-server/routes-setup-cortex-actions.js +116 -0
  11. package/dist/extensions/dashboard-server/routes-setup-cortex.js +143 -0
  12. package/dist/extensions/dashboard-server/routes.js +2 -0
  13. package/dist/extensions/dashboard-server/setup-cortex-actions.js +213 -0
  14. package/dist/extensions/dashboard-server/setup-cortex-blockers.js +70 -0
  15. package/dist/src/config/vector-cortex-vc9a.js +29 -0
  16. package/dist/src/config/vector-cortex-vc9b.js +29 -0
  17. package/dist/src/config/vector-cortex-vc9c.js +34 -0
  18. package/dist/src/config/vector-cortex.js +4 -0
  19. package/dist/src/config.js +1 -1
  20. package/extensions/dashboard-client/dist/assets/{AreaChart-DRErPez1.js → AreaChart-DIKsPqLG.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{AreaChart-DRErPez1.js.map → AreaChart-DIKsPqLG.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{BarChart-Cwxel3M7.js → BarChart-DeqN74Hn.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{BarChart-Cwxel3M7.js.map → BarChart-DeqN74Hn.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{CacheTab-D4j3vwFu.js → CacheTab-x1YU4tYc.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{CacheTab-D4j3vwFu.js.map → CacheTab-x1YU4tYc.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{EventsTab-BA7t_fsH.js → EventsTab-6BuEbd8Y.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{EventsTab-BA7t_fsH.js.map → EventsTab-6BuEbd8Y.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{HealthTab-Ci9gtYDP.js → HealthTab-B71Ft1ac.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{HealthTab-Ci9gtYDP.js.map → HealthTab-B71Ft1ac.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BeqWn-xu.js → MaintenanceTab-dysyJtHk.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BeqWn-xu.js.map → MaintenanceTab-dysyJtHk.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BreZegCV.js → MemoryMapTab-B3dKRb_4.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BreZegCV.js.map → MemoryMapTab-B3dKRb_4.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{MetricsTab-DLbgfJT2.js → MetricsTab-COn4GoUK.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{MetricsTab-DLbgfJT2.js.map → MetricsTab-COn4GoUK.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{OverviewTab-BtcXdrnC.js → OverviewTab-Cd9qAEB3.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{OverviewTab-BtcXdrnC.js.map → OverviewTab-Cd9qAEB3.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{ReposTab-DpDLEzV9.js → ReposTab-DpiP1-Vv.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{ReposTab-DpDLEzV9.js.map → ReposTab-DpiP1-Vv.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{SessionsTab-CMe5jSrZ.js → SessionsTab-BwRUeGZM.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{SessionsTab-CMe5jSrZ.js.map → SessionsTab-BwRUeGZM.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js +3 -0
  43. package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BFPJUQzs.js → TimeSavedCard-_XsdjQ7Z.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BFPJUQzs.js.map → TimeSavedCard-_XsdjQ7Z.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{TurnsTab-Ujt29pKI.js → TurnsTab-CWPscPLL.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{TurnsTab-Ujt29pKI.js.map → TurnsTab-CWPscPLL.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/VcStatusBadge-Cx56rAIM.js +2 -0
  49. package/extensions/dashboard-client/dist/assets/VcStatusBadge-Cx56rAIM.js.map +1 -0
  50. package/extensions/dashboard-client/dist/assets/VectorCortexTab-B5ElUM7S.js +2 -0
  51. package/extensions/dashboard-client/dist/assets/VectorCortexTab-B5ElUM7S.js.map +1 -0
  52. package/extensions/dashboard-client/dist/assets/{WikiTab-BiKXVwGT.js → WikiTab-uZ5Mq3XG.js} +2 -2
  53. package/extensions/dashboard-client/dist/assets/{WikiTab-BiKXVwGT.js.map → WikiTab-uZ5Mq3XG.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{button-DJwGcw0u.js → button-Kc18bYFz.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{button-DJwGcw0u.js.map → button-Kc18bYFz.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{card-CgjBf5LZ.js → card-COJZoG08.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{card-CgjBf5LZ.js.map → card-COJZoG08.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CTQIl2qs.js → generateCategoricalChart-ChEYo017.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CTQIl2qs.js.map → generateCategoricalChart-ChEYo017.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{index-Bu8CZUMX.js → index-CB7Rn5FP.js} +14 -14
  61. package/extensions/dashboard-client/dist/assets/index-CB7Rn5FP.js.map +1 -0
  62. package/extensions/dashboard-client/dist/assets/index-DbuGwYD7.css +1 -0
  63. package/extensions/dashboard-client/dist/assets/{switch-uUiS1Raq.js → switch-BFhl_tNh.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{switch-uUiS1Raq.js.map → switch-BFhl_tNh.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/{toggle-Dv3OEscH.js → toggle-DJ68kATc.js} +2 -2
  66. package/extensions/dashboard-client/dist/assets/{toggle-Dv3OEscH.js.map → toggle-DJ68kATc.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/{useSSE-n6ymAic3.js → useSSE-CXWh42xX.js} +2 -2
  68. package/extensions/dashboard-client/dist/assets/{useSSE-n6ymAic3.js.map → useSSE-CXWh42xX.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/index.html +2 -2
  70. package/extensions/dashboard-client/src/api/setup-cortex.ts +62 -0
  71. package/extensions/dashboard-client/src/tabs/SetupTab/CortexActionsCard.tsx +221 -0
  72. package/extensions/dashboard-client/src/tabs/SetupTab/CortexBlockersCard.tsx +74 -0
  73. package/extensions/dashboard-client/src/tabs/SetupTab/CortexEncoderCard.tsx +113 -0
  74. package/extensions/dashboard-client/src/tabs/SetupTab/CortexSetup.tsx +53 -0
  75. package/extensions/dashboard-client/src/tabs/SetupTab/CortexSetupStyles.ts +98 -0
  76. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +22 -6
  77. package/extensions/dashboard-client/src/tabs/useSetupCortexPoll.ts +64 -0
  78. package/extensions/dashboard-client/src/types/setup-cortex.ts +118 -0
  79. package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +44 -0
  80. package/extensions/dashboard-server/api-contracts/setup-cortex.ts +123 -0
  81. package/extensions/dashboard-server/route-dispatch.ts +6 -0
  82. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +18 -0
  83. package/extensions/dashboard-server/routes-setup-cortex-actions.ts +133 -0
  84. package/extensions/dashboard-server/routes-setup-cortex.ts +167 -0
  85. package/extensions/dashboard-server/routes.ts +5 -0
  86. package/extensions/dashboard-server/setup-cortex-actions.ts +242 -0
  87. package/extensions/dashboard-server/setup-cortex-blockers.ts +98 -0
  88. package/package.json +1 -1
  89. package/src/config/vector-cortex-vc9a.ts +31 -0
  90. package/src/config/vector-cortex-vc9b.ts +31 -0
  91. package/src/config/vector-cortex-vc9c.ts +36 -0
  92. package/src/config/vector-cortex.ts +5 -0
  93. package/src/config.ts +3 -0
  94. package/extensions/dashboard-client/dist/assets/SetupTab-C3OY8mc7.js +0 -2
  95. package/extensions/dashboard-client/dist/assets/SetupTab-C3OY8mc7.js.map +0 -1
  96. package/extensions/dashboard-client/dist/assets/VectorCortexTab-CfxZW91A.js +0 -2
  97. package/extensions/dashboard-client/dist/assets/VectorCortexTab-CfxZW91A.js.map +0 -1
  98. package/extensions/dashboard-client/dist/assets/index-Bu8CZUMX.js.map +0 -1
  99. package/extensions/dashboard-client/dist/assets/index-Difwoltx.css +0 -1
@@ -0,0 +1,64 @@
1
+ /**
2
+ * useSetupCortexPoll — polls the VC9A setup-cortex status endpoint (a sibling
3
+ * of useVectorCortexPoll, URL + payload differ only). Each fetch is
4
+ * best-effort: a failure sets the error slice and leaves data as-is. The
5
+ * Cortex sub-tab uses the returned payload to render the encoder card + the
6
+ * status badge, and SetupTab uses it to filter the sub-tab when the status
7
+ * reports the off/disabled shape.
8
+ */
9
+ import { useState, useEffect, useCallback } from "react";
10
+ import { fetchSetupCortexStatus } from "../api/setup-cortex";
11
+ import type { SetupCortexStatusResponse } from "../types/setup-cortex";
12
+
13
+ export interface SetupCortexPollState {
14
+ loading: boolean;
15
+ error: string | null;
16
+ data: SetupCortexStatusResponse | null;
17
+ }
18
+
19
+ /**
20
+ * Whether the Cortex sub-tab should be listed in SUB_TABS.
21
+ *
22
+ * The sub-tab is hidden (filtered from SUB_TABS) when the VC9A status payload
23
+ * reports the off/disabled shape — either the flag is off (`enabled:false`) or
24
+ * the derived status is "off" — exactly the VC0E honest-status gating the
25
+ * sibling VC cards use. While the payload is still loading/absent we default to
26
+ * visible so a transient poll isn't mistaken for the off state.
27
+ */
28
+ export function isCortexSubTabVisible(
29
+ data: SetupCortexStatusResponse | null,
30
+ ): boolean {
31
+ if (data === null) return true;
32
+ return data.enabled && data.status !== "off";
33
+ }
34
+
35
+ export function useSetupCortexPoll(): [SetupCortexPollState, () => void] {
36
+ const [state, setState] = useState<SetupCortexPollState>({
37
+ loading: true,
38
+ error: null,
39
+ data: null,
40
+ });
41
+
42
+ const poll = useCallback(() => {
43
+ setState((prev) => ({ ...prev, loading: true }));
44
+ fetchSetupCortexStatus()
45
+ .then((data) =>
46
+ setState((prev) => ({ ...prev, data, loading: false, error: null })),
47
+ )
48
+ .catch((e: unknown) =>
49
+ setState((prev) => ({
50
+ ...prev,
51
+ loading: false,
52
+ error: e instanceof Error ? e.message : String(e),
53
+ })),
54
+ );
55
+ }, []);
56
+
57
+ useEffect(() => {
58
+ poll();
59
+ const id = setInterval(poll, 5000);
60
+ return () => clearInterval(id);
61
+ }, [poll]);
62
+
63
+ return [state, poll];
64
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * dashboard-client/src/types/setup-cortex.ts — Setup Cortex client types.
3
+ *
4
+ * Client-side mirrors of the server contract (extensions/dashboard-server/
5
+ * api-contracts/setup-cortex.ts), kept in lockstep so the SetupTab Cortex
6
+ * sub-tab is fully typed end-to-end. The client bundle does not import the
7
+ * server tree, so these are redeclared here (PREVENT-011: no `any`; every type
8
+ * explicit). Aggregate values only — never payload bytes/prompts/ledger
9
+ * (EVAL-REDACT-002).
10
+ */
11
+
12
+ /** The deriveVcStatus status projected by the VC9A reader endpoint. */
13
+ export type VcStatus = "live" | "awaiting_data" | "deferred" | "structural" | "off";
14
+
15
+ /** One open hard-gate blocker row surfaced on the blockers card. */
16
+ export interface BlockerV1 {
17
+ /** Stable machine id keying the row (HG-1, HG-3, ...). */
18
+ readonly id: string;
19
+ /** Human title shown on the blockers card. */
20
+ readonly title: string;
21
+ /** Severity: blocker | high | medium. */
22
+ readonly severity: "blocker" | "high" | "medium";
23
+ /** Lifecycle state — always "open" (hard gates not closed in-workstream). */
24
+ readonly status: "open";
25
+ /** Optional candidate resolution surfaced for the user / controller. */
26
+ readonly resolution?: string;
27
+ }
28
+
29
+ /** Encoder qualification verdict projected for the reader. */
30
+ export type SetupCortexQualificationVerdict = "qualified" | "demoted" | "unavailable";
31
+
32
+ /** Reader-only view of the encoder health facts (digest prefix, no bytes). */
33
+ export interface SetupCortexEncoderHealth {
34
+ /** First 12 hex chars of the committed asset-manifest digest, or null. */
35
+ readonly assetDigestPrefix: string | null;
36
+ /** Effective encoder triad mode (A verified / B demoted / C absent). */
37
+ readonly mode: "A" | "B" | "C";
38
+ }
39
+
40
+ /** Response for GET /api/setup-cortex-status. */
41
+ export interface SetupCortexStatusResponse {
42
+ /** Whether the VC9A setup-cortex read path is active (its flag). */
43
+ readonly enabled: boolean;
44
+ /** The gating flag name ("MEGACOMPACT_VC9A"). */
45
+ readonly flag: string;
46
+ /** Effective encoder triad mode (A verified / B demoted / C absent / off). */
47
+ readonly mode: "A" | "B" | "C";
48
+ /** First 12 hex chars of the asset-manifest digest, or null. */
49
+ readonly assetDigestPrefix: string | null;
50
+ /** Qualification projection: verdict + any threshold failures surfaced. */
51
+ readonly qualification: {
52
+ readonly verdict: SetupCortexQualificationVerdict;
53
+ readonly thresholdFailures: string[];
54
+ };
55
+ /** The open hard-gate blockers (never closed here). */
56
+ readonly blockers: BlockerV1[];
57
+ /** Encoder health facts (digest prefix + mode). */
58
+ readonly encoderHealth: SetupCortexEncoderHealth;
59
+ /** ISO 8601 read timestamp. */
60
+ readonly updatedAt: string;
61
+ /** Shared status derivation (deriveVcStatus). */
62
+ readonly status: VcStatus;
63
+ }
64
+
65
+ /** The set of developer actions the Setup Cortex action drivers can run. */
66
+ export type SetupCortexActionKind = "fetch-model" | "bench" | "verify-asset";
67
+
68
+ /** Request body for POST /api/setup-cortex-action. confirm:true required. */
69
+ export interface SetupCortexActionRequest {
70
+ readonly action: SetupCortexActionKind;
71
+ readonly confirm: boolean;
72
+ }
73
+
74
+ /** Outcome of running one Setup Cortex action. */
75
+ export interface SetupCortexActionResult {
76
+ readonly action: SetupCortexActionKind;
77
+ readonly ok: boolean;
78
+ readonly exitCode: number | null;
79
+ readonly logPath: string;
80
+ readonly logName: string;
81
+ readonly spawned: boolean;
82
+ }
83
+
84
+ /** Error body used when a hard gate blocks the requested action. */
85
+ export interface SetupCortexActionBlocked {
86
+ readonly error: "action_blocked_by_open_item";
87
+ /** The open hard-gate ids (HG-1/HG-3) that gate this action. */
88
+ readonly blockers: string[];
89
+ }
90
+
91
+ /** Error body used when confirm:true was not supplied. */
92
+ export interface SetupCortexActionConfirmRequired {
93
+ readonly error: "confirmation_required";
94
+ }
95
+
96
+ /** Error body used when the setup-cortex action path is disabled (flag off). */
97
+ export interface SetupCortexActionDisabled {
98
+ readonly error: "disabled";
99
+ }
100
+
101
+ /** Union of every non-2xx action error body the route can return. */
102
+ export type SetupCortexActionErrorBody =
103
+ | SetupCortexActionBlocked
104
+ | SetupCortexActionConfirmRequired
105
+ | SetupCortexActionDisabled;
106
+
107
+ /** Request query for GET /api/setup-cortex-action-log. */
108
+ export interface SetupCortexActionLogQuery {
109
+ readonly name: string;
110
+ }
111
+
112
+ /** Response body for GET /api/setup-cortex-action-log (bounded, redacted). */
113
+ export interface SetupCortexActionLogResponse {
114
+ readonly name: string;
115
+ readonly tail: string;
116
+ /** True when the full file fit in the tail (false = truncated to 8 KiB). */
117
+ readonly complete: boolean;
118
+ }
@@ -16,6 +16,14 @@ import type {
16
16
  VectorCortexEvaluationSummary,
17
17
  VectorCortexLedgerView,
18
18
  } from "../vector-cortex.js";
19
+ import type {
20
+ SetupCortexStatusResponse,
21
+ SetupCortexActionRequest,
22
+ SetupCortexActionResult,
23
+ SetupCortexActionBlocked,
24
+ SetupCortexActionLogQuery,
25
+ SetupCortexActionLogResponse,
26
+ } from "../setup-cortex.js";
19
27
 
20
28
  /** Additive endpoint entries spread into the ENDPOINTS registry. */
21
29
  export const EXTRA_ENDPOINTS = {
@@ -64,4 +72,40 @@ export const EXTRA_ENDPOINTS = {
64
72
  undefined,
65
73
  VectorCortexLedgerView
66
74
  >,
75
+
76
+ // ─── VC9A Setup Cortex (dashboard Setup tab cortex status) ─────────
77
+
78
+ /** GET /api/setup-cortex-status — reader-only vector-cortex encoder gate. */
79
+ setupCortexStatus: {
80
+ method: "GET",
81
+ path: "/api/setup-cortex-status",
82
+ description:
83
+ "Reader-only vector-cortex encoder gate: mode A/B/C, qualification verdict, blockers, encoder health — for the dashboard Setup tab. Never closes the ML gate.",
84
+ } as const satisfies EndpointDef<"GET", undefined, SetupCortexStatusResponse>,
85
+
86
+ // ─── VC9B Setup Cortex actions (dashboard Setup tab action drivers) ─────
87
+
88
+ /** POST /api/setup-cortex-action — confirmation-gated fetch/bench/verify. */
89
+ setupCortexAction: {
90
+ method: "POST",
91
+ path: "/api/setup-cortex-action",
92
+ description:
93
+ "Confirmation-gated driver: fetch-model / bench / verify-asset. Executes only the committed local scripts (scripts/vc2-model-prep/*) or re-reads the committed encoder assets; an OPEN hard-gate item returns action_blocked_by_open_item and does NOT spawn. Never payload bytes; confirm:true required.",
94
+ } as const satisfies EndpointDef<
95
+ "POST",
96
+ SetupCortexActionRequest,
97
+ SetupCortexActionResult | SetupCortexActionBlocked
98
+ >,
99
+
100
+ /** GET /api/setup-cortex-action-log — bounded, redacted action log tail. */
101
+ setupCortexActionLog: {
102
+ method: "GET",
103
+ path: "/api/setup-cortex-action-log",
104
+ description:
105
+ "Bounded (8 KiB) redacted tail of a VC9B action log under <stateDir>/logs/vc9b/; the name must be a validated basename (path traversal rejected).",
106
+ } as const satisfies EndpointDef<
107
+ "GET",
108
+ SetupCortexActionLogQuery,
109
+ SetupCortexActionLogResponse
110
+ >,
67
111
  } as const;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * api-contracts/setup-cortex.ts — Setup Cortex status + action API types (VC9A/VC9B).
3
+ *
4
+ * Types for GET /api/setup-cortex-status (reader-only aggregate that surfaces
5
+ * the vector-cortex encoder gate WITHOUT closing the ML gate) and the VC9B
6
+ * action drivers POST /api/setup-cortex-action + GET /api/setup-cortex-action-log
7
+ * (confirmation-gated, hard-gate-aware fetches/bench/verify). Reader/actor-only:
8
+ * never payload bytes/prompts/ledger (EVAL-REDACT-002).
9
+ *
10
+ * PREVENT-PI-004: type definitions only, no network code.
11
+ * PREVENT-011: no `any` type — all types are explicit.
12
+ */
13
+
14
+ import type { VcStatus } from "../vc-status.js";
15
+
16
+ /** One blocker row surfaced on the dashboard Setup Cortex blockers card. */
17
+ export interface BlockerV1 {
18
+ /** Stable machine id (HG-1, HG-3, ...) keying the row. */
19
+ readonly id: string;
20
+ /** Human title shown on the blockers card. */
21
+ readonly title: string;
22
+ /** Severity: blocker | high | medium. */
23
+ readonly severity: "blocker" | "high" | "medium";
24
+ /** Lifecycle state — always "open" (hard gates not closed in-workstream). */
25
+ readonly status: "open";
26
+ /** Optional candidate resolution surfaced for the user / controller. */
27
+ readonly resolution?: string;
28
+ }
29
+
30
+ /** The encoder qualification verdict projected for the reader (no calibration run). */
31
+ export type SetupCortexQualificationVerdict = "qualified" | "demoted" | "unavailable";
32
+
33
+ /** Reader-only view of the encoder health facts (digest prefix, no bytes). */
34
+ export interface SetupCortexEncoderHealth {
35
+ /** First 12 hex chars of the committed asset-manifest digest, or null. */
36
+ readonly assetDigestPrefix: string | null;
37
+ /** Effective encoder triad mode (A verified / B demoted / C absent). */
38
+ readonly mode: "A" | "B" | "C";
39
+ }
40
+
41
+ /**
42
+ * Response for GET /api/setup-cortex-status.
43
+ */
44
+ export interface SetupCortexStatusResponse {
45
+ /** Whether the VC9A setup-cortex read path is active (its flag). */
46
+ readonly enabled: boolean;
47
+ /** The gating flag name ("MEGACOMPACT_VC9A"). */
48
+ readonly flag: string;
49
+ /** Effective encoder triad mode (A verified / B demoted / C absent / off). */
50
+ readonly mode: "A" | "B" | "C";
51
+ /** First 12 hex chars of the asset-manifest digest, or null. */
52
+ readonly assetDigestPrefix: string | null;
53
+ /** Qualification projection: verdict + any threshold failures surfaced. */
54
+ readonly qualification: {
55
+ readonly verdict: SetupCortexQualificationVerdict;
56
+ readonly thresholdFailures: string[];
57
+ };
58
+ /** The open hard-gate blockers (vc2-model-prep §6, never closed here). */
59
+ readonly blockers: BlockerV1[];
60
+ /** Encoder health facts (digest prefix + mode). */
61
+ readonly encoderHealth: SetupCortexEncoderHealth;
62
+ /** ISO 8601 read timestamp. */
63
+ readonly updatedAt: string;
64
+ /** Shared status derivation (deriveVcStatus). */
65
+ readonly status: VcStatus;
66
+ }
67
+
68
+ // ─── VC9B action drivers ────────────────────────────────────────────────────
69
+
70
+ /** The set of developer actions the Setup Cortex action drivers can run. */
71
+ export type SetupCortexActionKind = "fetch-model" | "bench" | "verify-asset";
72
+
73
+ /**
74
+ * Request body for POST /api/setup-cortex-action. `confirm:true` is the
75
+ * server-side hard requirement (mirrors the client ActionDef confirm pattern);
76
+ * anything else is rejected with confirmation_required.
77
+ */
78
+ export interface SetupCortexActionRequest {
79
+ /** Which action to run. */
80
+ readonly action: SetupCortexActionKind;
81
+ /** Required explicit confirmation. Absent/false → 400 confirmation_required. */
82
+ readonly confirm: boolean;
83
+ }
84
+
85
+ /** Outcome of running one Setup Cortex action. */
86
+ export interface SetupCortexActionResult {
87
+ readonly action: SetupCortexActionKind;
88
+ /** True when the subprocess (or asset re-verification) ran to completion. */
89
+ readonly ok: boolean;
90
+ /** Exit code of the spawned script, or null for verify-asset / no-spawn. */
91
+ readonly exitCode: number | null;
92
+ /** Absolute path of the captured log file under <stateDir>/logs/vc9b/. */
93
+ readonly logPath: string;
94
+ /** Relative basename of the log file (the value to pass to the log-tail route). */
95
+ readonly logName: string;
96
+ /** True when the subprocess was spawned (verify-asset re-runs asset seams only). */
97
+ readonly spawned: boolean;
98
+ }
99
+
100
+ /**
101
+ * Error body used when a hard gate blocks the requested action: the action is
102
+ * NOT spawned, and the blocking open hard-gate ids (HG-1/HG-3) are surfaced.
103
+ */
104
+ export interface SetupCortexActionBlocked {
105
+ readonly error: "action_blocked_by_open_item";
106
+ /** The open hard-gate ids (HG-1/HG-3) that gate this action. */
107
+ readonly blockers: string[];
108
+ }
109
+
110
+ /** Request query for GET /api/setup-cortex-action-log. */
111
+ export interface SetupCortexActionLogQuery {
112
+ /** Basename of a log file inside <stateDir>/logs/vc9b/ (traversal rejected). */
113
+ readonly name: string;
114
+ }
115
+
116
+ /** Response body for GET /api/setup-cortex-action-log (bounded, redacted). */
117
+ export interface SetupCortexActionLogResponse {
118
+ readonly name: string;
119
+ /** Tail of the action log, capped at 8 KiB and redacted. */
120
+ readonly tail: string;
121
+ /** True when the full file fit in the tail (false = truncated to 8 KiB). */
122
+ readonly complete: boolean;
123
+ }
@@ -56,6 +56,9 @@ import {
56
56
  handleVectorCortexRollout,
57
57
  handleVectorCortexClosureProof,
58
58
  handleVectorCortexRestore,
59
+ handleSetupCortexStatus,
60
+ handleSetupCortexAction,
61
+ handleSetupCortexActionLog,
59
62
  } from "./routes.js";
60
63
  // VC6C repair lives in its own module (routes-vector-cortex-repair.ts) so the
61
64
  // heal route file stays well under the 400-line extension soft limit.
@@ -146,5 +149,8 @@ export function dispatchRoutes(
146
149
  if (handleVectorCortexOutcomes(req, res, ctx)) return true;
147
150
  if (handleVectorCortexPolicy(req, res, ctx)) return true;
148
151
  if (handleVectorCortexPlatform(req, res, ctx)) return true;
152
+ if (handleSetupCortexStatus(req, res, ctx)) return true;
153
+ if (handleSetupCortexAction(req, res, ctx)) return true;
154
+ if (handleSetupCortexActionLog(req, res, ctx)) return true;
149
155
  return false;
150
156
  }
@@ -192,5 +192,23 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
192
192
  "Canary selection and external Rust parity. The selector admits a qualified external Rust artifact only when ABI version, URL metadata, commit, Cargo.lock digest, and platform all match evidence; a Cargo.lock digest mismatch rejects the artifact (RUST_CARGO_DIGEST_MISMATCH). The cross-conformance runner exchanges length-framed neutral records over a local stdin/stdout channel — a subprocess, never a URL (PREVENT-PI-004). A parity mismatch selects TS mode B. A qualified external artifact is mode A, TS reference is mode B, legacy path is mode C. OFF = byte-identical predecessor (VC8B); the selector and cross-conformance arithmetic still run, only the reporter + dashboard seam is suppressed.",
193
193
  true,
194
194
  ),
195
+ boolDirect(
196
+ "MEGACOMPACT_VC9A",
197
+ "VC9A Setup Cortex Status",
198
+ "Reader-only Setup Cortex status read path (GET /api/setup-cortex-status): surfaces the vector-cortex encoder gate — mode A/B/C, qualification verdict, open blockers, encoder health — to the dashboard Setup tab without closing the ML gate. OFF = byte-identical predecessor (VC8C-era): returns enabled:false / mode:C / status:off.",
199
+ true,
200
+ ),
201
+ boolDirect(
202
+ "MEGACOMPACT_VC9B",
203
+ "VC9B Setup Cortex Actions",
204
+ "Setup Cortex action drivers (POST /api/setup-cortex-action + GET /api/setup-cortex-action-log): confirmation-gated wrappers that fetch-model / bench / verify-asset by spawning only the committed local scripts (scripts/vc2-model-prep/fetch-model.sh, bench-onnx.mjs) or re-reading the committed encoder assets — never payload bytes, no network. Actions gated by an OPEN hard-gate item (HG-1/HG-3) return action_blocked_by_open_item and do NOT spawn. OFF = byte-identical predecessor (VC9A-era): the action POST returns a disabled/404 shape and flag-off bytes are unchanged.",
205
+ true,
206
+ ),
207
+ boolDirect(
208
+ "MEGACOMPACT_VC9C",
209
+ "VC9C SetupTab Cortex Sub-tab",
210
+ "SetupTab Cortex sub-tab (client UI): a Cortex sub-tab inside SetupTab that consumes the VC9A status endpoint (GET /api/setup-cortex-status) + the VC9B action endpoints. It surfaces the encoder mode A/B/C, asset digest prefix, qualification verdict + threshold failures, the open hard-gate blockers, and the confirmation-gated fetch/bench/verify actions. OFF = byte-identical predecessor (VC9B-era): the Cortex sub-tab is filtered from SUB_TABS and the Setup tab renders exactly as before.",
211
+ true,
212
+ ),
195
213
  ],
196
214
  };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * dashboard-server/routes-setup-cortex-actions.ts — VC9B Setup Cortex action routes.
3
+ *
4
+ * POST /api/setup-cortex-action — confirmation-gated driver
5
+ * GET /api/setup-cortex-action-log — bounded, redacted log tail
6
+ *
7
+ * Reader/actor-only: NEVER exposes payload bytes, prompts, or ledger. Actions
8
+ * only spawn the committed local vc2-model-prep scripts or re-read the committed
9
+ * encoder assets (verify-asset) — no network (PREVENT-PI-004). A hard gate
10
+ * (HG-1/HG-3) blocking the requested action yields 423 action_blocked_by_open_item
11
+ * with the blocker ids and NO subprocess is spawned. Missing confirm:true yields
12
+ * 400 confirmation_required. Flag-off (MEGACOMPACT_VC9B=0) is byte-identical to
13
+ * the VC9A-era predecessor: the routes are absent, so they return the 404
14
+ * disabled shape and no action runs.
15
+ *
16
+ * Guardrails: PREVENT-011 (no `any`), PREVENT-001 (guarded JSON.parse via
17
+ * readJsonBody), no string literals for scripts/blockers (delegated to
18
+ * setup-cortex-actions.ts + setup-cortex-blockers.ts).
19
+ */
20
+
21
+ import type { IncomingMessage, ServerResponse } from "node:http";
22
+ import type { RouteContext } from "./routes-core.js";
23
+ import { sendJson, readJsonBody } from "./routes-vector-cortex-shared.js";
24
+ import { VC9B_ENABLED } from "../../src/config.js";
25
+ import { setupCortexActionBlockers } from "./setup-cortex-blockers.js";
26
+ import {
27
+ runSetupCortexAction,
28
+ readActionLogTail,
29
+ } from "./setup-cortex-actions.js";
30
+ import type { SetupCortexActionKind } from "./api-contracts/setup-cortex.js";
31
+
32
+ const ACTION_KINDS = new Set<SetupCortexActionKind>([
33
+ "fetch-model",
34
+ "bench",
35
+ "verify-asset",
36
+ ]);
37
+
38
+ function isActionKind(v: unknown): v is SetupCortexActionKind {
39
+ return typeof v === "string" && ACTION_KINDS.has(v as SetupCortexActionKind);
40
+ }
41
+
42
+ /** Flag-off response, byte-identical regardless of request (VC9B absent). */
43
+ function sendDisabled(res: ServerResponse): void {
44
+ sendJson(res, 404, { error: "disabled" });
45
+ }
46
+
47
+ /**
48
+ * POST /api/setup-cortex-action (VC9B). Returns true when it claims the request.
49
+ */
50
+ export function handleSetupCortexAction(
51
+ req: IncomingMessage,
52
+ res: ServerResponse,
53
+ ctx: RouteContext,
54
+ ): boolean {
55
+ const url = req.url ?? "";
56
+ if (url !== "/api/setup-cortex-action") return false;
57
+ if (req.method !== "POST") {
58
+ sendJson(res, 405, { error: "method_not_allowed" });
59
+ return true;
60
+ }
61
+ if (!VC9B_ENABLED()) {
62
+ sendDisabled(res);
63
+ return true;
64
+ }
65
+ readJsonBody(req, (parsed) => {
66
+ if (!parsed.ok) {
67
+ sendJson(res, 400, { error: "invalid_body" });
68
+ return;
69
+ }
70
+ const value = parsed.value;
71
+ const action = value.action;
72
+ if (!isActionKind(action)) {
73
+ sendJson(res, 400, { error: "invalid_action" });
74
+ return;
75
+ }
76
+ if (value.confirm !== true) {
77
+ sendJson(res, 400, { error: "confirmation_required" });
78
+ return;
79
+ }
80
+ // Hard-gate check: when an OPEN hard-gate item gates this action, do NOT
81
+ // spawn — surface the blocker ids so the client highlights the matching rows.
82
+ const blockers = setupCortexActionBlockers(action);
83
+ if (blockers.length > 0) {
84
+ sendJson(res, 423, {
85
+ error: "action_blocked_by_open_item",
86
+ blockers: [...blockers],
87
+ });
88
+ return;
89
+ }
90
+ const result = runSetupCortexAction(action, ctx.stateDir);
91
+ sendJson(res, result.ok ? 200 : 500, result);
92
+ });
93
+ return true;
94
+ }
95
+
96
+ /**
97
+ * GET /api/setup-cortex-action-log?name=<basename> (VC9B). Returns true when it
98
+ * claims the request. Bounded tail (8 KiB max) + redacted (digest prefixes +
99
+ * codes); the name must validate to a basename inside the vc9b log dir.
100
+ */
101
+ export function handleSetupCortexActionLog(
102
+ req: IncomingMessage,
103
+ res: ServerResponse,
104
+ ctx: RouteContext,
105
+ ): boolean {
106
+ const url = req.url ?? "";
107
+ if (url.split("?")[0] !== "/api/setup-cortex-action-log") return false;
108
+ if (req.method !== "GET") {
109
+ sendJson(res, 405, { error: "method_not_allowed" });
110
+ return true;
111
+ }
112
+ if (!VC9B_ENABLED()) {
113
+ sendDisabled(res);
114
+ return true;
115
+ }
116
+ let name: string | null = null;
117
+ try {
118
+ name = new URL(url, "http://localhost").searchParams.get("name");
119
+ } catch {
120
+ name = null;
121
+ }
122
+ if (!name) {
123
+ sendJson(res, 400, { error: "invalid_log_name" });
124
+ return true;
125
+ }
126
+ const tail = readActionLogTail(ctx.stateDir, name);
127
+ if (tail === null) {
128
+ sendJson(res, 404, { error: "log_not_found" });
129
+ return true;
130
+ }
131
+ sendJson(res, 200, tail);
132
+ return true;
133
+ }