pi-mega-compact 0.17.0 → 0.18.0
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.js +20 -0
- package/dist/dedup/digest.js +30 -0
- package/dist/dedup/l1-lsh-v2.js +60 -0
- package/dist/dedup/l1-lsh.js +52 -0
- package/dist/dedup/l1-minhash-v2.js +193 -0
- package/dist/dedup/l1-minhash.js +91 -0
- package/dist/dedup/l1-verify.js +54 -0
- package/dist/dedup/mmr.js +45 -0
- package/dist/dedup/normalize.js +39 -0
- package/dist/dedup/raptor/buildHistory.js +164 -0
- package/dist/dedup/raptor/guardrails.js +83 -0
- package/dist/dedup/raptor/incremental.js +304 -0
- package/dist/dedup/raptor/index.js +190 -0
- package/dist/dedup/raptor/kmeans.js +152 -0
- package/dist/dedup/raptor/multilevel.js +184 -0
- package/dist/dedup/raptor/retrieval.js +93 -0
- package/dist/dedup/raptor/summarizer.js +86 -0
- package/dist/dedup/raptor/tree.js +202 -0
- package/dist/dedup/topk.js +60 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +2 -0
- package/dist/extensions/mega-events/context-handler/dbMirrorAppend.js +63 -0
- package/dist/extensions/mega-events/context-handler/gateCheck.js +59 -0
- package/dist/extensions/mega-events/context-handler/liveTrim.js +178 -0
- package/dist/extensions/mega-events/context-handler/pipelineRun.js +37 -0
- package/dist/extensions/mega-events/context-handler.js +39 -305
- package/dist/src/config/vector-cortex.js +20 -0
- package/dist/src/config.js +1 -1
- package/dist/src/dedup/l1-lsh-v2.js +60 -0
- package/dist/src/dedup/l1-minhash-v2.js +193 -0
- package/dist/src/dedup/normalize.js +1 -1
- package/dist/src/vector-cortex/conformance/emit.js +46 -0
- package/dist/src/vector-cortex/conformance/manifest.js +235 -0
- package/dist/src/vector-cortex/conformance/runner.js +111 -0
- package/dist/src/vector-cortex/conformance/triadB-reader.js +95 -0
- package/dist/src/vector-cortex/encoder/asset.js +142 -0
- package/dist/src/vector-cortex/encoder/emit.js +42 -0
- package/dist/src/vector-cortex/encoder/runtime.js +228 -0
- package/dist/src/vector-cortex/encoder/types.js +85 -0
- package/dist/src/vector-cortex/migrations/minhash-v2.js +209 -0
- package/dist/vector-cortex/conformance/emit.js +46 -0
- package/dist/vector-cortex/conformance/manifest.js +235 -0
- package/dist/vector-cortex/conformance/runner.js +111 -0
- package/dist/vector-cortex/conformance/triadB-reader.js +95 -0
- package/dist/vector-cortex/encoder/asset.js +142 -0
- package/dist/vector-cortex/encoder/emit.js +42 -0
- package/dist/vector-cortex/encoder/runtime.js +228 -0
- package/dist/vector-cortex/encoder/types.js +85 -0
- package/dist/vector-cortex/migrations/minhash-v2.js +209 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-CAnWomhw.js → AreaChart-BQXFF7UI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-CAnWomhw.js.map → AreaChart-BQXFF7UI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-lZ2-s71k.js → BarChart-BVtoz9Eg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-lZ2-s71k.js.map → BarChart-BVtoz9Eg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-BL2Thh66.js → CacheTab-trI2TIGy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BL2Thh66.js.map → CacheTab-trI2TIGy.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DEh2Z9fp.js → EventsTab-CNUbk9__.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DEh2Z9fp.js.map → EventsTab-CNUbk9__.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-DTwKclxk.js → HealthTab-K-bd_CM-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-DTwKclxk.js.map → HealthTab-K-bd_CM-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DDfBEdbX.js → MaintenanceTab-CoEioKzx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DDfBEdbX.js.map → MaintenanceTab-CoEioKzx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dgfmg-0Q.js → MemoryMapTab-CJo24ulv.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dgfmg-0Q.js.map → MemoryMapTab-CJo24ulv.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DOcMm0Tx.js → MetricsTab-DCNlQWWP.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DOcMm0Tx.js.map → MetricsTab-DCNlQWWP.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DHT5aoHg.js → OverviewTab-CQQlyIQ6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DHT5aoHg.js.map → OverviewTab-CQQlyIQ6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-CGAmtR_c.js → ReposTab-Cqm82_yn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-CGAmtR_c.js.map → ReposTab-Cqm82_yn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BIgx6iKT.js → SessionsTab-A8xTAdET.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BIgx6iKT.js.map → SessionsTab-A8xTAdET.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-ADghKuEI.js → SetupTab-CqaSgaZl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-ADghKuEI.js.map → SetupTab-CqaSgaZl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-C33UiiOM.js → TimeSavedCard-C_f3q8GR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-C33UiiOM.js.map → TimeSavedCard-C_f3q8GR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DdbL9wPN.js → TurnsTab-BEsafACo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DdbL9wPN.js.map → TurnsTab-BEsafACo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-Ch00OFKs.js → WikiTab-Bf01M2_Z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-Ch00OFKs.js.map → WikiTab-Bf01M2_Z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-ByeEdo2g.js → button-BEJPTk_E.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-ByeEdo2g.js.map → button-BEJPTk_E.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-DesoLXvc.js → card-DK1V382s.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-DesoLXvc.js.map → card-DK1V382s.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CCAB7Iz4.js → generateCategoricalChart-CRtaPphL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CCAB7Iz4.js.map → generateCategoricalChart-CRtaPphL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-B6cgyAPr.js → index-CB6BslE4.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-B6cgyAPr.js.map → index-CB6BslE4.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-DIZC-oe-.js → switch-C4FV6B9k.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-DIZC-oe-.js.map → switch-C4FV6B9k.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-CIoWaH2e.js → toggle-GBmeENMd.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-CIoWaH2e.js.map → toggle-GBmeENMd.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-Bv4943l1.js → useSSE-BOKZGSn1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-Bv4943l1.js.map → useSSE-BOKZGSn1.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +1 -1
- package/extensions/dashboard-client/tsconfig.json +1 -1
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +12 -0
- package/extensions/mega-events/context-handler/dbMirrorAppend.ts +93 -0
- package/extensions/mega-events/context-handler/gateCheck.ts +101 -0
- package/extensions/mega-events/context-handler/liveTrim.ts +241 -0
- package/extensions/mega-events/context-handler/pipelineRun.ts +79 -0
- package/extensions/mega-events/context-handler.ts +45 -347
- package/package.json +1 -1
- package/src/config/vector-cortex.ts +22 -0
- package/src/config.ts +2 -0
- package/src/dedup/l1-lsh-v2.ts +78 -0
- package/src/dedup/l1-minhash-v2.ts +221 -0
- package/src/dedup/normalize.ts +1 -1
- package/src/store/sqlite/game-scores.ts +2 -1
- package/src/vector-cortex/conformance/emit.ts +56 -0
- package/src/vector-cortex/conformance/manifest.ts +298 -0
- package/src/vector-cortex/conformance/runner.ts +165 -0
- package/src/vector-cortex/conformance/triadB-reader.ts +110 -0
- package/src/vector-cortex/encoder/asset.ts +155 -0
- package/src/vector-cortex/encoder/emit.ts +51 -0
- package/src/vector-cortex/encoder/runtime.ts +283 -0
- package/src/vector-cortex/encoder/types.ts +165 -0
- package/src/vector-cortex/migrations/minhash-v2.ts +263 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Cl1pbEdR.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Cl1pbEdR.js.map +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* conformance/triadB-reader.ts — TRIAD-B independent exact reader (VC1C).
|
|
3
|
+
*
|
|
4
|
+
* Deliberately shares NO code and NO cached-seed instance with the runner
|
|
5
|
+
* modules (l1-minhash-v2.ts / l1-lsh-v2.ts). It re-derives the minhash-v2
|
|
6
|
+
* signature and 64 bucket keys from first principles, using only the PUBLISHED
|
|
7
|
+
* (a,b) seed pairs passed in (read by the caller from
|
|
8
|
+
* conformance/.../minhash/seeds-v2.json — the table authored independently by
|
|
9
|
+
* scripts/gen-fixtures/minhash.mjs, the same process that produced the frozen
|
|
10
|
+
* fixture bytes). Because B shares no subroutine with the runner, a systematic
|
|
11
|
+
* error in the runner's splitmix64 / seed-derivation / signature arithmetic
|
|
12
|
+
* cannot satisfy both triad A and triad B.
|
|
13
|
+
*
|
|
14
|
+
* Pure compute, no deps, no storage, no network (PREVENT-PI-004 / PREVENT-011).
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
const MASK64 = 0xffffffffffffffffn;
|
|
18
|
+
const P = (1n << 61n) - 1n; // 2^61 - 1
|
|
19
|
+
const SLOTS = 256;
|
|
20
|
+
const U64 = 8;
|
|
21
|
+
const BANDS = 64;
|
|
22
|
+
/** 64-bit FNV-1a over UTF-8 bytes or a raw byte buffer (own, independent loop). */
|
|
23
|
+
function fnv1a64(input) {
|
|
24
|
+
let h = 0xcbf29ce484222325n;
|
|
25
|
+
for (const b of Buffer.from(input)) {
|
|
26
|
+
h = ((h ^ BigInt(b)) * 0x100000001b3n) & MASK64;
|
|
27
|
+
}
|
|
28
|
+
return h;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Re-derive the 2048-byte minhash-v2 signature and (optionally) the 64 LSH
|
|
32
|
+
* bucket keys for `text` within `session`, from published seed pairs only —
|
|
33
|
+
* never the runner module.
|
|
34
|
+
*/
|
|
35
|
+
export function independentReaderV2(text, session, seedPairs, withBuckets) {
|
|
36
|
+
// Normalization: ANSI-strip, NFC, case-fold, CRLF->LF, whitespace collapse,
|
|
37
|
+
// 32K cap — mirrored from the frozen VC1C spec.
|
|
38
|
+
let norm = (text || "")
|
|
39
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
|
|
40
|
+
.normalize("NFC")
|
|
41
|
+
.toLowerCase()
|
|
42
|
+
.replace(/\r\n?/g, "\n")
|
|
43
|
+
.replace(/\s+/g, " ")
|
|
44
|
+
.trim();
|
|
45
|
+
if (norm.length > 32768)
|
|
46
|
+
norm = norm.slice(0, 32768);
|
|
47
|
+
// Five-code-point shingles (deduped, capped at 50_000).
|
|
48
|
+
const grams = [];
|
|
49
|
+
if (norm.length > 0) {
|
|
50
|
+
const cps = Array.from(norm);
|
|
51
|
+
const seen = new Set();
|
|
52
|
+
const short = cps.length < 5;
|
|
53
|
+
for (let i = 0; i < (short ? 1 : cps.length - 4); i++) {
|
|
54
|
+
const h = short ? fnv1a64(norm) : fnv1a64(cps.slice(i, i + 5).join(""));
|
|
55
|
+
if (!seen.has(h)) {
|
|
56
|
+
seen.add(h);
|
|
57
|
+
grams.push(h);
|
|
58
|
+
}
|
|
59
|
+
if (!short && seen.size >= 50000)
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Signature: slot i = min over shingles of (a_i*x + b_i) mod p (exact BigInt).
|
|
64
|
+
const sig = new Array(SLOTS).fill(P);
|
|
65
|
+
for (let i = 0; i < SLOTS && grams.length > 0; i++) {
|
|
66
|
+
const pair = seedPairs[i];
|
|
67
|
+
const a = BigInt(pair.a);
|
|
68
|
+
const b = BigInt(pair.b);
|
|
69
|
+
let min = P;
|
|
70
|
+
for (const x of grams) {
|
|
71
|
+
const h = (a * x + b) % P;
|
|
72
|
+
if (h < min)
|
|
73
|
+
min = h;
|
|
74
|
+
}
|
|
75
|
+
sig[i] = min;
|
|
76
|
+
}
|
|
77
|
+
// Own 256 x u64 little-endian encoder.
|
|
78
|
+
const buf = Buffer.allocUnsafe(SLOTS * U64);
|
|
79
|
+
for (let i = 0; i < SLOTS; i++)
|
|
80
|
+
buf.writeBigUInt64LE(sig[i], i * U64);
|
|
81
|
+
const bytes = new Uint8Array(buf);
|
|
82
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
83
|
+
// 64 buckets: FNV-1a over `<session>|v2|` + each 32-byte band (LE hex).
|
|
84
|
+
const buckets = [];
|
|
85
|
+
if (withBuckets) {
|
|
86
|
+
const prefix = Buffer.from(`${session}|v2|`, "utf8");
|
|
87
|
+
for (let band = 0; band < BANDS; band++) {
|
|
88
|
+
const bandBytes = Buffer.from(bytes.slice(band * 32, band * 32 + 32));
|
|
89
|
+
const out = Buffer.allocUnsafe(U64);
|
|
90
|
+
out.writeBigUInt64LE(fnv1a64(Buffer.concat([prefix, bandBytes])), 0);
|
|
91
|
+
buckets.push(`b${band}:${out.toString("hex")}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { bytes, digest, buckets };
|
|
95
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/asset.ts — VC2A asset verification (task 2).
|
|
3
|
+
*
|
|
4
|
+
* Verifies a ModelManifestV1 before any allocation: SHA-256 the ONNX and
|
|
5
|
+
* tokenizer against the manifest digests, require opset 17, batch exactly 1 and
|
|
6
|
+
* maximum 512 tokens, and confirm the current platform is in the supported
|
|
7
|
+
* matrix. On ANY of these the caller demotes to mode B (asset-free trigram) —
|
|
8
|
+
* never a remote fetch (PREVENT-PI-004). A truncated/unreadable asset during
|
|
9
|
+
* the digest read demotes with ENC_ASSET_UNREADABLE.
|
|
10
|
+
*
|
|
11
|
+
* Pi-agnostic. Filesystem reads only, zero network (PREVENT-PI-004).
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { readFileSync, statSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { ENC_FAIL, ENCODER_BATCH, ENCODER_MAX_TOKENS, ENCODER_OPSET, ENCODER_SUPPORTED_PLATFORMS, } from "./types.js";
|
|
17
|
+
/** True when `p` is a single basename: non-empty, no path separators, no "..",
|
|
18
|
+
* no leading dot-segment traversal. Keeps manifest-controlled asset paths
|
|
19
|
+
* confined to the asset directory (no path-traversal via join()). */
|
|
20
|
+
function isBasename(p) {
|
|
21
|
+
if (!p || p.length === 0 || p.includes("/") || p.includes("\\"))
|
|
22
|
+
return false;
|
|
23
|
+
if (p === "." || p === "..")
|
|
24
|
+
return false;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
/** Digest the on-disk bytes of one asset file; "" on unreadable (truncated). */
|
|
28
|
+
function digestFile(path) {
|
|
29
|
+
try {
|
|
30
|
+
const buf = readFileSync(path);
|
|
31
|
+
return createHash("sha256").update(buf).digest("hex");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Truncated / unreadable during the digest read -> ENC_ASSET_UNREADABLE.
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Detect the current platform (MODEL_ASSET supported matrix). Unrecognized
|
|
40
|
+
* hosts return null so verification demotes to mode B (unsupported platform).
|
|
41
|
+
*/
|
|
42
|
+
export function detectPlatform(host = process.platform, arch = process.arch) {
|
|
43
|
+
if (!host || !arch)
|
|
44
|
+
return null;
|
|
45
|
+
// Normalize "win32"/"win32"/"linux"/"darwin" + "x64"/"arm64".
|
|
46
|
+
const plat = host === "win32" ? "win32" : host === "darwin" ? "darwin" : host === "linux" ? "linux" : "";
|
|
47
|
+
const a = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : "";
|
|
48
|
+
if (!plat || !a)
|
|
49
|
+
return null;
|
|
50
|
+
const candidate = `${plat}-${a}`;
|
|
51
|
+
return ENCODER_SUPPORTED_PLATFORMS.includes(candidate)
|
|
52
|
+
? candidate
|
|
53
|
+
: null;
|
|
54
|
+
}
|
|
55
|
+
function isManifest(m) {
|
|
56
|
+
const o = m;
|
|
57
|
+
return (!!o &&
|
|
58
|
+
typeof o === "object" &&
|
|
59
|
+
o.schema === "model-manifest-v1" &&
|
|
60
|
+
typeof o.opset === "number" &&
|
|
61
|
+
typeof o.batch === "number" &&
|
|
62
|
+
typeof o.maxTokens === "number" &&
|
|
63
|
+
typeof o.platform === "string" &&
|
|
64
|
+
!!o.onnx &&
|
|
65
|
+
!!o.tokenizer &&
|
|
66
|
+
typeof o.onnx.path === "string" &&
|
|
67
|
+
typeof o.onnx.sha256 === "string" &&
|
|
68
|
+
typeof o.tokenizer.path === "string" &&
|
|
69
|
+
typeof o.tokenizer.sha256 === "string");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Verify the asset manifest + digest + constraints BEFORE allocation.
|
|
73
|
+
*
|
|
74
|
+
* - manifest parse/shape failure -> ENC_MANIFEST_INVALID -> mode B
|
|
75
|
+
* - unsupported platform -> ENC_PLATFORM_UNSUPPORTED -> mode B
|
|
76
|
+
* - opset != 17 -> ENC_OPSET_INVALID -> mode B
|
|
77
|
+
* - batch != 1 -> ENC_BATCH_INVALID -> mode B
|
|
78
|
+
* - maxTokens > 512 -> ENC_TOKENS_EXCEEDED -> mode B
|
|
79
|
+
* - on-disk digest != manifest digest -> ENC_DIGEST_MISMATCH (one-byte mutation)
|
|
80
|
+
* - unreadable/truncated file -> ENC_ASSET_UNREADABLE
|
|
81
|
+
*
|
|
82
|
+
* Returns ok only when EVERY constraint passes and both files hash to the
|
|
83
|
+
* declared digests (the "only batch1/max512 verified assets reach inference"
|
|
84
|
+
* invariant). The ok result surfaces the verified manifest's `maxTokens`
|
|
85
|
+
* (<= 512) so the runtime can enforce the per-manifest token capacity at
|
|
86
|
+
* inference (Q03), not just the global 512 ceiling.
|
|
87
|
+
*/
|
|
88
|
+
export function verifyEncoderAsset(assetDir, manifest, platform = detectPlatform()) {
|
|
89
|
+
if (typeof manifest !== "object" || manifest === null || !isManifest(manifest)) {
|
|
90
|
+
return { ok: false, code: ENC_FAIL.MANIFEST_INVALID };
|
|
91
|
+
}
|
|
92
|
+
if (!platform)
|
|
93
|
+
return { ok: false, code: ENC_FAIL.PLATFORM_UNSUPPORTED };
|
|
94
|
+
// The manifest's declared platform must match the runtime host (per-platform
|
|
95
|
+
// asset pinning): a bundle cross-shipped to the wrong arch is not qualified.
|
|
96
|
+
if (manifest.platform !== platform)
|
|
97
|
+
return { ok: false, code: ENC_FAIL.PLATFORM_UNSUPPORTED };
|
|
98
|
+
if (manifest.opset !== ENCODER_OPSET)
|
|
99
|
+
return { ok: false, code: ENC_FAIL.OPSET_INVALID };
|
|
100
|
+
if (manifest.batch !== ENCODER_BATCH)
|
|
101
|
+
return { ok: false, code: ENC_FAIL.BATCH_INVALID };
|
|
102
|
+
if (manifest.maxTokens > ENCODER_MAX_TOKENS)
|
|
103
|
+
return { ok: false, code: ENC_FAIL.TOKENS_EXCEEDED };
|
|
104
|
+
// Constrain asset paths to basenames (no separators / no '..') so a forged
|
|
105
|
+
// manifest cannot read digests from arbitrary paths off the asset dir.
|
|
106
|
+
if (!isBasename(manifest.onnx.path) || !isBasename(manifest.tokenizer.path)) {
|
|
107
|
+
return { ok: false, code: ENC_FAIL.MANIFEST_INVALID };
|
|
108
|
+
}
|
|
109
|
+
const onnxPath = join(assetDir, manifest.onnx.path);
|
|
110
|
+
const onnxDigest = digestFile(onnxPath);
|
|
111
|
+
if (onnxDigest === null)
|
|
112
|
+
return { ok: false, code: ENC_FAIL.ASSET_UNREADABLE };
|
|
113
|
+
if (onnxDigest !== manifest.onnx.sha256)
|
|
114
|
+
return { ok: false, code: ENC_FAIL.DIGEST_MISMATCH };
|
|
115
|
+
const tokPath = join(assetDir, manifest.tokenizer.path);
|
|
116
|
+
const tokDigest = digestFile(tokPath);
|
|
117
|
+
if (tokDigest === null)
|
|
118
|
+
return { ok: false, code: ENC_FAIL.ASSET_UNREADABLE };
|
|
119
|
+
if (tokDigest !== manifest.tokenizer.sha256)
|
|
120
|
+
return { ok: false, code: ENC_FAIL.DIGEST_MISMATCH };
|
|
121
|
+
let embeddedBytes = 0;
|
|
122
|
+
try {
|
|
123
|
+
embeddedBytes = statSync(onnxPath).size + statSync(tokPath).size;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return { ok: false, code: ENC_FAIL.ASSET_UNREADABLE };
|
|
127
|
+
}
|
|
128
|
+
return { ok: true, embeddedBytes, maxTokens: manifest.maxTokens, onnxDigest, tokenizerDigest: tokDigest };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Read + shape-check a committed ModelManifestV1 from an asset directory.
|
|
132
|
+
* Returns the parsed manifest or null when the file is absent/malformed.
|
|
133
|
+
*/
|
|
134
|
+
export function readEncoderManifest(assetDir) {
|
|
135
|
+
try {
|
|
136
|
+
const raw = JSON.parse(readFileSync(join(assetDir, "manifest.json"), "utf8"));
|
|
137
|
+
return isManifest(raw) ? raw : null;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/emit.ts — VC2A observability seam.
|
|
3
|
+
*
|
|
4
|
+
* Emits the two VC2A structured events, gated on `MEGACOMPACT_VC2A` (mode C
|
|
5
|
+
* parity: flag OFF => zero emissions). Every event is a JSON line with `ts` +
|
|
6
|
+
* `event` (ENGINEERING_PRACTICES §8); the emitters are never fatal on consumer
|
|
7
|
+
* failure (non-fatal observability, never breaks the agent loop).
|
|
8
|
+
*
|
|
9
|
+
* vector_cortex_encoder_asset_verified — a qualified manifest+digest load
|
|
10
|
+
* vector_cortex_encoder_runtime_demoted — a demotion to mode B or C
|
|
11
|
+
*
|
|
12
|
+
* No network, no side effects beyond the supplied emit callback
|
|
13
|
+
* (PREVENT-PI-004 / PREVENT-011).
|
|
14
|
+
*/
|
|
15
|
+
import { VC2A_ENABLED } from "../../config/vector-cortex.js";
|
|
16
|
+
/** A flag-gated no-op reporter (zero emissions, default when none injected). */
|
|
17
|
+
export const NOOP_ENCODER_REPORTER = {
|
|
18
|
+
assetVerified: () => { },
|
|
19
|
+
runtimeDemoted: () => { },
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Flag-gated emit: no-op when VC2A is off or no emitter is supplied. The
|
|
23
|
+
* returned reporter is itself flag-gated (`VC2A_ENABLED`), so wiring it into a
|
|
24
|
+
* runtime seam yields zero emissions when `MEGACOMPACT_VC2A=0` (byte-identical
|
|
25
|
+
* to the predecessor).
|
|
26
|
+
*/
|
|
27
|
+
export function createEncoderReporter(emit) {
|
|
28
|
+
const fire = (event, fields) => {
|
|
29
|
+
if (!VC2A_ENABLED())
|
|
30
|
+
return;
|
|
31
|
+
try {
|
|
32
|
+
emit?.(event, { ...fields, ts: new Date().toISOString() });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* non-fatal observability */
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
assetVerified: (fields) => fire("vector_cortex_encoder_asset_verified", fields),
|
|
40
|
+
runtimeDemoted: (fields) => fire("vector_cortex_encoder_runtime_demoted", fields),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/runtime.ts — VC2A EncoderRuntime (task 3).
|
|
3
|
+
*
|
|
4
|
+
* Allocates (prepares an inference session) ONLY after manifest verification;
|
|
5
|
+
* rejects any non (batch 1, tokens <= maxTokens, <=512) input with
|
|
6
|
+
* ENC_SHAPE_INVALID; caps the encoder's MARGINAL footprint at 150 MiB
|
|
7
|
+
* (ENC_RSS_BUDGET_EXCEEDED -> mode B); and yields a deterministic mode-A
|
|
8
|
+
* inference over the verified asset (the trained weights are substituted in
|
|
9
|
+
* VC2C — the contract, shape gating and budgets all land here).
|
|
10
|
+
*
|
|
11
|
+
* MEMORY BUDGET (Q01/Q02): the 150 MiB cap measures the encoder's INCREMENTAL
|
|
12
|
+
* footprint — an in-process allocation counter (`selfAllocated`) plus any
|
|
13
|
+
* externally staged asset working set (`host.allocatedBytes()`) — NOT the
|
|
14
|
+
* whole-process RSS. In a live pi extension the process baseline (node:sqlite
|
|
15
|
+
* DatabaseSync + dashboard + loaded context) routinely exceeds 150 MiB, so an
|
|
16
|
+
* absolute-RSS cap would permanently demote a qualified asset to mode B and
|
|
17
|
+
* make mode A unreachable in production. Bounding the marginal footprint keeps
|
|
18
|
+
* mode A reachable while still enforcing the budget. `selfAllocated` models a
|
|
19
|
+
* single REUSABLE 384-float projection buffer (first inference allocates it,
|
|
20
|
+
* every later inference reuses it), so it is capped at `SEMANTIC_BUFFER_BYTES`
|
|
21
|
+
* — the marginal footprint can never grow without bound (Q01), and a long-lived
|
|
22
|
+
* runtime cannot drift over budget from healthy operation. The check runs
|
|
23
|
+
* BEFORE the allocation on both the load and the inference path
|
|
24
|
+
* (cap-before-allocation, task 3), and an over-budget inference demotes the
|
|
25
|
+
* runtime to mode B just as an over-budget load does (consistent demotion per
|
|
26
|
+
* ENC_FAIL.RSS_BUDGET_EXCEEDED).
|
|
27
|
+
*
|
|
28
|
+
* TOKEN CAPACITY (Q03): the per-manifest `maxTokens` (<= 512) is stored at load
|
|
29
|
+
* and enforced at inference — an input longer than the verified manifest's
|
|
30
|
+
* declared capacity is rejected with ENC_SHAPE_INVALID, honoring the model
|
|
31
|
+
* contract rather than a global 512 ceiling.
|
|
32
|
+
*
|
|
33
|
+
* FLAG GATING (Q04): the default factory consults `MEGACOMPACT_VC2A`; when the
|
|
34
|
+
* flag is OFF the runtime is fixed at mode C (rollback, byte-identical to the
|
|
35
|
+
* predecessor — no asset is read or verified). `forcedMode: "C"` is the
|
|
36
|
+
* explicit override for the same rollback path.
|
|
37
|
+
*
|
|
38
|
+
* Triad: A = qualified local ONNX (verified); B = asset-free trigram (forced by
|
|
39
|
+
* a missing/unsupported/digest-bad asset, no remote fetch); C = lexical forced
|
|
40
|
+
* when A verification fails AND B initialization itself fails. Demotions always
|
|
41
|
+
* select B/C locally and never attempt a network fetch (PREVENT-PI-004).
|
|
42
|
+
*
|
|
43
|
+
* Pi-agnostic. No `any` (PREVENT-011). Emits the two VC2A events via the
|
|
44
|
+
* reporter (non-fatal).
|
|
45
|
+
*/
|
|
46
|
+
import { detectPlatform, readEncoderManifest, verifyEncoderAsset, } from "./asset.js";
|
|
47
|
+
import { createEncoderReporter } from "./emit.js";
|
|
48
|
+
import { VC2A_ENABLED } from "../../config/vector-cortex.js";
|
|
49
|
+
import { ENC_FAIL, ENCODER_MAX_TOKENS, ENCODER_RSS_BUDGET_BYTES, ENCODER_SEMANTIC_WIDTH, } from "./types.js";
|
|
50
|
+
/** Bytes a single encoder-owned projection buffer commits to the marginal
|
|
51
|
+
* footprint (Float32Array, 4 bytes per element). */
|
|
52
|
+
const SEMANTIC_BUFFER_BYTES = ENCODER_SEMANTIC_WIDTH * 4;
|
|
53
|
+
const DEFAULT_HOST = {
|
|
54
|
+
allocatedBytes: () => 0,
|
|
55
|
+
allocatorFails: () => false,
|
|
56
|
+
nowMs: () => Date.now(),
|
|
57
|
+
};
|
|
58
|
+
function mergeHost(partial) {
|
|
59
|
+
return { ...DEFAULT_HOST, ...partial };
|
|
60
|
+
}
|
|
61
|
+
/** A deterministic seeded projection so the mode-A inference path is testable
|
|
62
|
+
* end-to-end without onnxruntime (real weights + execution are VC2C). */
|
|
63
|
+
function projectSemantic(seed, n) {
|
|
64
|
+
const out = new Float32Array(n);
|
|
65
|
+
let state = (seed >>> 0) ^ 0x9e3779b9;
|
|
66
|
+
let sum = 0;
|
|
67
|
+
for (let i = 0; i < n; i++) {
|
|
68
|
+
state = (state * 1664525 + 1013904223) >>> 0;
|
|
69
|
+
out[i] = (state / 4294967296) * 2 - 1;
|
|
70
|
+
sum += out[i] * out[i];
|
|
71
|
+
}
|
|
72
|
+
const norm = Math.sqrt(sum) || 1;
|
|
73
|
+
for (let i = 0; i < n; i++)
|
|
74
|
+
out[i] = out[i] / norm;
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/** Deterministic token seed derived from the verified asset bytes count. */
|
|
78
|
+
function seedFromBytes(embeddedBytes) {
|
|
79
|
+
return (embeddedBytes * 2654435761) >>> 0;
|
|
80
|
+
}
|
|
81
|
+
function modeLabel(mode) {
|
|
82
|
+
return mode === "A" ? "qualified-onnx" : mode === "B" ? "trigram" : "lexical";
|
|
83
|
+
}
|
|
84
|
+
export function createEncoderRuntime(options = {}) {
|
|
85
|
+
const reporter = options.reporter ?? createEncoderReporter();
|
|
86
|
+
const host = mergeHost(options.host);
|
|
87
|
+
const forced = options.forcedMode;
|
|
88
|
+
const plat = options.platform ?? detectPlatform;
|
|
89
|
+
// Q04: rollback contract — MEGACOMPACT_VC2A=0 selects mode C (byte-identical
|
|
90
|
+
// to the predecessor: no asset read/verify, no learned infer). An explicit
|
|
91
|
+
// forcedMode "C" takes precedence; otherwise the flag gates the default.
|
|
92
|
+
const rolledBack = forced === "C" || !VC2A_ENABLED();
|
|
93
|
+
let mode = rolledBack ? "C" : "C";
|
|
94
|
+
let embeddedBytes = 0;
|
|
95
|
+
let verified = false;
|
|
96
|
+
/** Per-manifest token capacity (<= 512) from the verified asset; enforced at
|
|
97
|
+
* inference (Q03). Defaults to the global ceiling before a load. */
|
|
98
|
+
let maxTokens = ENCODER_MAX_TOKENS;
|
|
99
|
+
/** Bytes this runtime itself has allocated. This models a SINGLE reusable
|
|
100
|
+
* 384-float projection buffer: the first inference allocates it (1536
|
|
101
|
+
* bytes), every later inference reuses it, so the counter is capped at
|
|
102
|
+
* `SEMANTIC_BUFFER_BYTES` and never grows without bound (Q01). Combined
|
|
103
|
+
* with `host.allocatedBytes()` it drives the 150 MiB marginal budget (Q02),
|
|
104
|
+
* never whole-process RSS. */
|
|
105
|
+
let selfAllocated = 0;
|
|
106
|
+
/** The encoder's marginal working-set footprint, in bytes. */
|
|
107
|
+
const footprint = () => selfAllocated + host.allocatedBytes();
|
|
108
|
+
const demoteTo = (rmode, code) => {
|
|
109
|
+
mode = rmode;
|
|
110
|
+
verified = false;
|
|
111
|
+
reporter.runtimeDemoted({ reason: code, mode: rmode, platform: plat()?.toString() ?? "unsupported" });
|
|
112
|
+
};
|
|
113
|
+
const runtime = {
|
|
114
|
+
schema: "encoder-runtime-v1",
|
|
115
|
+
// Live getter so `mode` always reflects the latest load/demote outcome
|
|
116
|
+
// (a plain property would freeze at its construction-time value forever).
|
|
117
|
+
get mode() {
|
|
118
|
+
return mode;
|
|
119
|
+
},
|
|
120
|
+
load(assetDir) {
|
|
121
|
+
if (rolledBack) {
|
|
122
|
+
// Rollback path (forcedMode "C" or MEGACOMPACT_VC2A=0): mode C restores
|
|
123
|
+
// the prior derived pointer; no asset is read or verified; no emission.
|
|
124
|
+
// Q04: report the rollback with its own code, not MANIFEST_INVALID, so a
|
|
125
|
+
// correctly-shaped, digest-correct asset is not mis-read as corrupted.
|
|
126
|
+
mode = "C";
|
|
127
|
+
verified = false;
|
|
128
|
+
return { ok: false, mode: "C", code: ENC_FAIL.ROLLBACK };
|
|
129
|
+
}
|
|
130
|
+
// Attempt A: verify the local qualified ONNX asset (never a remote fetch).
|
|
131
|
+
const manifest = readEncoderManifest(assetDir);
|
|
132
|
+
let verify;
|
|
133
|
+
if (manifest === null) {
|
|
134
|
+
verify = { ok: false, code: ENC_FAIL.MANIFEST_INVALID };
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
verify = verifyEncoderAsset(assetDir, manifest, plat());
|
|
138
|
+
}
|
|
139
|
+
if (!verify.ok) {
|
|
140
|
+
// A failed -> B, unless B init itself fails (allocator) -> C.
|
|
141
|
+
if (host.allocatorFails()) {
|
|
142
|
+
demoteTo("C", ENC_FAIL.ASSET_UNREADABLE);
|
|
143
|
+
return { ok: false, mode: "C", code: ENC_FAIL.ASSET_UNREADABLE };
|
|
144
|
+
}
|
|
145
|
+
demoteTo("B", verify.code);
|
|
146
|
+
return { ok: false, mode: "B", code: verify.code };
|
|
147
|
+
}
|
|
148
|
+
// Allocate only after verification (task 3). Simulate allocator failure.
|
|
149
|
+
if (host.allocatorFails()) {
|
|
150
|
+
demoteTo("B", ENC_FAIL.ASSET_UNREADABLE);
|
|
151
|
+
return { ok: false, mode: "B", code: ENC_FAIL.ASSET_UNREADABLE };
|
|
152
|
+
}
|
|
153
|
+
// Cap the encoder's MARGINAL footprint at 150 MiB (task 3, Q01). This
|
|
154
|
+
// bounds the encoder's incremental allocation, so a healthy process with
|
|
155
|
+
// a large baseline RSS still reaches mode A.
|
|
156
|
+
if (footprint() > ENCODER_RSS_BUDGET_BYTES) {
|
|
157
|
+
demoteTo("B", ENC_FAIL.RSS_BUDGET_EXCEEDED);
|
|
158
|
+
return { ok: false, mode: "B", code: ENC_FAIL.RSS_BUDGET_EXCEEDED };
|
|
159
|
+
}
|
|
160
|
+
embeddedBytes = verify.embeddedBytes;
|
|
161
|
+
// Q03: record the verified manifest's token capacity so inference can
|
|
162
|
+
// enforce the model's declared maximum, not just the global 512 ceiling.
|
|
163
|
+
maxTokens = verify.maxTokens;
|
|
164
|
+
verified = true;
|
|
165
|
+
mode = "A";
|
|
166
|
+
reporter.assetVerified({
|
|
167
|
+
mode: "A",
|
|
168
|
+
embeddedBytes: verify.embeddedBytes,
|
|
169
|
+
onnxDigest: verify.onnxDigest.slice(0, 12),
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
mode: "A",
|
|
174
|
+
embeddedBytes: verify.embeddedBytes,
|
|
175
|
+
rssBytes: footprint(),
|
|
176
|
+
sessionId: `enc-${seedFromBytes(verify.embeddedBytes).toString(16)}`,
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
infer(input) {
|
|
180
|
+
if (!verified || mode !== "A") {
|
|
181
|
+
// Only batch1/max512 verified assets reach inference (mode B/C do not).
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
code: ENC_FAIL.SHAPE_INVALID,
|
|
185
|
+
shapeError: "no verified learned asset; mode is " + modeLabel(mode),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (!input || !Array.isArray(input.tokens)) {
|
|
189
|
+
return { ok: false, code: ENC_FAIL.SHAPE_INVALID, shapeError: "missing tokens array" };
|
|
190
|
+
}
|
|
191
|
+
const n = input.tokens.length;
|
|
192
|
+
// Q03: enforce the per-manifest maxTokens (<= global 512 ceiling), so an
|
|
193
|
+
// over-cap request against a low-cap verified asset is rejected rather
|
|
194
|
+
// than silently exceeding the model's declared capacity.
|
|
195
|
+
if (n < 1 || n > maxTokens) {
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
code: ENC_FAIL.SHAPE_INVALID,
|
|
199
|
+
shapeError: `token count ${n} outside 1..${maxTokens} (manifest cap)`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Q03: cap-before-allocation on the inference path too. Check the
|
|
203
|
+
// marginal footprint BEFORE allocating the projection buffer; an
|
|
204
|
+
// over-budget inference demotes to mode B consistently with load() (the
|
|
205
|
+
// ENC_FAIL.RSS_BUDGET_EXCEEDED model: "measured RSS over 150 MiB -> B"),
|
|
206
|
+
// so a subsequent infer no longer attempts allocation in a stale mode A.
|
|
207
|
+
if (footprint() > ENCODER_RSS_BUDGET_BYTES) {
|
|
208
|
+
demoteTo("B", ENC_FAIL.RSS_BUDGET_EXCEEDED);
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
code: ENC_FAIL.RSS_BUDGET_EXCEEDED,
|
|
212
|
+
shapeError: "encoder footprint over budget during inference",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const start = host.nowMs();
|
|
216
|
+
// Batch is always 1 (single request); shape is (1, n) for n in 1..maxTokens.
|
|
217
|
+
const semantic = projectSemantic(seedFromBytes(embeddedBytes) ^ n, ENCODER_SEMANTIC_WIDTH);
|
|
218
|
+
// Q01: the projection buffer is a single reusable 384-float array; the
|
|
219
|
+
// marginal footprint is a fixed SEMANTIC_BUFFER_BYTES once it exists, so
|
|
220
|
+
// selfAllocated is SET (never accumulated) — bounded regardless of how
|
|
221
|
+
// many inferences run on a long-lived runtime.
|
|
222
|
+
selfAllocated = SEMANTIC_BUFFER_BYTES;
|
|
223
|
+
const latencyMs = host.nowMs() - start;
|
|
224
|
+
return { ok: true, semantic, rssBytes: footprint(), latencyMs, shapeError: null };
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
return runtime;
|
|
228
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/types.ts — VC2A contract (ModelManifestV1 /
|
|
3
|
+
* EncoderRuntime).
|
|
4
|
+
*
|
|
5
|
+
* The offline encoder runtime owns the learned-asset path (triad mode A: a
|
|
6
|
+
* qualified local ONNX). MODEL_ASSET.md is the normative target. This
|
|
7
|
+
* sprint (VC2A) ships the manifest + verification + shaped-inference contract;
|
|
8
|
+
* the trained weights are packaged in VC2C (MODEL_ASSET: "package.json changes
|
|
9
|
+
* occur only in VC2C"), but the verification, digest-before-load, platform
|
|
10
|
+
* demotion, shape rejection and RSS/latency budget all land here so a later
|
|
11
|
+
* sprint only substitutes real weights.
|
|
12
|
+
*
|
|
13
|
+
* Contract-first (ENGINEERING_PRACTICES §3): this types file is the reviewed
|
|
14
|
+
* gate; implementations import from it; consumers import only types + factory.
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic and dependency-free (PREVENT-PI-004 — local assets only, the
|
|
17
|
+
* runtime never fetches). No `any` (PREVENT-011).
|
|
18
|
+
*/
|
|
19
|
+
/** Supported matrix from MODEL_ASSET.md §qualification. */
|
|
20
|
+
export const ENCODER_SUPPORTED_PLATFORMS = [
|
|
21
|
+
"linux-x64",
|
|
22
|
+
"linux-arm64",
|
|
23
|
+
"darwin-x64",
|
|
24
|
+
"darwin-arm64",
|
|
25
|
+
"win32-x64",
|
|
26
|
+
];
|
|
27
|
+
/** ONNX opset required by the normative v1 target (opset 17). */
|
|
28
|
+
export const ENCODER_OPSET = 17;
|
|
29
|
+
/** Batch must be exactly 1 (single-request inference). */
|
|
30
|
+
export const ENCODER_BATCH = 1;
|
|
31
|
+
/** Maximum accepted token count (WordPiece, deterministic truncation). */
|
|
32
|
+
export const ENCODER_MAX_TOKENS = 512;
|
|
33
|
+
/** Caps the encoder's MARGINAL footprint (bytes) at 150 MiB (MODEL_ASSET
|
|
34
|
+
* §qualification). The budget bounds the encoder's own incremental allocation
|
|
35
|
+
* (a reusable projection buffer + any externally staged asset working set),
|
|
36
|
+
* NOT the whole-process RSS — in a live pi extension the process baseline
|
|
37
|
+
* routinely exceeds 150 MiB, so measuring absolute RSS would make mode A
|
|
38
|
+
* unreachable in production. This is the "RSS" figure the acceptance metric
|
|
39
|
+
* and ENC_FAIL.RSS_BUDGET_EXCEEDED refer to: it is the encoder's marginal
|
|
40
|
+
* footprint, never the process RSS (code-review Q01/Q02). */
|
|
41
|
+
export const ENCODER_RSS_BUDGET_BYTES = 150 * 1024 * 1024;
|
|
42
|
+
/** p95 inference budget in milliseconds (MODEL_ASSET §qualification). */
|
|
43
|
+
export const ENCODER_LATENCY_P95_MS = 40;
|
|
44
|
+
/** Semantic projection head width (MODEL_ASSET: 384 float32 L2-normalized). */
|
|
45
|
+
export const ENCODER_SEMANTIC_WIDTH = 384;
|
|
46
|
+
/** Exact VC2A failure codes (returned, never thrown across the boundary). */
|
|
47
|
+
export const ENC_FAIL = {
|
|
48
|
+
/** opset != 17. */
|
|
49
|
+
OPSET_INVALID: "ENC_OPSET_INVALID",
|
|
50
|
+
/** batch != 1. */
|
|
51
|
+
BATCH_INVALID: "ENC_BATCH_INVALID",
|
|
52
|
+
/** maxTokens > 512. */
|
|
53
|
+
TOKENS_EXCEEDED: "ENC_TOKENS_EXCEEDED",
|
|
54
|
+
/** input token count > declared maxTokens / 512, or not batch 1. */
|
|
55
|
+
SHAPE_INVALID: "ENC_SHAPE_INVALID",
|
|
56
|
+
/** asset file unreadable (truncated during digest read, allocator failure). */
|
|
57
|
+
ASSET_UNREADABLE: "ENC_ASSET_UNREADABLE",
|
|
58
|
+
/** on-disk digest does not match the manifest (one-byte mutation). */
|
|
59
|
+
DIGEST_MISMATCH: "ENC_DIGEST_MISMATCH",
|
|
60
|
+
/** platform not in the supported matrix (selects trigram B). */
|
|
61
|
+
PLATFORM_UNSUPPORTED: "ENC_PLATFORM_UNSUPPORTED",
|
|
62
|
+
/** manifest missing/invalid (selects trigram B). */
|
|
63
|
+
MANIFEST_INVALID: "ENC_MANIFEST_INVALID",
|
|
64
|
+
/** encoder MARGINAL footprint over the 150 MiB budget (selects trigram B).
|
|
65
|
+
* This is the encoder's own incremental allocation (a reusable projection
|
|
66
|
+
* buffer + any externally staged asset working set), NOT whole-process RSS
|
|
67
|
+
* — see ENCODER_RSS_BUDGET_BYTES. */
|
|
68
|
+
RSS_BUDGET_EXCEEDED: "ENC_RSS_BUDGET_EXCEEDED",
|
|
69
|
+
/** mode C forced by the rollback path (MEGACOMPACT_VC2A=0 / forcedMode "C").
|
|
70
|
+
* Distinct from MANIFEST_INVALID so a non-corrupt, correctly-shaped asset
|
|
71
|
+
* present on disk is not mis-reported as "manifest invalid" when the runtime
|
|
72
|
+
* is simply rolled back to the predecessor path (code-review Q04). */
|
|
73
|
+
ROLLBACK: "ENC_ROLLBACK_ACTIVE",
|
|
74
|
+
};
|
|
75
|
+
/** The 8 registered VC2A conformance IDs (task 1: "register ENC-001..008"). */
|
|
76
|
+
export const ENC_IDS = [
|
|
77
|
+
"ENC-001",
|
|
78
|
+
"ENC-002",
|
|
79
|
+
"ENC-003",
|
|
80
|
+
"ENC-004",
|
|
81
|
+
"ENC-005",
|
|
82
|
+
"ENC-006",
|
|
83
|
+
"ENC-007",
|
|
84
|
+
"ENC-008",
|
|
85
|
+
];
|