pi-mega-compact 0.20.36 → 0.20.39
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-ml5b.js +26 -0
- package/dist/config/vector-cortex-ml5c.js +28 -0
- package/dist/config/vector-cortex.js +3 -1
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/monitoring.js +172 -0
- package/dist/src/config/vector-cortex-ml5b.js +26 -0
- package/dist/src/config/vector-cortex-ml5c.js +28 -0
- package/dist/src/config/vector-cortex.js +3 -1
- package/dist/src/config.js +1 -1
- package/dist/src/monitoring.js +19 -0
- package/dist/src/store/backfill.js +0 -8
- package/dist/src/vector-cortex/encoder/bench-export.js +13 -0
- package/dist/src/vector-cortex/encoder/bench.js +100 -0
- package/dist/src/vector-cortex/encoder/runtime-emit.js +42 -0
- package/dist/src/vector-cortex/encoder/runtime-native.js +77 -0
- package/dist/src/vector-cortex/encoder/runtime-select.js +122 -0
- package/dist/src/vector-cortex/encoder/runtime-stub.js +35 -0
- package/dist/src/vector-cortex/encoder/runtime-wasm.js +71 -0
- package/dist/src/vector-cortex/encoder/runtime.js +49 -61
- package/dist/vector-cortex/encoder/bench-export.js +13 -0
- package/dist/vector-cortex/encoder/bench.js +100 -0
- package/dist/vector-cortex/encoder/runtime-emit.js +42 -0
- package/dist/vector-cortex/encoder/runtime-native.js +77 -0
- package/dist/vector-cortex/encoder/runtime-select.js +122 -0
- package/dist/vector-cortex/encoder/runtime-stub.js +35 -0
- package/dist/vector-cortex/encoder/runtime-wasm.js +71 -0
- package/dist/vector-cortex/encoder/runtime.js +49 -61
- package/dist/vectorStore/dedup-audit.js +104 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/package.json +1 -1
- package/src/config/vector-cortex-ml5b.ts +28 -0
- package/src/config/vector-cortex-ml5c.ts +30 -0
- package/src/config/vector-cortex.ts +3 -2
- package/src/config.ts +2 -0
- package/src/monitoring.ts +24 -0
- package/src/store/backfill.ts +0 -6
- package/src/vector-cortex/encoder/bench-export.ts +65 -0
- package/src/vector-cortex/encoder/bench.ts +109 -0
- package/src/vector-cortex/encoder/runtime-emit.ts +47 -0
- package/src/vector-cortex/encoder/runtime-native.ts +117 -0
- package/src/vector-cortex/encoder/runtime-select.ts +167 -0
- package/src/vector-cortex/encoder/runtime-stub.ts +38 -0
- package/src/vector-cortex/encoder/runtime-wasm.ts +110 -0
- package/src/vector-cortex/encoder/runtime.ts +59 -66
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-ml5b.ts — ML5-B production bench harness flag.
|
|
3
|
+
*
|
|
4
|
+
* Sibling extract mirroring vector-cortex-ml5a.ts, so vector-cortex.ts stays
|
|
5
|
+
* under its 300-line soft limit (soft-as-hard gate). This is the ONNX Runtime
|
|
6
|
+
* evaluation/benchmark sprint flag. vector-cortex.ts re-exports the ENUM below
|
|
7
|
+
* and root src/config.ts re-exports it, so no consumer import path changes.
|
|
8
|
+
*
|
|
9
|
+
* ML5-B introduces NO runtime code path: the bench harness and corpus export
|
|
10
|
+
* are developer/evidence tooling (scripts/) plus a consumer-facing TypeScript
|
|
11
|
+
* shell (src/vector-cortex/encoder/bench.ts) that only writes monitoring
|
|
12
|
+
* events. The flag records intent and scopes the sprint's evidence assets; it
|
|
13
|
+
* gates nothing at runtime today. There is no HTTP endpoint and no dashboard
|
|
14
|
+
* change, so there is no SETTINGS toggle and no EXCLUDED_SETTINGS interaction.
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
19
|
+
/**
|
|
20
|
+
* ML5-B — production bench harness (ONNX Runtime eval). Default ON.
|
|
21
|
+
* `MEGACOMPACT_ML5_B=0` disables and is byte-identical to the ML5-A survivor:
|
|
22
|
+
* no bench endpoint exists and mode B continues to serve all clients exactly as
|
|
23
|
+
* before. The flag does not gate the harness itself — the harness is an on-demand
|
|
24
|
+
* developer tool with no runtime path.
|
|
25
|
+
*/
|
|
26
|
+
export const ML5B_ENABLED = () => sprintFlag("MEGACOMPACT_ML5_B");
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-ml5c.ts — ML5-C runtime decision + packaging flag.
|
|
3
|
+
*
|
|
4
|
+
* Sibling extract mirroring vector-cortex-ml5a.ts / vector-cortex-ml5b.ts, so
|
|
5
|
+
* vector-cortex.ts stays under its 300-line soft limit (soft-as-hard gate).
|
|
6
|
+
* This is the ONNX Runtime backend selection + packaging sprint flag.
|
|
7
|
+
* vector-cortex.ts re-exports the ENUM below and root src/config.ts re-exports
|
|
8
|
+
* it, so no consumer import path changes.
|
|
9
|
+
*
|
|
10
|
+
* ML5-C selects the ONNX runtime backend (WASM vs native) based on the ML5-B
|
|
11
|
+
* bench record and platform support. The flag gates the runtime-selection
|
|
12
|
+
* dispatch only; when OFF the encoder serves mode B trigram exactly as before
|
|
13
|
+
* (byte-identical to the ML5-B survivor — no `vector_cortex_runtime_selected`
|
|
14
|
+
* event is emitted, no session-selection dispatch runs).
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
19
|
+
/**
|
|
20
|
+
* ML5-C — runtime decision + packaging (WASM vs native). Default ON.
|
|
21
|
+
* `MEGACOMPACT_ML5_C=0` disables and is byte-identical to the ML5-B survivor:
|
|
22
|
+
* no runtime selection runs — the encoder continues to serve mode B trigram,
|
|
23
|
+
* exactly as before, with no `vector_cortex_runtime_selected` event emitted.
|
|
24
|
+
* The flag gates the runtime-selection dispatch only; it does not gate the
|
|
25
|
+
* underlying WASM/native backends (which are exercised by ML5-B's bench
|
|
26
|
+
* harness and ML5-A's trained asset independently).
|
|
27
|
+
*/
|
|
28
|
+
export const ML5C_ENABLED = () => sprintFlag("MEGACOMPACT_ML5_C");
|
|
@@ -242,12 +242,14 @@ export const VC8B_ENABLED = () => sprintFlag("MEGACOMPACT_VC8B");
|
|
|
242
242
|
// VC8C (canary selection + Rust parity) extracted to vector-cortex-vc8c.ts;
|
|
243
243
|
// re-exported so existing `./config/vector-cortex.js` imports keep resolving.
|
|
244
244
|
export { VC8C_ENABLED } from "./vector-cortex-vc8c.js";
|
|
245
|
-
//
|
|
245
|
+
// Sibling extracts to stay under the 300-line soft limit.
|
|
246
246
|
export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
|
|
247
247
|
export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
|
|
248
248
|
export { VC9C_ENABLED } from "./vector-cortex-vc9c.js";
|
|
249
249
|
export { VC9D_ENABLED } from "./vector-cortex-vc9d.js";
|
|
250
250
|
export { PCC_ENABLED } from "./vector-cortex-pcc.js";
|
|
251
251
|
export { ML5A_ENABLED } from "./vector-cortex-ml5a.js";
|
|
252
|
+
export { ML5B_ENABLED } from "./vector-cortex-ml5b.js";
|
|
253
|
+
export { ML5C_ENABLED } from "./vector-cortex-ml5c.js";
|
|
252
254
|
// Breaker constants (TRIAD_RESILIENCE.md §breaker) extracted to vector-cortex-breakers.ts.
|
|
253
255
|
export { BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./vector-cortex-breakers.js";
|
package/dist/config.js
CHANGED
|
@@ -114,4 +114,4 @@ export const NEW_UI = () => ragEnabled("MEGACOMPACT_NEW_UI");
|
|
|
114
114
|
// default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
|
|
115
115
|
// so root consumers share one source of truth.
|
|
116
116
|
// ---------------------------------------------------------------------------
|
|
117
|
-
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_ENABLED, VC8B_ENABLED, VC8C_ENABLED, VC9A_ENABLED, VC9B_ENABLED, VC9C_ENABLED, VC9D_ENABLED, PCC_ENABLED, ML5A_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
117
|
+
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_ENABLED, VC8B_ENABLED, VC8C_ENABLED, VC9A_ENABLED, VC9B_ENABLED, VC9C_ENABLED, VC9D_ENABLED, PCC_ENABLED, ML5A_ENABLED, ML5B_ENABLED, ML5C_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
@@ -54,5 +54,6 @@ export const VECTOR_CORTEX_SETTINGS = {
|
|
|
54
54
|
boolDirect("MEGACOMPACT_VC9D", "VC9D Embedder Detect Consolidation", "Embedder-detect consolidation + VC9 workstream roll-up: memoizes /api/setup-detect against the mutable input (resolved binary path + mtime) so consecutive requests reuse the result without re-spawning, and unifies the embedder + cortex sub-tabs' 5s poll contract. OFF = byte-identical predecessor (VC9C-era): detect spawns fresh per request and the embedder poll keeps its previous cadence.", true),
|
|
55
55
|
boolDirect("MEGACOMPACT_PC_C", "PC-C Dashboard Cache Visibility", "Dashboard per-turn prompt-cache visibility: surfaces the per-turn stable-prefix ratio trend (GET /api/prefix-stability) in the CacheTab PrefixStabilityCard. Reads aggregate ratios/counts from the local monitoring events log only — no payload bytes. OFF = byte-identical predecessor (PC-B-era): /api/prefix-stability returns 404 and the CacheTab omits the PrefixStabilityCard.", true),
|
|
56
56
|
boolDirect("MEGACOMPACT_ML5_A", "ML5-A Five-Head Training Load", "ML5-A real trained-head loading: loadHeadProjections (trained-heads-v1) feeds selectQualifiedEncoder (trainedHeadsPath atomic demotion) + loadCalibrationV1. ON (default) = a pinned trained-heads path must load for mode A. OFF = loaders return null and selection ignores trainedHeadsPath — byte-identical to the placeholder-weighted VC2C path.", true),
|
|
57
|
+
boolDirect("MEGACOMPACT_ML5_C", "ML5-C Runtime Decision + Packaging", "ML5-C runtime backend selection (WASM vs native): selects the ONNX runtime backend based on the ML5-B bench record and platform support. ON (default) = the runtime-selection dispatch runs and emits vector_cortex_runtime_selected. OFF = no selection runs — encoder serves mode B trigram, byte-identical to ML5-B.", true),
|
|
57
58
|
],
|
|
58
59
|
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* monitoring.ts — local dedup monitoring + alerting (Sprint 14, Phase 7).
|
|
3
|
+
*
|
|
4
|
+
* Per-decision structured events go to `events.log` (append-only JSON).
|
|
5
|
+
* Aggregate metrics (hit rate, FP rate, per-tier p95 latency, storage) go to
|
|
6
|
+
* `dashboard.json` — the SAME local-only file the /dashboard UI reads. There is
|
|
7
|
+
* NO Prometheus port and NO network listener (PREVENT-PI-004). Alerting is local
|
|
8
|
+
* only: an FP-rate breach flips the tier to MARK_ONLY and writes a warning.
|
|
9
|
+
*
|
|
10
|
+
* Best-effort: logging/metrics never throw into the add()/search() path.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } from "node:fs";
|
|
13
|
+
import { dirname, join } from "node:path";
|
|
14
|
+
import { STATE_DIR_DEFAULT } from "./config.js";
|
|
15
|
+
const TIERS = ["L0", "L1", "L2", "RAPTOR"];
|
|
16
|
+
function emptyMetrics() {
|
|
17
|
+
const dec = {};
|
|
18
|
+
const dp = {};
|
|
19
|
+
const fp = {};
|
|
20
|
+
const lat = {};
|
|
21
|
+
for (const t of TIERS) {
|
|
22
|
+
dec[t] = 0;
|
|
23
|
+
dp[t] = 0;
|
|
24
|
+
fp[t] = 0;
|
|
25
|
+
lat[t] = [];
|
|
26
|
+
}
|
|
27
|
+
return { decisions: dec, deduped: dp, falsePositives: fp, latency: lat, storageBytes: 0 };
|
|
28
|
+
}
|
|
29
|
+
/** Append a structured decision event to events.log (best-effort). */
|
|
30
|
+
export function logDecision(path, ev) {
|
|
31
|
+
try {
|
|
32
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
33
|
+
appendFileSync(path, `${JSON.stringify(ev)}\n`);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* never break the extension on a log failure */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load metrics from dashboard.json, or return a fresh empty snapshot.
|
|
41
|
+
* Kept simple + synchronous (no network).
|
|
42
|
+
*/
|
|
43
|
+
export function loadMetrics(path) {
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(path)) {
|
|
46
|
+
const raw = readFileSync(path, "utf-8");
|
|
47
|
+
const parsed = JSON.parse(raw);
|
|
48
|
+
const base = emptyMetrics();
|
|
49
|
+
return {
|
|
50
|
+
decisions: { ...base.decisions, ...(parsed.decisions ?? {}) },
|
|
51
|
+
deduped: { ...base.deduped, ...(parsed.deduped ?? {}) },
|
|
52
|
+
falsePositives: { ...base.falsePositives, ...(parsed.falsePositives ?? {}) },
|
|
53
|
+
latency: { ...base.latency, ...(parsed.latency ?? {}) },
|
|
54
|
+
storageBytes: parsed.storageBytes ?? 0,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
/* corrupt metrics → fresh */
|
|
60
|
+
}
|
|
61
|
+
return emptyMetrics();
|
|
62
|
+
}
|
|
63
|
+
/** Persist metrics to dashboard.json (best-effort). */
|
|
64
|
+
export function saveMetrics(path, m) {
|
|
65
|
+
try {
|
|
66
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
67
|
+
writeFileSync(path, JSON.stringify(m));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* never break the extension */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Compute the p95 latency (ms) for a tier from its samples. */
|
|
74
|
+
export function p95(samples) {
|
|
75
|
+
if (samples.length === 0)
|
|
76
|
+
return 0;
|
|
77
|
+
const sorted = [...samples].sort((a, b) => a - b);
|
|
78
|
+
const idx = Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95));
|
|
79
|
+
return sorted[idx];
|
|
80
|
+
}
|
|
81
|
+
/** FP rate for a tier over the current window (0..1). */
|
|
82
|
+
export function fpRate(m, tier) {
|
|
83
|
+
const decisions = m.decisions[tier] ?? 0;
|
|
84
|
+
if (decisions === 0)
|
|
85
|
+
return 0;
|
|
86
|
+
return (m.falsePositives[tier] ?? 0) / decisions;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Evaluate FP-rate breaches against the config thresholds. A breached fuzzy tier
|
|
90
|
+
* (L0 vs L1/L2 have different thresholds) is auto-downgraded to MARK_ONLY — the
|
|
91
|
+
* local re-map of "alertmanager" (QA #18/#19): record but don't collapse, no
|
|
92
|
+
* remote alert. Returns the tiers flipped so the caller can mutate its config.
|
|
93
|
+
*/
|
|
94
|
+
export function evaluateAlerts(m, cfg) {
|
|
95
|
+
const breached = [];
|
|
96
|
+
const warnings = [];
|
|
97
|
+
for (const tier of TIERS) {
|
|
98
|
+
const rate = fpRate(m, tier);
|
|
99
|
+
const limit = tier === "L0" ? cfg.FP_RATE_L0 : cfg.FP_RATE_L1L2;
|
|
100
|
+
if (rate > limit) {
|
|
101
|
+
breached.push(tier);
|
|
102
|
+
warnings.push(`DEDUP FP BREACH tier=${tier} rate=${rate.toFixed(4)} > ${limit}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { breached, warnings };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Record one decision into the metrics snapshot (mutates `m` in place) and
|
|
109
|
+
* returns the updated snapshot. Caps stored latency samples to keep memory
|
|
110
|
+
* bounded (last 1000 per tier).
|
|
111
|
+
*/
|
|
112
|
+
export function recordDecision(m, tier, result, latencyMs, falsePositive = false) {
|
|
113
|
+
m.decisions[tier] = (m.decisions[tier] ?? 0) + 1;
|
|
114
|
+
if (result === "deduped")
|
|
115
|
+
m.deduped[tier] = (m.deduped[tier] ?? 0) + 1;
|
|
116
|
+
if (falsePositive)
|
|
117
|
+
m.falsePositives[tier] = (m.falsePositives[tier] ?? 0) + 1;
|
|
118
|
+
const arr = m.latency[tier] ?? (m.latency[tier] = []);
|
|
119
|
+
arr.push(latencyMs);
|
|
120
|
+
if (arr.length > 1000)
|
|
121
|
+
arr.shift();
|
|
122
|
+
return m;
|
|
123
|
+
}
|
|
124
|
+
/** Default metrics path alongside the state dir. */
|
|
125
|
+
export function defaultMetricsPath(stateDir = STATE_DIR_DEFAULT) {
|
|
126
|
+
return join(stateDir, "dashboard.json");
|
|
127
|
+
}
|
|
128
|
+
/** Default events-log path alongside the state dir. */
|
|
129
|
+
export function defaultEventsPath(stateDir = STATE_DIR_DEFAULT) {
|
|
130
|
+
return join(stateDir, "events.log");
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Append a RecallQualityEvent to events.log (best-effort, non-fatal).
|
|
134
|
+
* Follows the same append-one-JSON-line pattern as logDecision.
|
|
135
|
+
*/
|
|
136
|
+
export function logRecallQuality(path, ev) {
|
|
137
|
+
try {
|
|
138
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
139
|
+
appendFileSync(path, JSON.stringify(ev) + "\n", "utf-8");
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* best-effort — never break the extension */
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// ML5-B encoder bench events (consumer-facing for the dashboard + evidence)
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
/**
|
|
149
|
+
* Append a structured ML5-B bench event to events.log (best-effort, non-fatal).
|
|
150
|
+
* Mirrors the extension's appendEvent schema ({ ts, event, ...fields }) so the
|
|
151
|
+
* dashboard live-stream tail and evidence tooling parse the four
|
|
152
|
+
* `vector_cortex_encoder_bench_*` events identically. The bench is developer/
|
|
153
|
+
* evidence tooling with no runtime gating; this only records its results.
|
|
154
|
+
*/
|
|
155
|
+
export function logBenchEvent(path, event, fields) {
|
|
156
|
+
try {
|
|
157
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
158
|
+
appendFileSync(path, JSON.stringify({ ts: Date.now(), event, ...fields }) + "\n", "utf8");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* best-effort — never break the caller */
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Dedup audit trail (external-audit item #2)
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// The event shape and its append helper are DEFINED in vectorStore/dedup-audit.ts,
|
|
168
|
+
// co-located with the only recorder that emits them (this file already carries
|
|
169
|
+
// decision events + the metrics snapshot + FP alerting and must stay under its
|
|
170
|
+
// 300-line soft limit). Re-exported here so callers that treat monitoring.ts as
|
|
171
|
+
// the events.log barrel — including the dashboard SSE tail — keep one import.
|
|
172
|
+
export { logDedupAudit } from "./vectorStore/dedup-audit.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-ml5b.ts — ML5-B production bench harness flag.
|
|
3
|
+
*
|
|
4
|
+
* Sibling extract mirroring vector-cortex-ml5a.ts, so vector-cortex.ts stays
|
|
5
|
+
* under its 300-line soft limit (soft-as-hard gate). This is the ONNX Runtime
|
|
6
|
+
* evaluation/benchmark sprint flag. vector-cortex.ts re-exports the ENUM below
|
|
7
|
+
* and root src/config.ts re-exports it, so no consumer import path changes.
|
|
8
|
+
*
|
|
9
|
+
* ML5-B introduces NO runtime code path: the bench harness and corpus export
|
|
10
|
+
* are developer/evidence tooling (scripts/) plus a consumer-facing TypeScript
|
|
11
|
+
* shell (src/vector-cortex/encoder/bench.ts) that only writes monitoring
|
|
12
|
+
* events. The flag records intent and scopes the sprint's evidence assets; it
|
|
13
|
+
* gates nothing at runtime today. There is no HTTP endpoint and no dashboard
|
|
14
|
+
* change, so there is no SETTINGS toggle and no EXCLUDED_SETTINGS interaction.
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
19
|
+
/**
|
|
20
|
+
* ML5-B — production bench harness (ONNX Runtime eval). Default ON.
|
|
21
|
+
* `MEGACOMPACT_ML5_B=0` disables and is byte-identical to the ML5-A survivor:
|
|
22
|
+
* no bench endpoint exists and mode B continues to serve all clients exactly as
|
|
23
|
+
* before. The flag does not gate the harness itself — the harness is an on-demand
|
|
24
|
+
* developer tool with no runtime path.
|
|
25
|
+
*/
|
|
26
|
+
export const ML5B_ENABLED = () => sprintFlag("MEGACOMPACT_ML5_B");
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-ml5c.ts — ML5-C runtime decision + packaging flag.
|
|
3
|
+
*
|
|
4
|
+
* Sibling extract mirroring vector-cortex-ml5a.ts / vector-cortex-ml5b.ts, so
|
|
5
|
+
* vector-cortex.ts stays under its 300-line soft limit (soft-as-hard gate).
|
|
6
|
+
* This is the ONNX Runtime backend selection + packaging sprint flag.
|
|
7
|
+
* vector-cortex.ts re-exports the ENUM below and root src/config.ts re-exports
|
|
8
|
+
* it, so no consumer import path changes.
|
|
9
|
+
*
|
|
10
|
+
* ML5-C selects the ONNX runtime backend (WASM vs native) based on the ML5-B
|
|
11
|
+
* bench record and platform support. The flag gates the runtime-selection
|
|
12
|
+
* dispatch only; when OFF the encoder serves mode B trigram exactly as before
|
|
13
|
+
* (byte-identical to the ML5-B survivor — no `vector_cortex_runtime_selected`
|
|
14
|
+
* event is emitted, no session-selection dispatch runs).
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
19
|
+
/**
|
|
20
|
+
* ML5-C — runtime decision + packaging (WASM vs native). Default ON.
|
|
21
|
+
* `MEGACOMPACT_ML5_C=0` disables and is byte-identical to the ML5-B survivor:
|
|
22
|
+
* no runtime selection runs — the encoder continues to serve mode B trigram,
|
|
23
|
+
* exactly as before, with no `vector_cortex_runtime_selected` event emitted.
|
|
24
|
+
* The flag gates the runtime-selection dispatch only; it does not gate the
|
|
25
|
+
* underlying WASM/native backends (which are exercised by ML5-B's bench
|
|
26
|
+
* harness and ML5-A's trained asset independently).
|
|
27
|
+
*/
|
|
28
|
+
export const ML5C_ENABLED = () => sprintFlag("MEGACOMPACT_ML5_C");
|
|
@@ -242,12 +242,14 @@ export const VC8B_ENABLED = () => sprintFlag("MEGACOMPACT_VC8B");
|
|
|
242
242
|
// VC8C (canary selection + Rust parity) extracted to vector-cortex-vc8c.ts;
|
|
243
243
|
// re-exported so existing `./config/vector-cortex.js` imports keep resolving.
|
|
244
244
|
export { VC8C_ENABLED } from "./vector-cortex-vc8c.js";
|
|
245
|
-
//
|
|
245
|
+
// Sibling extracts to stay under the 300-line soft limit.
|
|
246
246
|
export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
|
|
247
247
|
export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
|
|
248
248
|
export { VC9C_ENABLED } from "./vector-cortex-vc9c.js";
|
|
249
249
|
export { VC9D_ENABLED } from "./vector-cortex-vc9d.js";
|
|
250
250
|
export { PCC_ENABLED } from "./vector-cortex-pcc.js";
|
|
251
251
|
export { ML5A_ENABLED } from "./vector-cortex-ml5a.js";
|
|
252
|
+
export { ML5B_ENABLED } from "./vector-cortex-ml5b.js";
|
|
253
|
+
export { ML5C_ENABLED } from "./vector-cortex-ml5c.js";
|
|
252
254
|
// Breaker constants (TRIAD_RESILIENCE.md §breaker) extracted to vector-cortex-breakers.ts.
|
|
253
255
|
export { BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./vector-cortex-breakers.js";
|
package/dist/src/config.js
CHANGED
|
@@ -114,4 +114,4 @@ export const NEW_UI = () => ragEnabled("MEGACOMPACT_NEW_UI");
|
|
|
114
114
|
// default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
|
|
115
115
|
// so root consumers share one source of truth.
|
|
116
116
|
// ---------------------------------------------------------------------------
|
|
117
|
-
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_ENABLED, VC8B_ENABLED, VC8C_ENABLED, VC9A_ENABLED, VC9B_ENABLED, VC9C_ENABLED, VC9D_ENABLED, PCC_ENABLED, ML5A_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
|
117
|
+
export { VC0A_ENABLED, VC0B_ENABLED, VC1A_ENABLED, VC0C_ENABLED, VC1B_ENABLED, VC1C_ENABLED, VC2A_ENABLED, VC2B_ENABLED, VC2C_ENABLED, VC3A_ENABLED, VC3B_ENABLED, VC3C_ENABLED, VC4A_ENABLED, VC4B_ENABLED, VC4C_ENABLED, VC5A_ENABLED, VC5B_ENABLED, VC5C_ENABLED, VC6A_ENABLED, VC6B_ENABLED, VC6C_ENABLED, VC7A_ENABLED, VC7B_ENABLED, VC7C_ENABLED, VC8A_ENABLED, VC8B_ENABLED, VC8C_ENABLED, VC9A_ENABLED, VC9B_ENABLED, VC9C_ENABLED, VC9D_ENABLED, PCC_ENABLED, ML5A_ENABLED, ML5B_ENABLED, ML5C_ENABLED, BREAKER_WINDOW_MS, BREAKER_MIN_ATTEMPTS, BREAKER_PERF_FAILURES, BREAKER_PERF_FAILURE_RATE, BREAKER_CORRECTNESS_FAILURES, BREAKER_COOLDOWN_MS, BREAKER_PROBE_COUNT, BREAKER_RETRY_BASE_MS, BREAKER_RETRY_CAP_MS, BREAKER_RETRY_JITTER, BREAKER_HYSTERESIS_FAILURE_RATE, BREAKER_HYSTERESIS_BUDGET_P95_MS, BREAKER_MIN_HEALTHY_RESIDENCE_MS, } from "./config/vector-cortex.js";
|
package/dist/src/monitoring.js
CHANGED
|
@@ -143,6 +143,25 @@ export function logRecallQuality(path, ev) {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
// ---------------------------------------------------------------------------
|
|
146
|
+
// ML5-B encoder bench events (consumer-facing for the dashboard + evidence)
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
/**
|
|
149
|
+
* Append a structured ML5-B bench event to events.log (best-effort, non-fatal).
|
|
150
|
+
* Mirrors the extension's appendEvent schema ({ ts, event, ...fields }) so the
|
|
151
|
+
* dashboard live-stream tail and evidence tooling parse the four
|
|
152
|
+
* `vector_cortex_encoder_bench_*` events identically. The bench is developer/
|
|
153
|
+
* evidence tooling with no runtime gating; this only records its results.
|
|
154
|
+
*/
|
|
155
|
+
export function logBenchEvent(path, event, fields) {
|
|
156
|
+
try {
|
|
157
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
158
|
+
appendFileSync(path, JSON.stringify({ ts: Date.now(), event, ...fields }) + "\n", "utf8");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* best-effort — never break the caller */
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
146
165
|
// Dedup audit trail (external-audit item #2)
|
|
147
166
|
// ---------------------------------------------------------------------------
|
|
148
167
|
// The event shape and its append helper are DEFINED in vectorStore/dedup-audit.ts,
|
|
@@ -24,7 +24,6 @@ import { buildRaptorTree } from "../dedup/raptor/tree.js";
|
|
|
24
24
|
import { defaultEmbedder } from "../embedder.js";
|
|
25
25
|
import { getStateDir } from "../store.js";
|
|
26
26
|
const BATCH = 1000;
|
|
27
|
-
const THROTTLE_MS = 0; // synchronous backfill; no cross-process yield needed
|
|
28
27
|
function ensureProgressTable(db) {
|
|
29
28
|
db.exec(`
|
|
30
29
|
CREATE TABLE IF NOT EXISTS backfill_progress (
|
|
@@ -92,9 +91,6 @@ export function backfillContentHashes(stateDir = getStateDir()) {
|
|
|
92
91
|
withTx(db, () => applyRows(pending));
|
|
93
92
|
db.prepare("INSERT INTO backfill_progress(name, last_session_id, last_id, updated, duplicates_resolved) VALUES('content_hashes',?,?,?,?) ON CONFLICT(name) DO UPDATE SET last_session_id=excluded.last_session_id, last_id=excluded.last_id, updated=excluded.updated, duplicates_resolved=excluded.duplicates_resolved").run(lastSid, lastId, updated, duplicatesResolved);
|
|
94
93
|
}
|
|
95
|
-
if (THROTTLE_MS > 0) {
|
|
96
|
-
// No-op in this synchronous build; placeholder for future streaming backfill.
|
|
97
|
-
}
|
|
98
94
|
return { processed, updated, duplicatesResolved };
|
|
99
95
|
}
|
|
100
96
|
/** True when no rows remain pending (backfill complete for this state dir). */
|
|
@@ -150,10 +146,6 @@ export function backfillPhase(phase, sessionId, stateDir, opts = {}) {
|
|
|
150
146
|
});
|
|
151
147
|
savePhaseCursor(db, phase, cursor ?? null, processed);
|
|
152
148
|
batches++;
|
|
153
|
-
if (THROTTLE_MS > 0) {
|
|
154
|
-
const end = Date.now() + THROTTLE_MS;
|
|
155
|
-
while (Date.now() < end) { /* throttle */ }
|
|
156
|
-
}
|
|
157
149
|
if (opts.interruptAfterBatches && batches >= opts.interruptAfterBatches) {
|
|
158
150
|
interrupted = true;
|
|
159
151
|
break;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/bench-export.ts — ML5-B bench result contract.
|
|
3
|
+
*
|
|
4
|
+
* BenchResultV1 is the typed surface `bench.ts` parses from the qualification
|
|
5
|
+
* harness (`scripts/ml5/bench-onnx-prod.mjs`) and the dashboard / evidence
|
|
6
|
+
* tooling consume. It carries AGGREGATE measurements + a digest only — never
|
|
7
|
+
* chunk/message content (EVAL-REDACT-002).
|
|
8
|
+
*
|
|
9
|
+
* Contract-first (ENGINEERING_PRACTICES §3): this types file is the reviewed
|
|
10
|
+
* gate; implementations import from it. Pi-agnostic, dependency-free
|
|
11
|
+
* (PREVENT-PI-004 / PREVENT-011).
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/bench.ts — ML5-B bench runner (consumer-facing shell).
|
|
3
|
+
*
|
|
4
|
+
* Calls `scripts/ml5/bench-onnx-prod.mjs` via child_process, parses the
|
|
5
|
+
* BenchResultV1 it emits, and writes the four `vector_cortex_encoder_bench_*`
|
|
6
|
+
* events to the monitoring events.log (the dashboard / ML5-D surface consume
|
|
7
|
+
* them later). This is NOT a runtime path — it is developer/evidence tooling.
|
|
8
|
+
*
|
|
9
|
+
* Events written (all best-effort / non-fatal):
|
|
10
|
+
* - vector_cortex_encoder_bench_p95_ms
|
|
11
|
+
* - vector_cortex_encoder_bench_rss_mib
|
|
12
|
+
* - vector_cortex_encoder_bench_opset_ok
|
|
13
|
+
* - vector_cortex_encoder_bench_deterministic
|
|
14
|
+
*
|
|
15
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 — the child bench is pure local
|
|
16
|
+
* computation). No `any` (PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
import { spawnSync } from "node:child_process";
|
|
19
|
+
import { dirname, join } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { getStateDir } from "../../store.js";
|
|
22
|
+
import { defaultEventsPath, logBenchEvent } from "../../monitoring.js";
|
|
23
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const REPO_ROOT = join(HERE, "..", "..", "..");
|
|
25
|
+
const BENCH_SCRIPT = join(REPO_ROOT, "scripts", "ml5", "bench-onnx-prod.mjs");
|
|
26
|
+
/** Default events.log beside the state dir (mirrors defaultEventsPath). */
|
|
27
|
+
function benchEventsPath(stateDir) {
|
|
28
|
+
return defaultEventsPath(stateDir);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Run the ONNX bench once and record its four events. Returns the parsed
|
|
32
|
+
* BenchResultV1. On any failure (script missing, non-zero exit, unparsable
|
|
33
|
+
* output) it returns a degraded result with gates.all:false — never throws, so
|
|
34
|
+
* the caller's agent loop is never broken (non-fatal store/write contract).
|
|
35
|
+
*/
|
|
36
|
+
export function runBench(stateDir = getStateDir()) {
|
|
37
|
+
const noop = (error) => ({
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
platform: `${process.platform}-${process.arch}`,
|
|
40
|
+
encoderNative: false,
|
|
41
|
+
threads: 4,
|
|
42
|
+
tokens: 512,
|
|
43
|
+
corpusTokens: 0,
|
|
44
|
+
p95Ms: null,
|
|
45
|
+
rssMib: null,
|
|
46
|
+
rssBaselineMib: null,
|
|
47
|
+
rssMarginalMib: null,
|
|
48
|
+
opset: null,
|
|
49
|
+
deterministic: false,
|
|
50
|
+
digest: null,
|
|
51
|
+
gates: { latency: false, rss: false, opset: false, determinism: false, all: false },
|
|
52
|
+
error,
|
|
53
|
+
});
|
|
54
|
+
const fallback = (error) => {
|
|
55
|
+
const r = noop(error);
|
|
56
|
+
emitEvents(stateDir, r);
|
|
57
|
+
return r;
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
const res = spawnSync(process.execPath, ["--expose-gc", BENCH_SCRIPT], {
|
|
61
|
+
cwd: REPO_ROOT,
|
|
62
|
+
encoding: "utf8",
|
|
63
|
+
timeout: 600_000,
|
|
64
|
+
});
|
|
65
|
+
const stdout = (res.stdout ?? "").trim();
|
|
66
|
+
if (res.status === null) {
|
|
67
|
+
return fallback("bench timed out or failed to spawn");
|
|
68
|
+
}
|
|
69
|
+
const parsed = JSON.parse(stdout || "");
|
|
70
|
+
if (!isBenchResultV1(parsed)) {
|
|
71
|
+
return fallback("bench output was not a BenchResultV1");
|
|
72
|
+
}
|
|
73
|
+
emitEvents(stateDir, parsed);
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
return fallback(`bench failed: ${e?.message ?? String(e)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function isBenchResultV1(v) {
|
|
81
|
+
if (typeof v !== "object" || v === null)
|
|
82
|
+
return false;
|
|
83
|
+
const o = v;
|
|
84
|
+
return (typeof o.timestamp === "number" &&
|
|
85
|
+
typeof o.platform === "string" &&
|
|
86
|
+
typeof o.encoderNative === "boolean" &&
|
|
87
|
+
typeof o.threads === "number" &&
|
|
88
|
+
typeof o.tokens === "number" &&
|
|
89
|
+
typeof o.corpusTokens === "number" &&
|
|
90
|
+
typeof o.gates === "object" && o.gates !== null &&
|
|
91
|
+
typeof o.gates.all === "boolean");
|
|
92
|
+
}
|
|
93
|
+
function emitEvents(stateDir, r) {
|
|
94
|
+
const path = benchEventsPath(stateDir);
|
|
95
|
+
const run = { platform: r.platform, encoderNative: r.encoderNative, threads: r.threads, tokens: r.tokens, digest: r.digest, corpusTokens: r.corpusTokens };
|
|
96
|
+
logBenchEvent(path, "vector_cortex_encoder_bench_p95_ms", { ...run, p95Ms: r.p95Ms, pass: r.gates.latency });
|
|
97
|
+
logBenchEvent(path, "vector_cortex_encoder_bench_rss_mib", { ...run, rssMib: r.rssMib, rssBaselineMib: r.rssBaselineMib, rssMarginalMib: r.rssMarginalMib, pass: r.gates.rss });
|
|
98
|
+
logBenchEvent(path, "vector_cortex_encoder_bench_opset_ok", { ...run, opset: r.opset, pass: r.gates.opset });
|
|
99
|
+
logBenchEvent(path, "vector_cortex_encoder_bench_deterministic", { ...run, deterministic: r.deterministic, pass: r.gates.determinism });
|
|
100
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/runtime-emit.ts — ML5-C seller event emitter.
|
|
3
|
+
*
|
|
4
|
+
* Emits the `vector_cortex_runtime_selected` seller event to the local
|
|
5
|
+
* events.log so the dashboard Setup Cortex blockers card can surface the HG-3
|
|
6
|
+
* (install budget) / HG-4 (darwin-x64 demotion) closure state. Aggregate
|
|
7
|
+
* fields only — never payload bytes (EVAL-REDACT-002).
|
|
8
|
+
*
|
|
9
|
+
* Extracted from runtime.ts so the runtime delegate-shell stays under the
|
|
10
|
+
* 300-line soft limit after the ML5-C dispatch was added. All writes are
|
|
11
|
+
* best-effort / non-fatal; a disk-full or missing state dir never breaks the
|
|
12
|
+
* encoder loop.
|
|
13
|
+
*
|
|
14
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 — local filesystem append only;
|
|
15
|
+
* no network). No `any` (PREVENT-011).
|
|
16
|
+
*/
|
|
17
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
18
|
+
import { dirname } from "node:path";
|
|
19
|
+
import { defaultEventsPath } from "../../monitoring.js";
|
|
20
|
+
/**
|
|
21
|
+
* Emit the ML5-C `vector_cortex_runtime_selected` seller event (best-effort).
|
|
22
|
+
* The event carries ONLY the four aggregate fields the sprint spec pins
|
|
23
|
+
* ({backend, p95Ms, budgetOk, platform}) — never message content.
|
|
24
|
+
*/
|
|
25
|
+
export function emitRuntimeSelected(stateDir, result) {
|
|
26
|
+
try {
|
|
27
|
+
const path = defaultEventsPath(stateDir);
|
|
28
|
+
const payload = {
|
|
29
|
+
ts: Date.now(),
|
|
30
|
+
event: "vector_cortex_runtime_selected",
|
|
31
|
+
backend: result.backend,
|
|
32
|
+
p95Ms: result.p95Ms,
|
|
33
|
+
budgetOk: result.budgetOk,
|
|
34
|
+
platform: result.platform,
|
|
35
|
+
};
|
|
36
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
37
|
+
appendFileSync(path, JSON.stringify(payload) + "\n", "utf8");
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
/* best-effort — never break the encoder loop */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/runtime-native.ts — ML5-C native backend (Option N).
|
|
3
|
+
*
|
|
4
|
+
* Loads an `InferenceSession` from the `onnxruntime-node` native binding for
|
|
5
|
+
* the committed encoder-v1 ONNX asset. This is the CHOSEN selection when
|
|
6
|
+
* `MEGACOMPACT_ENCODER_NATIVE=1` (the native opt-in marker) is set AND the
|
|
7
|
+
* package is present — it uses the platform-specific prebuilt binary (no
|
|
8
|
+
* postinstall compilation needed; per vc2-model-prep §1 the allowScripts
|
|
9
|
+
* removal is safe because only CUDA/TensorRT downloads use it, and pi blocks
|
|
10
|
+
* all scripts anyway).
|
|
11
|
+
*
|
|
12
|
+
* The package is NOT declared in package.json dependencies — it is a lazily-
|
|
13
|
+
* resolved peer that the runtime loads ONLY when the native opt-in is set AND
|
|
14
|
+
* selected. Loading uses dynamic `import()` so the module graph compiles
|
|
15
|
+
* cleanly on hosts without the package (absent installs return null, never
|
|
16
|
+
* throw), so the ML5-C dispatch demotes to mode B trigram rather than
|
|
17
|
+
* breaking.
|
|
18
|
+
*
|
|
19
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 — the native binary + model are
|
|
20
|
+
* committed local files). No `any` (PREVENT-011).
|
|
21
|
+
*/
|
|
22
|
+
import { ENCODER_OPSET, ENCODER_SEMANTIC_WIDTH, ENCODER_MAX_TOKENS, } from "./types.js";
|
|
23
|
+
/** True when `MEGACOMPACT_ENCODER_NATIVE=1` (the native opt-in operator flag). */
|
|
24
|
+
export function nativeOptIn() {
|
|
25
|
+
return process.env.MEGACOMPACT_ENCODER_NATIVE === "1";
|
|
26
|
+
}
|
|
27
|
+
/** True if `onnxruntime-node` resolves on this host (loading is best-effort).
|
|
28
|
+
* Absent installs return null (never throw) so the ML5-C dispatch can demote
|
|
29
|
+
* to mode B trigram cleanly. */
|
|
30
|
+
async function loadOrtNative() {
|
|
31
|
+
try {
|
|
32
|
+
// @ts-expect-error — optional peer; the shadow type above covers the surface
|
|
33
|
+
const mod = (await import("onnxruntime-node"));
|
|
34
|
+
return mod;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a native-backed `NativeSession` over the committed ONNX asset, gated
|
|
42
|
+
* first on `nativeOptIn()`. Returns null (never throws) on any failure
|
|
43
|
+
* (opt-in off, absent package, unreadable asset, bad session creation) so the
|
|
44
|
+
* caller demotes to mode B trigram.
|
|
45
|
+
*/
|
|
46
|
+
export async function createNativeSession(modelPath, options = {}) {
|
|
47
|
+
if (!nativeOptIn())
|
|
48
|
+
return null;
|
|
49
|
+
const ort = await loadOrtNative();
|
|
50
|
+
if (!ort || !ort.InferenceSession?.create)
|
|
51
|
+
return null;
|
|
52
|
+
const threads = options.threads ?? 4;
|
|
53
|
+
const maxTokens = options.maxTokens ?? ENCODER_MAX_TOKENS;
|
|
54
|
+
try {
|
|
55
|
+
const session = await ort.InferenceSession.create(modelPath, {
|
|
56
|
+
executionProviders: ["cpu"],
|
|
57
|
+
intraOpNumThreads: threads,
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
opset: ENCODER_OPSET,
|
|
61
|
+
semanticWidth: ENCODER_SEMANTIC_WIDTH,
|
|
62
|
+
maxTokens,
|
|
63
|
+
async infer(inputIds) {
|
|
64
|
+
const feeds = { input_ids: inputIds };
|
|
65
|
+
const results = await session.run(feeds, ["embedding"]);
|
|
66
|
+
const out = results["embedding"];
|
|
67
|
+
if (!out || !(out.data instanceof Float32Array)) {
|
|
68
|
+
return new Float32Array(ENCODER_SEMANTIC_WIDTH);
|
|
69
|
+
}
|
|
70
|
+
return out.data;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|