pi-mega-compact 0.20.48 → 0.20.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/vector-cortex-enc0g.js +37 -0
- package/dist/config/vector-cortex.js +1 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/qualification-record.js +71 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes-setup-cortex-actions.js +49 -3
- package/dist/extensions/dashboard-server/routes-setup-cortex.js +65 -16
- package/dist/extensions/dashboard-server/setup-cortex-actions.js +21 -4
- package/dist/extensions/dashboard-server/setup-cortex-blockers.js +3 -69
- package/dist/src/config/vector-cortex-enc0g.js +37 -0
- package/dist/src/config/vector-cortex.js +1 -0
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/setup-cortex-blockers-compute.js +160 -0
- package/dist/vector-cortex/setup-cortex-blockers-compute.js +160 -0
- package/extensions/dashboard-server/api-contracts/setup-cortex.ts +6 -2
- package/extensions/dashboard-server/qualification-record.ts +70 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/extensions/dashboard-server/routes-setup-cortex-actions.ts +50 -3
- package/extensions/dashboard-server/routes-setup-cortex.ts +92 -16
- package/extensions/dashboard-server/setup-cortex-actions.ts +23 -4
- package/extensions/dashboard-server/setup-cortex-blockers.ts +3 -97
- package/package.json +1 -1
- package/src/config/vector-cortex-enc0g.ts +39 -0
- package/src/config/vector-cortex.ts +1 -0
- package/src/config.ts +1 -0
- package/src/vector-cortex/setup-cortex-blockers-compute.ts +216 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/vector-cortex/setup-cortex-blockers-compute.ts — canonical blocker
|
|
3
|
+
* manifest + pure computed blocker derivation for the Setup Cortex status
|
|
4
|
+
* read path (VC9A/ENC-0g).
|
|
5
|
+
*
|
|
6
|
+
* The hard-gate items enumerated in docs/vector-cortex/vc2-model-prep.md §6
|
|
7
|
+
* (per the 2026-08-05 research update: the opset-14→17 re-export blocker is
|
|
8
|
+
* REMOVED because onnx-community exports are now opset 21). This module is the
|
|
9
|
+
* SINGLE canonical source of those blockers — the route file
|
|
10
|
+
* (routes-setup-cortex.ts) carries NO string literals for them; it reads this
|
|
11
|
+
* manifest so the UI rows and the spec stay in one place.
|
|
12
|
+
*
|
|
13
|
+
* ENC-0g: `SETUP_CORTEX_BLOCKERS` remains the canonical BASE data (authored
|
|
14
|
+
* all-open, byte-identical to ENC-0f-era for flag-off). `computeSetupCortexBlockers`
|
|
15
|
+
* is a PURE function over (platform, ENC-0f QualificationV1 record, asset-manifest
|
|
16
|
+
* head-count) that returns the live blocker list: HG-1 closes on a five-head
|
|
17
|
+
* manifest (ENC-0c), HG-5 reflects the measured qualification verdict, HG-4
|
|
18
|
+
* notes the ENC-0e visibility close while the binary gap persists, HG-3 stays
|
|
19
|
+
* open (genuinely unresolved). `setupCortexActionBlockers` re-derives VC9B
|
|
20
|
+
* action gating from the live computed blockers (intersects each action's
|
|
21
|
+
* static candidate gate ids with the currently-open blocker ids).
|
|
22
|
+
*
|
|
23
|
+
* Reader-only, pure computation: zero network, no writes (PREVENT-PI-004), no
|
|
24
|
+
* `any` (PREVENT-011). Thresholds come from src/vector-cortex/encoder/types.js
|
|
25
|
+
* (ENCODER_HEAD_ORDER / ENCODER_LATENCY_P95_MS / ENCODER_RSS_BUDGET_BYTES) —
|
|
26
|
+
* never magic numbers in the computed path.
|
|
27
|
+
*/
|
|
28
|
+
import { ENCODER_HEAD_ORDER, ENCODER_LATENCY_P95_MS, ENCODER_RSS_BUDGET_BYTES, } from "./encoder/types.js";
|
|
29
|
+
const MIB = 1024 * 1024;
|
|
30
|
+
/**
|
|
31
|
+
* Marker threshold-failure emitted by the status route when NO QualificationV1
|
|
32
|
+
* record exists on the device (or it is missing / unreadable / corrupt) — the
|
|
33
|
+
* route falls back to the verify-only verdict and includes this marker, never a
|
|
34
|
+
* fabricated pass and never a bare silent fallback. SINGLE source: the status
|
|
35
|
+
* route references this const, never a re-literal (no-scattered-literal scan).
|
|
36
|
+
*/
|
|
37
|
+
export const QUALIFICATION_RECORD_UNAVAILABLE = "qualification_record_unavailable";
|
|
38
|
+
/**
|
|
39
|
+
* The four blockers VC9A reports. Enumerates the vc2-model-prep §6 items that
|
|
40
|
+
* remain per the 2026-08-05 research. The opset re-export blocker (formerly
|
|
41
|
+
* §6 #2) is NOT listed: onnx-community exports are opset 21, so it is removed.
|
|
42
|
+
* This is the canonical BASE (all `status:"open"`); `computeSetupCortexBlockers`
|
|
43
|
+
* derives the live list from it. Flag-off consumes this array verbatim.
|
|
44
|
+
*/
|
|
45
|
+
export const SETUP_CORTEX_BLOCKERS = [
|
|
46
|
+
{
|
|
47
|
+
id: "HG-1",
|
|
48
|
+
title: "Five projection heads do not exist",
|
|
49
|
+
severity: "blocker",
|
|
50
|
+
status: "open",
|
|
51
|
+
resolution: "Supervision transfer onto a frozen bge-small-en-v1.5 trunk (contradiction distilled from cross-encoder/nli-deberta-v3-small; dependency NLI-assisted; cache-stability deterministic; payload-routing small MLP) — VC2B training + export.",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "HG-3",
|
|
55
|
+
title: "onnxruntime-node install exceeds the 80 MiB asset budget",
|
|
56
|
+
severity: "blocker",
|
|
57
|
+
status: "open",
|
|
58
|
+
resolution: "onnxruntime-node bundles ~258 MiB across all platforms. Candidate: transformers.js v4.2.0 (9.5 MiB shell, pure-Node via onnxruntime-web WASM) measured against budget + p95 gate before committing.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "HG-4",
|
|
62
|
+
title: "No darwin-x64 binary in onnxruntime-node",
|
|
63
|
+
severity: "high",
|
|
64
|
+
status: "open",
|
|
65
|
+
resolution: "Intel-Mac mode-A users demote to the WASM path (if HG-3 resolves that way) or mode B. " +
|
|
66
|
+
"darwin-x64: no native binary upstream (arm64-only); mode-B WASM per HG-4.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "HG-5",
|
|
70
|
+
title: "RSS margin at 512 tokens is ~0.5%",
|
|
71
|
+
severity: "medium",
|
|
72
|
+
status: "open",
|
|
73
|
+
resolution: "149.2 MiB vs 150 MiB cap with run-to-run variance 119-149 MiB; considers capping mode A at 384 tokens or using the marginal-footprint accounting runtime.ts already implements.",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
/** Look up one blocker by id; undefined when unknown (defensive). */
|
|
77
|
+
export function setupCortexBlocker(id) {
|
|
78
|
+
return SETUP_CORTEX_BLOCKERS.find((b) => b.id === id);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The live blockers computed from (platform, ENC-0f QualificationV1 record,
|
|
82
|
+
* asset-manifest head-count). Pure + deterministic — no IO, no clock, no flag
|
|
83
|
+
* dependence. Rules:
|
|
84
|
+
* - HG-1 → `"closed"` when the asset manifest declares all five projection
|
|
85
|
+
* heads (`headCount === ENCODER_HEAD_ORDER.length`); otherwise stays open.
|
|
86
|
+
* - HG-3 → unchanged (genuinely open — onnxruntime-node budget unresolved).
|
|
87
|
+
* - HG-4 → stays `"open"` (the upstream binary gap is unchanged); resolution
|
|
88
|
+
* notes that ENC-0e ships the darwin demotion visibility surface.
|
|
89
|
+
* - HG-5 → derived from the qualification record: an empty record is
|
|
90
|
+
* `"superseded"` (no measurement on this device); a `failed` verdict closes
|
|
91
|
+
* it with the measured p95/RSS wording; a `qualified` verdict closes it with
|
|
92
|
+
* "measured" wording. Severity stays `"medium"` from the base row.
|
|
93
|
+
* `platform` is carried for contract symmetry with Worker B's route input; the
|
|
94
|
+
* HG rules here do not branch on it (HG-4's darwin note applies regardless).
|
|
95
|
+
*/
|
|
96
|
+
export function computeSetupCortexBlockers(input) {
|
|
97
|
+
const { qualification, headCount } = input;
|
|
98
|
+
return SETUP_CORTEX_BLOCKERS.map((base) => {
|
|
99
|
+
switch (base.id) {
|
|
100
|
+
case "HG-1":
|
|
101
|
+
return headCount === ENCODER_HEAD_ORDER.length
|
|
102
|
+
? { ...base, status: "closed" }
|
|
103
|
+
: base;
|
|
104
|
+
case "HG-4":
|
|
105
|
+
return {
|
|
106
|
+
...base,
|
|
107
|
+
resolution: `${base.resolution} ENC-0e shipped the darwin demotion visibility surface.`,
|
|
108
|
+
};
|
|
109
|
+
case "HG-5":
|
|
110
|
+
if (qualification === null) {
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
status: "superseded",
|
|
114
|
+
resolution: "No QualificationV1 record on this device — run the gate (scripts/encoder/gate-qualify.mjs) to measure.",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (qualification.verdict === "failed") {
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
title: "Real-asset qualification: failed (latency + marginal-RSS over budget)",
|
|
121
|
+
status: "closed",
|
|
122
|
+
resolution: `p95 ${qualification.p95Ms} ms vs ${ENCODER_LATENCY_P95_MS} ms gate, marginal RSS ${qualification.rssMib} MiB vs ${ENCODER_RSS_BUDGET_BYTES / MIB} MiB cap — mode A requires the native onnxruntime-node selection`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
...base,
|
|
127
|
+
title: "Real-asset qualification: measured",
|
|
128
|
+
status: "closed",
|
|
129
|
+
};
|
|
130
|
+
default:
|
|
131
|
+
return base;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The static PER-ACTION CANDIDATE gate ids — this is POLICY, NOT the derived
|
|
137
|
+
* gating. fetch-model and bench ARE candidates for HG-1 (five-head training)
|
|
138
|
+
* and HG-3 (install budget); verify-asset is a pure re-read of committed assets
|
|
139
|
+
* and is NEVER gated (empty candidate list). The derived gating (below)
|
|
140
|
+
* intersects these candidates with the currently-OPEN blockers from the live
|
|
141
|
+
* computed list, so a candidate only blocks when its blocker is actually open.
|
|
142
|
+
*/
|
|
143
|
+
const ACTION_GATE_CANDIDATES = {
|
|
144
|
+
"fetch-model": ["HG-1", "HG-3"],
|
|
145
|
+
bench: ["HG-1", "HG-3"],
|
|
146
|
+
"verify-asset": [],
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Re-derived VC9B action gating from the LIVE computed blockers. An action is
|
|
150
|
+
* gated by exactly the candidate ids that are `status:"open"` AND
|
|
151
|
+
* `severity:"blocker"` in the supplied blockers. `blockers` defaults to the
|
|
152
|
+
* base `SETUP_CORTEX_BLOCKERS` (authored all-open) for backward compatibility
|
|
153
|
+
* with single-arg callers — with HG-1 closed by a computed list, fetch-model
|
|
154
|
+
* and bench surface `["HG-3"]`; verify-asset always `[]`.
|
|
155
|
+
*/
|
|
156
|
+
export function setupCortexActionBlockers(action, blockers) {
|
|
157
|
+
const live = blockers ?? SETUP_CORTEX_BLOCKERS;
|
|
158
|
+
const openBlockerIds = new Set(live.filter((b) => b.status === "open" && b.severity === "blocker").map((b) => b.id));
|
|
159
|
+
return ACTION_GATE_CANDIDATES[action].filter((id) => openBlockerIds.has(id));
|
|
160
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/vector-cortex/setup-cortex-blockers-compute.ts — canonical blocker
|
|
3
|
+
* manifest + pure computed blocker derivation for the Setup Cortex status
|
|
4
|
+
* read path (VC9A/ENC-0g).
|
|
5
|
+
*
|
|
6
|
+
* The hard-gate items enumerated in docs/vector-cortex/vc2-model-prep.md §6
|
|
7
|
+
* (per the 2026-08-05 research update: the opset-14→17 re-export blocker is
|
|
8
|
+
* REMOVED because onnx-community exports are now opset 21). This module is the
|
|
9
|
+
* SINGLE canonical source of those blockers — the route file
|
|
10
|
+
* (routes-setup-cortex.ts) carries NO string literals for them; it reads this
|
|
11
|
+
* manifest so the UI rows and the spec stay in one place.
|
|
12
|
+
*
|
|
13
|
+
* ENC-0g: `SETUP_CORTEX_BLOCKERS` remains the canonical BASE data (authored
|
|
14
|
+
* all-open, byte-identical to ENC-0f-era for flag-off). `computeSetupCortexBlockers`
|
|
15
|
+
* is a PURE function over (platform, ENC-0f QualificationV1 record, asset-manifest
|
|
16
|
+
* head-count) that returns the live blocker list: HG-1 closes on a five-head
|
|
17
|
+
* manifest (ENC-0c), HG-5 reflects the measured qualification verdict, HG-4
|
|
18
|
+
* notes the ENC-0e visibility close while the binary gap persists, HG-3 stays
|
|
19
|
+
* open (genuinely unresolved). `setupCortexActionBlockers` re-derives VC9B
|
|
20
|
+
* action gating from the live computed blockers (intersects each action's
|
|
21
|
+
* static candidate gate ids with the currently-open blocker ids).
|
|
22
|
+
*
|
|
23
|
+
* Reader-only, pure computation: zero network, no writes (PREVENT-PI-004), no
|
|
24
|
+
* `any` (PREVENT-011). Thresholds come from src/vector-cortex/encoder/types.js
|
|
25
|
+
* (ENCODER_HEAD_ORDER / ENCODER_LATENCY_P95_MS / ENCODER_RSS_BUDGET_BYTES) —
|
|
26
|
+
* never magic numbers in the computed path.
|
|
27
|
+
*/
|
|
28
|
+
import { ENCODER_HEAD_ORDER, ENCODER_LATENCY_P95_MS, ENCODER_RSS_BUDGET_BYTES, } from "./encoder/types.js";
|
|
29
|
+
const MIB = 1024 * 1024;
|
|
30
|
+
/**
|
|
31
|
+
* Marker threshold-failure emitted by the status route when NO QualificationV1
|
|
32
|
+
* record exists on the device (or it is missing / unreadable / corrupt) — the
|
|
33
|
+
* route falls back to the verify-only verdict and includes this marker, never a
|
|
34
|
+
* fabricated pass and never a bare silent fallback. SINGLE source: the status
|
|
35
|
+
* route references this const, never a re-literal (no-scattered-literal scan).
|
|
36
|
+
*/
|
|
37
|
+
export const QUALIFICATION_RECORD_UNAVAILABLE = "qualification_record_unavailable";
|
|
38
|
+
/**
|
|
39
|
+
* The four blockers VC9A reports. Enumerates the vc2-model-prep §6 items that
|
|
40
|
+
* remain per the 2026-08-05 research. The opset re-export blocker (formerly
|
|
41
|
+
* §6 #2) is NOT listed: onnx-community exports are opset 21, so it is removed.
|
|
42
|
+
* This is the canonical BASE (all `status:"open"`); `computeSetupCortexBlockers`
|
|
43
|
+
* derives the live list from it. Flag-off consumes this array verbatim.
|
|
44
|
+
*/
|
|
45
|
+
export const SETUP_CORTEX_BLOCKERS = [
|
|
46
|
+
{
|
|
47
|
+
id: "HG-1",
|
|
48
|
+
title: "Five projection heads do not exist",
|
|
49
|
+
severity: "blocker",
|
|
50
|
+
status: "open",
|
|
51
|
+
resolution: "Supervision transfer onto a frozen bge-small-en-v1.5 trunk (contradiction distilled from cross-encoder/nli-deberta-v3-small; dependency NLI-assisted; cache-stability deterministic; payload-routing small MLP) — VC2B training + export.",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "HG-3",
|
|
55
|
+
title: "onnxruntime-node install exceeds the 80 MiB asset budget",
|
|
56
|
+
severity: "blocker",
|
|
57
|
+
status: "open",
|
|
58
|
+
resolution: "onnxruntime-node bundles ~258 MiB across all platforms. Candidate: transformers.js v4.2.0 (9.5 MiB shell, pure-Node via onnxruntime-web WASM) measured against budget + p95 gate before committing.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "HG-4",
|
|
62
|
+
title: "No darwin-x64 binary in onnxruntime-node",
|
|
63
|
+
severity: "high",
|
|
64
|
+
status: "open",
|
|
65
|
+
resolution: "Intel-Mac mode-A users demote to the WASM path (if HG-3 resolves that way) or mode B. " +
|
|
66
|
+
"darwin-x64: no native binary upstream (arm64-only); mode-B WASM per HG-4.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "HG-5",
|
|
70
|
+
title: "RSS margin at 512 tokens is ~0.5%",
|
|
71
|
+
severity: "medium",
|
|
72
|
+
status: "open",
|
|
73
|
+
resolution: "149.2 MiB vs 150 MiB cap with run-to-run variance 119-149 MiB; considers capping mode A at 384 tokens or using the marginal-footprint accounting runtime.ts already implements.",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
/** Look up one blocker by id; undefined when unknown (defensive). */
|
|
77
|
+
export function setupCortexBlocker(id) {
|
|
78
|
+
return SETUP_CORTEX_BLOCKERS.find((b) => b.id === id);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The live blockers computed from (platform, ENC-0f QualificationV1 record,
|
|
82
|
+
* asset-manifest head-count). Pure + deterministic — no IO, no clock, no flag
|
|
83
|
+
* dependence. Rules:
|
|
84
|
+
* - HG-1 → `"closed"` when the asset manifest declares all five projection
|
|
85
|
+
* heads (`headCount === ENCODER_HEAD_ORDER.length`); otherwise stays open.
|
|
86
|
+
* - HG-3 → unchanged (genuinely open — onnxruntime-node budget unresolved).
|
|
87
|
+
* - HG-4 → stays `"open"` (the upstream binary gap is unchanged); resolution
|
|
88
|
+
* notes that ENC-0e ships the darwin demotion visibility surface.
|
|
89
|
+
* - HG-5 → derived from the qualification record: an empty record is
|
|
90
|
+
* `"superseded"` (no measurement on this device); a `failed` verdict closes
|
|
91
|
+
* it with the measured p95/RSS wording; a `qualified` verdict closes it with
|
|
92
|
+
* "measured" wording. Severity stays `"medium"` from the base row.
|
|
93
|
+
* `platform` is carried for contract symmetry with Worker B's route input; the
|
|
94
|
+
* HG rules here do not branch on it (HG-4's darwin note applies regardless).
|
|
95
|
+
*/
|
|
96
|
+
export function computeSetupCortexBlockers(input) {
|
|
97
|
+
const { qualification, headCount } = input;
|
|
98
|
+
return SETUP_CORTEX_BLOCKERS.map((base) => {
|
|
99
|
+
switch (base.id) {
|
|
100
|
+
case "HG-1":
|
|
101
|
+
return headCount === ENCODER_HEAD_ORDER.length
|
|
102
|
+
? { ...base, status: "closed" }
|
|
103
|
+
: base;
|
|
104
|
+
case "HG-4":
|
|
105
|
+
return {
|
|
106
|
+
...base,
|
|
107
|
+
resolution: `${base.resolution} ENC-0e shipped the darwin demotion visibility surface.`,
|
|
108
|
+
};
|
|
109
|
+
case "HG-5":
|
|
110
|
+
if (qualification === null) {
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
status: "superseded",
|
|
114
|
+
resolution: "No QualificationV1 record on this device — run the gate (scripts/encoder/gate-qualify.mjs) to measure.",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (qualification.verdict === "failed") {
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
title: "Real-asset qualification: failed (latency + marginal-RSS over budget)",
|
|
121
|
+
status: "closed",
|
|
122
|
+
resolution: `p95 ${qualification.p95Ms} ms vs ${ENCODER_LATENCY_P95_MS} ms gate, marginal RSS ${qualification.rssMib} MiB vs ${ENCODER_RSS_BUDGET_BYTES / MIB} MiB cap — mode A requires the native onnxruntime-node selection`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
...base,
|
|
127
|
+
title: "Real-asset qualification: measured",
|
|
128
|
+
status: "closed",
|
|
129
|
+
};
|
|
130
|
+
default:
|
|
131
|
+
return base;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The static PER-ACTION CANDIDATE gate ids — this is POLICY, NOT the derived
|
|
137
|
+
* gating. fetch-model and bench ARE candidates for HG-1 (five-head training)
|
|
138
|
+
* and HG-3 (install budget); verify-asset is a pure re-read of committed assets
|
|
139
|
+
* and is NEVER gated (empty candidate list). The derived gating (below)
|
|
140
|
+
* intersects these candidates with the currently-OPEN blockers from the live
|
|
141
|
+
* computed list, so a candidate only blocks when its blocker is actually open.
|
|
142
|
+
*/
|
|
143
|
+
const ACTION_GATE_CANDIDATES = {
|
|
144
|
+
"fetch-model": ["HG-1", "HG-3"],
|
|
145
|
+
bench: ["HG-1", "HG-3"],
|
|
146
|
+
"verify-asset": [],
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Re-derived VC9B action gating from the LIVE computed blockers. An action is
|
|
150
|
+
* gated by exactly the candidate ids that are `status:"open"` AND
|
|
151
|
+
* `severity:"blocker"` in the supplied blockers. `blockers` defaults to the
|
|
152
|
+
* base `SETUP_CORTEX_BLOCKERS` (authored all-open) for backward compatibility
|
|
153
|
+
* with single-arg callers — with HG-1 closed by a computed list, fetch-model
|
|
154
|
+
* and bench surface `["HG-3"]`; verify-asset always `[]`.
|
|
155
|
+
*/
|
|
156
|
+
export function setupCortexActionBlockers(action, blockers) {
|
|
157
|
+
const live = blockers ?? SETUP_CORTEX_BLOCKERS;
|
|
158
|
+
const openBlockerIds = new Set(live.filter((b) => b.status === "open" && b.severity === "blocker").map((b) => b.id));
|
|
159
|
+
return ACTION_GATE_CANDIDATES[action].filter((id) => openBlockerIds.has(id));
|
|
160
|
+
}
|
|
@@ -21,8 +21,12 @@ export interface BlockerV1 {
|
|
|
21
21
|
readonly title: string;
|
|
22
22
|
/** Severity: blocker | high | medium. */
|
|
23
23
|
readonly severity: "blocker" | "high" | "medium";
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Lifecycle state. "open" (hard gate unresolved), "closed" (re-derived by
|
|
26
|
+
* the ENC-0g computed blocker list, e.g. HG-1 once five heads exist), or
|
|
27
|
+
* "superseded" (an open question with no live measurement on this device).
|
|
28
|
+
*/
|
|
29
|
+
readonly status: "open" | "closed" | "superseded";
|
|
26
30
|
/** Optional candidate resolution surfaced for the user / controller. */
|
|
27
31
|
readonly resolution?: string;
|
|
28
32
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/qualification-record.ts — ENC-0g QualificationV1 reader.
|
|
3
|
+
*
|
|
4
|
+
* Read-only reader for the ENC-0f qualification record at
|
|
5
|
+
* <stateDir>/encoder-qualification.json. The computed-blocker + action-gating
|
|
6
|
+
* functions live in setup-cortex-blockers.ts (Worker A's canonical module).
|
|
7
|
+
*
|
|
8
|
+
* Reader-only: local filesystem read only (PREVENT-PI-004), no `any`
|
|
9
|
+
* (PREVENT-011), never payloads/prompts/ledger (EVAL-REDACT-002).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import type { QualificationV1 } from "../../src/vector-cortex/encoder/qualify.js";
|
|
16
|
+
import { QUALIFICATION_RECORD_UNAVAILABLE } from "../../src/vector-cortex/setup-cortex-blockers-compute.js";
|
|
17
|
+
|
|
18
|
+
/** Sentinel appended to thresholdFailures when no valid record is readable (canonical def in setup-cortex-blockers-compute). */
|
|
19
|
+
export { QUALIFICATION_RECORD_UNAVAILABLE };
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the encoder state dir (the record's home) — same precedence as
|
|
23
|
+
* scripts/encoder/gate-qualify.mjs: MEGACOMPACT_STATE_DIR first, else
|
|
24
|
+
* ~/.pi/mega-compact-encoder.
|
|
25
|
+
*/
|
|
26
|
+
export function encoderStateDir(): string {
|
|
27
|
+
const env = process.env.MEGACOMPACT_STATE_DIR;
|
|
28
|
+
return env !== undefined && env.length > 0
|
|
29
|
+
? env
|
|
30
|
+
: join(homedir(), ".pi", "mega-compact-encoder");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Read + minimally validate the QualificationV1 record. Returns null on a
|
|
35
|
+
* missing/unreadable file, a JSON parse failure, or a shape mismatch (the
|
|
36
|
+
* route degrades to verify-only — never crashes). Read-only (PREVENT-PI-004).
|
|
37
|
+
*/
|
|
38
|
+
export function readQualificationRecord(stateDir: string): QualificationV1 | null {
|
|
39
|
+
let raw: string;
|
|
40
|
+
try {
|
|
41
|
+
// guardrails-allow PREVENT-PI-004: local qualification-record filesystem read (loopback)
|
|
42
|
+
raw = readFileSync(join(stateDir, "encoder-qualification.json"), "utf8");
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
let parsed: unknown;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(raw) as unknown;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const rec = parsed as Record<string, unknown> | null;
|
|
53
|
+
if (rec === null || typeof rec !== "object") return null;
|
|
54
|
+
if (rec["schema"] !== "qualification-v1") return null;
|
|
55
|
+
if (typeof rec["verdict"] !== "string") return null;
|
|
56
|
+
if (!Array.isArray(rec["reasons"])) return null;
|
|
57
|
+
if (typeof rec["platform"] !== "string") return null;
|
|
58
|
+
const reasons = rec["reasons"].map((r) => String(r));
|
|
59
|
+
return {
|
|
60
|
+
schema: "qualification-v1",
|
|
61
|
+
verdict: rec["verdict"] === "qualified" ? "qualified" : "failed",
|
|
62
|
+
reasons,
|
|
63
|
+
platform: rec["platform"],
|
|
64
|
+
p95Ms: typeof rec["p95Ms"] === "number" ? rec["p95Ms"] : 0,
|
|
65
|
+
rssMib: typeof rec["rssMib"] === "number" ? rec["rssMib"] : 0,
|
|
66
|
+
opset: typeof rec["opset"] === "number" ? rec["opset"] : 0,
|
|
67
|
+
digest: typeof rec["digest"] === "string" ? rec["digest"] : "",
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
@@ -288,5 +288,11 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
|
|
|
288
288
|
"ENC-0f p95 + marginal-RSS qualification gate (real trained asset → mode A): runs the ENC-0d-promoted trained asset through the bench under --expose-gc, asserts p95 ≤ 40 ms @ 512/4 threads, marginal RSS ≤ 150 MiB (baseline-subtracted), determinism, and opset-21; on pass emits QualificationV1 + flips runtime to qualified mode A, on failure asset stays demoted to mode B. OFF = no qualification gate runs, no QualificationV1 written, runtime keeps serving the ENC-0d survivor (byte-identical predecessor).",
|
|
289
289
|
true,
|
|
290
290
|
),
|
|
291
|
+
boolDirect(
|
|
292
|
+
"MEGACOMPACT_ENC_0G",
|
|
293
|
+
"ENC-0g Setup Cortex honest state (verdict override + live blockers)",
|
|
294
|
+
"ENC-0g makes the Setup Cortex status route honest: reads the ENC-0f QualificationV1 record (when ENC_0F is ON and a record exists) and lets its verdict override the structural verify for the qualification field; computes the blocker list from (platform, record, manifest head-count) with corrected HG statuses/wording; re-derives VC9B action gating from live blockers. OFF = verdict from verifyEncoderAsset alone, static SETUP_CORTEX_BLOCKERS, static action gating (byte-identical ENC-0f predecessor).",
|
|
295
|
+
true,
|
|
296
|
+
),
|
|
291
297
|
],
|
|
292
298
|
};
|
|
@@ -19,10 +19,18 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
import { join, dirname } from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
22
25
|
import type { RouteContext } from "./routes-core.js";
|
|
23
26
|
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";
|
|
27
|
+
import { VC9B_ENABLED, ENC_0G_ENABLED, ENC_0F_ENABLED } from "../../src/config.js";
|
|
28
|
+
import { setupCortexActionBlockers, computeSetupCortexBlockers } from "./setup-cortex-blockers.js";
|
|
29
|
+
import { readEncoderManifest, detectPlatform } from "../../src/vector-cortex/encoder/asset.js";
|
|
30
|
+
import {
|
|
31
|
+
readQualificationRecord,
|
|
32
|
+
encoderStateDir,
|
|
33
|
+
} from "./qualification-record.js";
|
|
26
34
|
import {
|
|
27
35
|
runSetupCortexAction,
|
|
28
36
|
readActionLogTail,
|
|
@@ -39,6 +47,42 @@ function isActionKind(v: unknown): v is SetupCortexActionKind {
|
|
|
39
47
|
return typeof v === "string" && ACTION_KINDS.has(v as SetupCortexActionKind);
|
|
40
48
|
}
|
|
41
49
|
|
|
50
|
+
/** The encoder asset dir used by the action gate (mirrors routes-setup-cortex.ts). */
|
|
51
|
+
function encoderAssetDir(): string | null {
|
|
52
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
const rel = join("assets", "vector-cortex", "encoder-v1");
|
|
54
|
+
for (let i = 0; i < 8; i++) {
|
|
55
|
+
const candidate = join(dir, rel);
|
|
56
|
+
if (existsSync(join(candidate, "manifest.json"))) return candidate;
|
|
57
|
+
const next = dirname(dir);
|
|
58
|
+
if (next === dir) break;
|
|
59
|
+
dir = next;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* ENC-0g: the live computed blockers for the action gate. When both gates are
|
|
66
|
+
* ON, read the QualificationV1 record + verified manifest head-count and derive
|
|
67
|
+
* the live list (so a closed HG-1 no longer gates fetch-model/bench). Otherwise
|
|
68
|
+
* return null and let setupCortexActionBlockers fall back to the static base.
|
|
69
|
+
*/
|
|
70
|
+
function liveActionBlockers(): ReturnType<typeof computeSetupCortexBlockers> | null {
|
|
71
|
+
if (!ENC_0G_ENABLED() || !ENC_0F_ENABLED()) return null;
|
|
72
|
+
const record = readQualificationRecord(encoderStateDir());
|
|
73
|
+
let headCount: number | null = null;
|
|
74
|
+
const dir = encoderAssetDir();
|
|
75
|
+
if (dir !== null) {
|
|
76
|
+
const manifest = readEncoderManifest(dir);
|
|
77
|
+
if (manifest !== null) headCount = Object.keys(manifest.heads).length;
|
|
78
|
+
}
|
|
79
|
+
return computeSetupCortexBlockers({
|
|
80
|
+
platform: detectPlatform(),
|
|
81
|
+
qualification: record,
|
|
82
|
+
headCount,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
42
86
|
/** Flag-off response, byte-identical regardless of request (VC9B absent). */
|
|
43
87
|
function sendDisabled(res: ServerResponse): void {
|
|
44
88
|
sendJson(res, 404, { error: "disabled" });
|
|
@@ -79,7 +123,10 @@ export function handleSetupCortexAction(
|
|
|
79
123
|
}
|
|
80
124
|
// Hard-gate check: when an OPEN hard-gate item gates this action, do NOT
|
|
81
125
|
// spawn — surface the blocker ids so the client highlights the matching rows.
|
|
82
|
-
|
|
126
|
+
// ENC-0g: re-derive against the LIVE computed blockers (a closed HG-1 no
|
|
127
|
+
// longer blocks), falling back to the static base when the gates are off.
|
|
128
|
+
const live = liveActionBlockers();
|
|
129
|
+
const blockers = live !== null ? setupCortexActionBlockers(action, live) : setupCortexActionBlockers(action);
|
|
83
130
|
if (blockers.length > 0) {
|
|
84
131
|
sendJson(res, 423, {
|
|
85
132
|
error: "action_blocked_by_open_item",
|
|
@@ -25,12 +25,18 @@ import { readFileSync, statSync } from "node:fs";
|
|
|
25
25
|
import { join, dirname } from "node:path";
|
|
26
26
|
import { fileURLToPath } from "node:url";
|
|
27
27
|
import type { RouteContext } from "./routes-core.js";
|
|
28
|
-
import { VC9A_ENABLED, ENC_0E_ENABLED } from "../../src/config.js";
|
|
28
|
+
import { VC9A_ENABLED, ENC_0E_ENABLED, ENC_0F_ENABLED, ENC_0G_ENABLED } from "../../src/config.js";
|
|
29
29
|
import { readEncoderManifest, verifyEncoderAsset, detectPlatform } from "../../src/vector-cortex/encoder/asset.js";
|
|
30
|
+
import type { QualificationV1 } from "../../src/vector-cortex/encoder/qualify.js";
|
|
30
31
|
import { selectRuntimeBackend } from "../../src/vector-cortex/encoder/runtime-select.js";
|
|
31
32
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
32
33
|
import { deriveVcStatus } from "./vc-status.js";
|
|
33
|
-
import { SETUP_CORTEX_BLOCKERS } from "./setup-cortex-blockers.js";
|
|
34
|
+
import { SETUP_CORTEX_BLOCKERS, computeSetupCortexBlockers } from "./setup-cortex-blockers.js";
|
|
35
|
+
import {
|
|
36
|
+
readQualificationRecord,
|
|
37
|
+
encoderStateDir,
|
|
38
|
+
QUALIFICATION_RECORD_UNAVAILABLE,
|
|
39
|
+
} from "./qualification-record.js";
|
|
34
40
|
import type {
|
|
35
41
|
SetupCortexStatusResponse,
|
|
36
42
|
BlockerV1,
|
|
@@ -62,6 +68,8 @@ interface SetupCortexFacts {
|
|
|
62
68
|
assetDigestPrefix: string | null;
|
|
63
69
|
verdict: "qualified" | "demoted" | "unavailable";
|
|
64
70
|
thresholdFailures: string[];
|
|
71
|
+
/** Number of projection heads the verified manifest declares, or null. */
|
|
72
|
+
headCount: number | null;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
interface SetupCortexFactCache {
|
|
@@ -72,7 +80,13 @@ interface SetupCortexFactCache {
|
|
|
72
80
|
let factCache: SetupCortexFactCache | null = null;
|
|
73
81
|
|
|
74
82
|
/** Stable cache key: manifest bytes + (size,mtime) of the asset files + platform. */
|
|
75
|
-
function factCacheKey(
|
|
83
|
+
function factCacheKey(
|
|
84
|
+
dir: string,
|
|
85
|
+
manifestPath: string,
|
|
86
|
+
stateDir: string,
|
|
87
|
+
record: QualificationV1 | null,
|
|
88
|
+
recordGate: boolean,
|
|
89
|
+
): string | null {
|
|
76
90
|
const platform = detectPlatform();
|
|
77
91
|
if (!platform) return null;
|
|
78
92
|
const parts: string[] = [platform];
|
|
@@ -86,16 +100,56 @@ function factCacheKey(dir: string, manifestPath: string): string | null {
|
|
|
86
100
|
} catch {
|
|
87
101
|
return null;
|
|
88
102
|
}
|
|
103
|
+
// ENC-0g: fold the qualification-record gate + (mtime, content sha) into the
|
|
104
|
+
// key so a re-run gate invalidates memoized facts (no stale verdict served).
|
|
105
|
+
try {
|
|
106
|
+
const s = statSync(join(stateDir, "encoder-qualification.json"));
|
|
107
|
+
parts.push(`g:${recordGate ? "on" : "off"}`, `q:${s.size}:${s.mtimeMs}`);
|
|
108
|
+
parts.push(createHash("sha256").update(JSON.stringify(record)).digest("hex"));
|
|
109
|
+
} catch {
|
|
110
|
+
parts.push(`g:${recordGate ? "on" : "off"}`, "q:absent");
|
|
111
|
+
}
|
|
89
112
|
return parts.join("|");
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
function
|
|
115
|
+
function applyQualificationOverride(
|
|
116
|
+
base: SetupCortexFacts,
|
|
117
|
+
record: QualificationV1 | null,
|
|
118
|
+
recordGate: boolean,
|
|
119
|
+
): SetupCortexFacts {
|
|
120
|
+
// Flag-off (recordGate false): byte-identical verify-derived facts.
|
|
121
|
+
if (!recordGate) return base;
|
|
122
|
+
if (record !== null) {
|
|
123
|
+
// The ENC-0f QualificationV1 failure maps onto the contract "demoted": a
|
|
124
|
+
// structurally-valid asset whose real-asset gate measured failure is honest
|
|
125
|
+
// as demoted, NOT qualified. mode stays verify-derived (A).
|
|
126
|
+
return {
|
|
127
|
+
...base,
|
|
128
|
+
verdict: record.verdict === "qualified" ? "qualified" : "demoted",
|
|
129
|
+
thresholdFailures: [...record.reasons],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// No record + gate on: keep the verify verdict but surface the missing-record
|
|
133
|
+
// sentinel (never a fabricated pass, never a bare silent fallback).
|
|
134
|
+
return {
|
|
135
|
+
...base,
|
|
136
|
+
thresholdFailures: [...base.thresholdFailures, QUALIFICATION_RECORD_UNAVAILABLE],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function computeSetupCortexFacts(
|
|
141
|
+
dir: string,
|
|
142
|
+
stateDir: string,
|
|
143
|
+
record: QualificationV1 | null,
|
|
144
|
+
recordGate: boolean,
|
|
145
|
+
): SetupCortexFacts | null {
|
|
93
146
|
const manifest = readEncoderManifest(dir);
|
|
94
147
|
if (manifest === null) {
|
|
95
|
-
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
148
|
+
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [], headCount: null };
|
|
96
149
|
}
|
|
150
|
+
const headCount = Object.keys(manifest.heads).length;
|
|
97
151
|
const manifestPath = join(dir, "manifest.json");
|
|
98
|
-
const key = factCacheKey(dir, manifestPath);
|
|
152
|
+
const key = factCacheKey(dir, manifestPath, stateDir, record, recordGate);
|
|
99
153
|
if (key === null) return null;
|
|
100
154
|
if (factCache !== null && factCache.key === key) return factCache.facts;
|
|
101
155
|
let digest: string;
|
|
@@ -103,26 +157,31 @@ function computeSetupCortexFacts(dir: string): SetupCortexFacts | null {
|
|
|
103
157
|
// guardrails-allow PREVENT-PI-004: local manifest filesystem read (loopback)
|
|
104
158
|
digest = createHash("sha256").update(readFileSync(manifestPath)).digest("hex");
|
|
105
159
|
} catch {
|
|
106
|
-
const
|
|
160
|
+
const base: SetupCortexFacts = { mode: "B", assetDigestPrefix: null, verdict: "demoted", thresholdFailures: ["ENC_ASSET_UNREADABLE"], headCount };
|
|
161
|
+
const facts = applyQualificationOverride(base, record, recordGate);
|
|
107
162
|
factCache = { key, facts };
|
|
108
163
|
return facts;
|
|
109
164
|
}
|
|
110
165
|
const verify = verifyEncoderAsset(dir, manifest, detectPlatform());
|
|
111
166
|
const prefix = digest.slice(0, 12);
|
|
112
|
-
const
|
|
113
|
-
? { mode: "A", assetDigestPrefix: prefix, verdict: "qualified", thresholdFailures: [] }
|
|
114
|
-
: { mode: "B", assetDigestPrefix: prefix, verdict: "demoted", thresholdFailures: [verify.code] };
|
|
167
|
+
const base: SetupCortexFacts = verify.ok
|
|
168
|
+
? { mode: "A", assetDigestPrefix: prefix, verdict: "qualified", thresholdFailures: [], headCount }
|
|
169
|
+
: { mode: "B", assetDigestPrefix: prefix, verdict: "demoted", thresholdFailures: [verify.code], headCount };
|
|
170
|
+
const facts = applyQualificationOverride(base, record, recordGate);
|
|
115
171
|
factCache = { key, facts };
|
|
116
172
|
return facts;
|
|
117
173
|
}
|
|
118
174
|
|
|
119
|
-
function setupCortexFacts(
|
|
175
|
+
function setupCortexFacts(
|
|
176
|
+
record: QualificationV1 | null,
|
|
177
|
+
recordGate: boolean,
|
|
178
|
+
): SetupCortexFacts {
|
|
120
179
|
const dir = encoderAssetDir();
|
|
121
180
|
if (dir === null) {
|
|
122
|
-
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
181
|
+
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [], headCount: null };
|
|
123
182
|
}
|
|
124
|
-
const facts = computeSetupCortexFacts(dir);
|
|
125
|
-
return facts ?? { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
183
|
+
const facts = computeSetupCortexFacts(dir, encoderStateDir(), record, recordGate);
|
|
184
|
+
return facts ?? { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [], headCount: null };
|
|
126
185
|
}
|
|
127
186
|
|
|
128
187
|
/**
|
|
@@ -145,8 +204,25 @@ export function handleSetupCortexStatus(
|
|
|
145
204
|
}
|
|
146
205
|
|
|
147
206
|
const enabled = VC9A_ENABLED();
|
|
148
|
-
|
|
149
|
-
|
|
207
|
+
|
|
208
|
+
// ENC-0g: when both gates are ON, read the QualificationV1 record and let its
|
|
209
|
+
// verdict override the structural verify for the `qualification` field. When
|
|
210
|
+
// ENC_0G is OFF, nothing below reads the record (byte-identical to ENC-0f-era).
|
|
211
|
+
const enc0g = enabled && ENC_0G_ENABLED();
|
|
212
|
+
const recordGate = enc0g && ENC_0F_ENABLED();
|
|
213
|
+
const record = recordGate ? readQualificationRecord(encoderStateDir()) : null;
|
|
214
|
+
|
|
215
|
+
const facts = enabled ? setupCortexFacts(record, recordGate) : null;
|
|
216
|
+
|
|
217
|
+
const blocks: BlockerV1[] = enabled
|
|
218
|
+
? enc0g
|
|
219
|
+
? [...computeSetupCortexBlockers({
|
|
220
|
+
platform: detectPlatform(),
|
|
221
|
+
qualification: record,
|
|
222
|
+
headCount: facts ? facts.headCount : null,
|
|
223
|
+
})]
|
|
224
|
+
: [...SETUP_CORTEX_BLOCKERS]
|
|
225
|
+
: [];
|
|
150
226
|
|
|
151
227
|
// ENC-0e: surface the darwin-x64 demotion reason additively (reader-only GET,
|
|
152
228
|
// no new route). The platform is read locally; the selection is pure. On a
|