pi-mega-compact 0.20.18 → 0.20.20
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-vc8c.js +31 -0
- package/dist/config/vector-cortex.js +19 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-platform.js +12 -0
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-policy.js +12 -0
- package/dist/extensions/dashboard-server/route-dispatch.js +12 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-platform.js +42 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-policy.js +45 -0
- package/dist/src/config/vector-cortex-vc8c.js +31 -0
- package/dist/src/config/vector-cortex.js +19 -0
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/cache/_diagnostics-fixture.js +79 -5
- package/dist/src/vector-cortex/cache/diagnostics.js +17 -8
- package/dist/src/vector-cortex/controller/_adaptive-fixture.js +126 -0
- package/dist/src/vector-cortex/controller/policy-emit.js +56 -0
- package/dist/src/vector-cortex/migrations/pressure-v2-ops.js +166 -0
- package/dist/src/vector-cortex/migrations/pressure-v2-types.js +32 -0
- package/dist/src/vector-cortex/migrations/pressure-v2.js +36 -0
- package/dist/src/vector-cortex/migrations/request-hash-v2-ops.js +23 -7
- package/dist/src/vector-cortex/platform/cross-read.js +98 -0
- package/dist/src/vector-cortex/platform/emit.js +54 -0
- package/dist/src/vector-cortex/platform/select.js +104 -0
- package/dist/src/vector-cortex/platform/types.js +57 -0
- package/dist/vector-cortex/cache/_diagnostics-fixture.js +79 -5
- package/dist/vector-cortex/cache/diagnostics.js +17 -8
- package/dist/vector-cortex/controller/_adaptive-fixture.js +126 -0
- package/dist/vector-cortex/controller/policy-emit.js +56 -0
- package/dist/vector-cortex/controller/policy.js +158 -0
- package/dist/vector-cortex/controller/shadow.js +117 -0
- package/dist/vector-cortex/controller/types.js +85 -0
- package/dist/vector-cortex/migrations/pressure-v2-ops.js +166 -0
- package/dist/vector-cortex/migrations/pressure-v2-types.js +32 -0
- package/dist/vector-cortex/migrations/pressure-v2.js +36 -0
- package/dist/vector-cortex/migrations/request-hash-v2-ops.js +23 -7
- package/dist/vector-cortex/platform/cross-read.js +98 -0
- package/dist/vector-cortex/platform/emit.js +54 -0
- package/dist/vector-cortex/platform/select.js +104 -0
- package/dist/vector-cortex/platform/types.js +57 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-BOGp2sag.js → AreaChart-BkfB-LSQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-BOGp2sag.js.map → AreaChart-BkfB-LSQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-BHgA-QPL.js → BarChart-Cs1kogko.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-BHgA-QPL.js.map → BarChart-Cs1kogko.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-6E7lwM74.js → CacheTab-BZgaguGr.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-6E7lwM74.js.map → CacheTab-BZgaguGr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-BEtNmFHz.js → EventsTab-BFbkI_MO.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-BEtNmFHz.js.map → EventsTab-BFbkI_MO.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-DGxZulRH.js → HealthTab-CvlOENCX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-DGxZulRH.js.map → HealthTab-CvlOENCX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-C86jppQE.js → MaintenanceTab-CtBuz2qL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-C86jppQE.js.map → MaintenanceTab-CtBuz2qL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-J3VVxooZ.js → MemoryMapTab-K4775S4d.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-J3VVxooZ.js.map → MemoryMapTab-K4775S4d.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-yn9AFumo.js → MetricsTab-DVGcFInz.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-yn9AFumo.js.map → MetricsTab-DVGcFInz.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BMarUiq3.js → OverviewTab-4LmW5ZCl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BMarUiq3.js.map → OverviewTab-4LmW5ZCl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DxnzMive.js → ReposTab-StebchgQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DxnzMive.js.map → ReposTab-StebchgQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DXKpDUuC.js → SessionsTab-C3D_XAkX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DXKpDUuC.js.map → SessionsTab-C3D_XAkX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-BctuV-CJ.js → SetupTab-BTBGyppF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-BctuV-CJ.js.map → SetupTab-BTBGyppF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-D8yOC96S.js → TimeSavedCard-CTPi_AAW.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-D8yOC96S.js.map → TimeSavedCard-CTPi_AAW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-BBxqGYH-.js → TurnsTab-DSOGcY5Q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-BBxqGYH-.js.map → TurnsTab-DSOGcY5Q.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-OMW8_RFf.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-OMW8_RFf.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-DdJQSagO.js → WikiTab-Db-qFDdg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-DdJQSagO.js.map → WikiTab-Db-qFDdg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-B4Q9h_8Y.js → button-BF4UgBAD.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-B4Q9h_8Y.js.map → button-BF4UgBAD.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-WyR31hUV.js → card-XmXoYQqB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-WyR31hUV.js.map → card-XmXoYQqB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-pTio6Bq3.js → generateCategoricalChart-Be8hM1aU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-pTio6Bq3.js.map → generateCategoricalChart-Be8hM1aU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/index-Difwoltx.css +1 -0
- package/extensions/dashboard-client/dist/assets/{index-BoLUiNsd.js → index-NXDgILxv.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-BoLUiNsd.js.map → index-NXDgILxv.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-5dieXxoo.js → switch-kUZCrbia.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-5dieXxoo.js.map → switch-kUZCrbia.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-BFc-7_LL.js → toggle-DEe5mCwF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-BFc-7_LL.js.map → toggle-DEe5mCwF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-BqmKNBAI.js → useSSE-BlCyLqge.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BqmKNBAI.js.map → useSSE-BlCyLqge.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/api/vector-cortex.ts +18 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexPlatformCard.tsx +42 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexPolicyCard.tsx +43 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +4 -0
- package/extensions/dashboard-client/src/tabs/useVectorCortexPoll.ts +10 -0
- package/extensions/dashboard-client/src/types/vector-cortex-vc8.ts +34 -1
- package/extensions/dashboard-client/src/types/vector-cortex.ts +1 -1
- package/extensions/dashboard-server/api-contracts/vector-cortex-platform.ts +34 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-policy.ts +36 -0
- package/extensions/dashboard-server/route-dispatch.ts +12 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
- package/extensions/dashboard-server/routes-vector-cortex-platform.ts +52 -0
- package/extensions/dashboard-server/routes-vector-cortex-policy.ts +55 -0
- package/package.json +1 -1
- package/src/config/vector-cortex-vc8c.ts +33 -0
- package/src/config/vector-cortex.ts +21 -0
- package/src/config.ts +2 -0
- package/src/vector-cortex/cache/_diagnostics-fixture.ts +163 -5
- package/src/vector-cortex/cache/diagnostics.ts +18 -9
- package/src/vector-cortex/controller/_adaptive-fixture.ts +230 -0
- package/src/vector-cortex/controller/policy-emit.ts +82 -0
- package/src/vector-cortex/migrations/pressure-v2-ops.ts +204 -0
- package/src/vector-cortex/migrations/pressure-v2-types.ts +83 -0
- package/src/vector-cortex/migrations/pressure-v2.ts +59 -0
- package/src/vector-cortex/migrations/request-hash-v2-ops.ts +21 -6
- package/src/vector-cortex/platform/cross-read.ts +122 -0
- package/src/vector-cortex/platform/emit.ts +77 -0
- package/src/vector-cortex/platform/select.ts +131 -0
- package/src/vector-cortex/platform/types.ts +169 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BTF1AGCJ.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-BTF1AGCJ.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-CYpzq9Lm.css +0 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pressure-v2-ops.ts — M7 migration operational logic (copy/validate/switch).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from pressure-v2.ts to keep the parent file under the 300-line
|
|
5
|
+
* soft limit (soft-as-hard gate). Pure logic over an injected M7Host;
|
|
6
|
+
* deterministic + testable; no console. PREVENT-002/011/PI-004 honored.
|
|
7
|
+
*
|
|
8
|
+
* WHY THE LABEL CHECK RE-READS THE HOST AT SWITCH TIME. The sprint's failure
|
|
9
|
+
* injection is explicit: kill the process after the copy phase, insert an
|
|
10
|
+
* unknown legacy pressure row, then resume — and the resumed run must return
|
|
11
|
+
* M7_PRESSURE_UNKNOWN and KEEP THE OLD POINTER. If the switch trusted the
|
|
12
|
+
* verdict of an earlier verify call, the injected row would be invisible and
|
|
13
|
+
* the pointer would flip over a store that still holds an uncanonical label.
|
|
14
|
+
* So `m7Switch` re-reads `v1Rows`/`existingV2`/`activeVersion` and re-validates
|
|
15
|
+
* against that live state. Validation is a precondition; the switch is the only
|
|
16
|
+
* place that proves the hazard is absent *right now*.
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import { isPressureLevel } from "../controller/policy.js";
|
|
20
|
+
import { M7_FAIL, PRESSURE_LEGACY_VERSION } from "./pressure-v2-types.js";
|
|
21
|
+
/** Length-prefixed framing so the folded fields cannot alias. */
|
|
22
|
+
function field(value) {
|
|
23
|
+
return `${Buffer.byteLength(value, "utf8")}:${value}`;
|
|
24
|
+
}
|
|
25
|
+
/** Row identity is (session, effectiveSeq) — one pressure per sequence point. */
|
|
26
|
+
const identity = (sessionId, effectiveSeq) => `${sessionId}::${effectiveSeq}`;
|
|
27
|
+
/** The authoritative v2 digest: SHA-256 over the length-prefixed fields. */
|
|
28
|
+
export function derivePressureDigest(sessionId, level, effectiveSeq, ts) {
|
|
29
|
+
return createHash("sha256")
|
|
30
|
+
.update(field("pressure-v2") +
|
|
31
|
+
field(sessionId) +
|
|
32
|
+
field(level) +
|
|
33
|
+
field(String(effectiveSeq)) +
|
|
34
|
+
field(ts), "utf8")
|
|
35
|
+
.digest("hex");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Map ONE legacy row to its v2 form. ONLY the canonical five labels map;
|
|
39
|
+
* anything else throws `{ code: M7_PRESSURE_UNKNOWN }`. There is deliberately
|
|
40
|
+
* no fallback branch — a coerced label is a silently misclassified workload.
|
|
41
|
+
*/
|
|
42
|
+
export function mapPressureRow(v1) {
|
|
43
|
+
if (!isPressureLevel(v1.label)) {
|
|
44
|
+
throw { code: M7_FAIL.PRESSURE_UNKNOWN };
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
sessionId: v1.sessionId,
|
|
48
|
+
level: v1.label,
|
|
49
|
+
effectiveSeq: v1.effectiveSeq,
|
|
50
|
+
ts: v1.ts,
|
|
51
|
+
digest: derivePressureDigest(v1.sessionId, v1.label, v1.effectiveSeq, v1.ts),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** True when every legacy row carries a canonical label. */
|
|
55
|
+
export function allLabelsCanonical(host) {
|
|
56
|
+
return host.v1Rows().every((r) => isPressureLevel(r.label));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* COPY: resumable per (session, effectiveSeq). An interrupted run resumes
|
|
60
|
+
* without duplicate rows. An uncanonical label aborts the copy with
|
|
61
|
+
* M7_PRESSURE_UNKNOWN before anything is written.
|
|
62
|
+
*/
|
|
63
|
+
export function m7Copy(host) {
|
|
64
|
+
const existing = new Map(host.existingV2().map((r) => [identity(r.sessionId, r.effectiveSeq), r]));
|
|
65
|
+
const wanted = [];
|
|
66
|
+
for (const v1 of host.v1Rows()) {
|
|
67
|
+
// Throws M7_PRESSURE_UNKNOWN for a non-canonical label.
|
|
68
|
+
const fresh = mapPressureRow(v1);
|
|
69
|
+
const stored = existing.get(identity(v1.sessionId, v1.effectiveSeq));
|
|
70
|
+
if (stored !== undefined && stored.digest === fresh.digest)
|
|
71
|
+
continue;
|
|
72
|
+
wanted.push(fresh);
|
|
73
|
+
}
|
|
74
|
+
if (wanted.length > 0)
|
|
75
|
+
host.putV2(wanted);
|
|
76
|
+
return { written: wanted, all: [...host.existingV2()] };
|
|
77
|
+
}
|
|
78
|
+
function dedupe(codes) {
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const c of codes)
|
|
81
|
+
if (!out.includes(c))
|
|
82
|
+
out.push(c);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* VALIDATE: compare counts and digests between v1 and v2, and re-check every
|
|
87
|
+
* legacy label. Returns codes rather than throwing so a caller sees every
|
|
88
|
+
* problem at once.
|
|
89
|
+
*/
|
|
90
|
+
export function m7Verify(host) {
|
|
91
|
+
const codes = [];
|
|
92
|
+
const v1Rows = host.v1Rows();
|
|
93
|
+
const stored = host.existingV2();
|
|
94
|
+
// Label check first: an uncanonical legacy label invalidates the whole run.
|
|
95
|
+
for (const v1 of v1Rows) {
|
|
96
|
+
if (!isPressureLevel(v1.label))
|
|
97
|
+
codes.push(M7_FAIL.PRESSURE_UNKNOWN);
|
|
98
|
+
}
|
|
99
|
+
const counts = new Map();
|
|
100
|
+
for (const r of stored) {
|
|
101
|
+
const id = identity(r.sessionId, r.effectiveSeq);
|
|
102
|
+
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
103
|
+
}
|
|
104
|
+
const expected = new Set();
|
|
105
|
+
for (const v1 of v1Rows) {
|
|
106
|
+
if (!isPressureLevel(v1.label))
|
|
107
|
+
continue;
|
|
108
|
+
const id = identity(v1.sessionId, v1.effectiveSeq);
|
|
109
|
+
expected.add(id);
|
|
110
|
+
const n = counts.get(id) ?? 0;
|
|
111
|
+
if (n === 0)
|
|
112
|
+
codes.push(M7_FAIL.COPY_PARTIAL);
|
|
113
|
+
if (n > 1)
|
|
114
|
+
codes.push(M7_FAIL.COUNT_MISMATCH);
|
|
115
|
+
}
|
|
116
|
+
// Every stored row must re-derive its own digest and correspond to a v1 row.
|
|
117
|
+
for (const r of stored) {
|
|
118
|
+
const fresh = derivePressureDigest(r.sessionId, r.level, r.effectiveSeq, r.ts);
|
|
119
|
+
if (r.digest !== fresh)
|
|
120
|
+
codes.push(M7_FAIL.DIGEST_MISMATCH);
|
|
121
|
+
if (!expected.has(identity(r.sessionId, r.effectiveSeq))) {
|
|
122
|
+
codes.push(M7_FAIL.COUNT_MISMATCH);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return { ok: codes.length === 0, codes: dedupe(codes) };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* SWITCH: atomically flip the active pointer to v2 — but ONLY after
|
|
129
|
+
* re-validating against freshly-read host state (see the module note on the
|
|
130
|
+
* post-copy failure injection). The pointer is left untouched on any failure.
|
|
131
|
+
*/
|
|
132
|
+
export function m7Switch(host) {
|
|
133
|
+
if (host.activeVersion() !== PRESSURE_LEGACY_VERSION) {
|
|
134
|
+
return { ok: false, codes: [M7_FAIL.NOT_ON_LEGACY] };
|
|
135
|
+
}
|
|
136
|
+
// Re-read the live rows: an unknown label injected after the copy is caught
|
|
137
|
+
// here, and the old pointer survives.
|
|
138
|
+
if (!allLabelsCanonical(host)) {
|
|
139
|
+
return { ok: false, codes: [M7_FAIL.PRESSURE_UNKNOWN] };
|
|
140
|
+
}
|
|
141
|
+
const verify = m7Verify(host);
|
|
142
|
+
if (!verify.ok)
|
|
143
|
+
return verify;
|
|
144
|
+
host.switchToV2();
|
|
145
|
+
return { ok: true, codes: [] };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Full M7 migration: copy, then validate + switch. An uncanonical label thrown
|
|
149
|
+
* during the copy is converted to a result code so the caller sees the same
|
|
150
|
+
* shape as a validation failure, and the pointer is left on legacy.
|
|
151
|
+
*/
|
|
152
|
+
export function migratePressureV2(host) {
|
|
153
|
+
try {
|
|
154
|
+
m7Copy(host);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
const code = typeof err === "object" && err !== null && "code" in err
|
|
158
|
+
? err.code
|
|
159
|
+
: undefined;
|
|
160
|
+
if (code === M7_FAIL.PRESSURE_UNKNOWN) {
|
|
161
|
+
return { ok: false, codes: [M7_FAIL.PRESSURE_UNKNOWN] };
|
|
162
|
+
}
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
return m7Switch(host);
|
|
166
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pressure-v2-types.ts — M7 pressure-v2 migration types.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from pressure-v2.ts to keep the parent file under the 300-line
|
|
5
|
+
* soft limit (soft-as-hard gate). Pure type + constant definitions; no logic.
|
|
6
|
+
* PREVENT-002/011/PI-004 honored.
|
|
7
|
+
*/
|
|
8
|
+
/** The active-version value the v2 pointer is switched to. */
|
|
9
|
+
export const PRESSURE_V2_VERSION = 2;
|
|
10
|
+
/** The legacy (predecessor) active version. */
|
|
11
|
+
export const PRESSURE_LEGACY_VERSION = 1;
|
|
12
|
+
/** M7 failure codes. */
|
|
13
|
+
export const M7_FAIL = {
|
|
14
|
+
/** A legacy row carries a label outside the canonical five levels. */
|
|
15
|
+
PRESSURE_UNKNOWN: "M7_PRESSURE_UNKNOWN",
|
|
16
|
+
/** Copied row count does not match the legacy row count. */
|
|
17
|
+
COUNT_MISMATCH: "M7_COUNT_MISMATCH",
|
|
18
|
+
/** A v2 row digest does not re-derive from its own declared fields. */
|
|
19
|
+
DIGEST_MISMATCH: "M7_DIGEST_MISMATCH",
|
|
20
|
+
/** A legacy row has no corresponding v2 row (interrupted copy). */
|
|
21
|
+
COPY_PARTIAL: "M7_COPY_PARTIAL",
|
|
22
|
+
/** The active pointer is not on v1; switching would regress or no-op. */
|
|
23
|
+
NOT_ON_LEGACY: "M7_NOT_ON_LEGACY",
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Registered M7 conformance IDs (M7-001..015). The acceptance test reads these
|
|
27
|
+
* rows from the v2 `adaptive-policy/` domain and asserts each returns its
|
|
28
|
+
* manifest bytes or exactly its listed failure code. Mirrors M5_IDS / M6_IDS.
|
|
29
|
+
*/
|
|
30
|
+
export const M7_IDS = Array.from({ length: 15 }, (_v, i) => `M7-${String(i + 1).padStart(3, "0")}`);
|
|
31
|
+
/** Named M7 rows surfaced by the conformance corpus. */
|
|
32
|
+
export const M7_NAMED_IDS = ["M7-PRESSURE-003"];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/migrations/pressure-v2.ts — M7 pressure-v2 migration
|
|
3
|
+
* (COPY + VALIDATE + SWITCH).
|
|
4
|
+
*
|
|
5
|
+
* Delegate-shell: types + constants live in pressure-v2-types.ts and the
|
|
6
|
+
* operational logic (copy/verify/switch/label mapping) lives in
|
|
7
|
+
* pressure-v2-ops.ts. This file re-exports the public surface so callers import
|
|
8
|
+
* from a single module. Split to keep under the 300-line soft limit
|
|
9
|
+
* (soft-as-hard gate).
|
|
10
|
+
*
|
|
11
|
+
* M7 canonicalizes the context-pressure label. The predecessor stored whatever
|
|
12
|
+
* label a producer happened to write; v2 admits EXACTLY five — `low`, `medium`,
|
|
13
|
+
* `high`, `ultra`, `mega` — and rejects everything else as
|
|
14
|
+
* `M7_PRESSURE_UNKNOWN`. The rejection is the feature: coercing an unrecognized
|
|
15
|
+
* legacy label onto the nearest level would silently reclassify a workload, and
|
|
16
|
+
* the direction of that error is unknowable from the label alone.
|
|
17
|
+
*
|
|
18
|
+
* Like M4/M5/M6 it follows the copy/validate/switch contract:
|
|
19
|
+
*
|
|
20
|
+
* - copy: resumable per (session, effectiveSeq) — an interrupted run
|
|
21
|
+
* resumes without duplicate rows or active-pointer drift.
|
|
22
|
+
* - validate: every v1 row has exactly one v2 row, every v2 digest re-derives
|
|
23
|
+
* from its own declared fields, and every legacy label is
|
|
24
|
+
* canonical.
|
|
25
|
+
* - switch: ATOMICALLY flip the active pointer via `host.switchToV2()`, but
|
|
26
|
+
* only after RE-READING host state and re-validating. The sprint's
|
|
27
|
+
* failure injection kills the process after the copy and then
|
|
28
|
+
* inserts an unknown legacy pressure; the resumed run must return
|
|
29
|
+
* `M7_PRESSURE_UNKNOWN` and KEEP THE OLD POINTER. A migration that
|
|
30
|
+
* trusts a stale verification is a migration that corrupts on
|
|
31
|
+
* restart.
|
|
32
|
+
*
|
|
33
|
+
* PREVENT-002/011/PI-004 honored.
|
|
34
|
+
*/
|
|
35
|
+
export { PRESSURE_V2_VERSION, PRESSURE_LEGACY_VERSION, M7_FAIL, M7_IDS, M7_NAMED_IDS, } from "./pressure-v2-types.js";
|
|
36
|
+
export { derivePressureDigest, mapPressureRow, allLabelsCanonical, m7Copy, m7Verify, m7Switch, migratePressureV2, } from "./pressure-v2-ops.js";
|
|
@@ -48,15 +48,23 @@ function generationFromEconomics(economicsVersion) {
|
|
|
48
48
|
}
|
|
49
49
|
export function detectCollision(host) {
|
|
50
50
|
const byHash = new Map();
|
|
51
|
-
|
|
51
|
+
// Track the v1 hash seen for each identity so a genuine collision (same
|
|
52
|
+
// identity, DIFFERENT v1 hash) is distinguished from a benign duplicate
|
|
53
|
+
// (same identity, SAME v1 hash — an idempotent resume re-reads the same row).
|
|
54
|
+
const identityHash = new Map();
|
|
52
55
|
for (const v1 of host.v1Rows()) {
|
|
53
56
|
const row = deriveRequestHashRow(host, v1);
|
|
54
57
|
const id = identity(v1.profileId, v1.requestDigest);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
const priorHash = identityHash.get(id);
|
|
59
|
+
if (priorHash !== undefined) {
|
|
60
|
+
// Same identity seen before. Only a collision if the v1 hashes differ —
|
|
61
|
+
// two genuinely distinct v1 rows collapsing to one v2 hash. Identical
|
|
62
|
+
// duplicates (same hash) are benign and skipped.
|
|
63
|
+
if (priorHash !== v1.hash)
|
|
64
|
+
return true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
identityHash.set(id, v1.hash);
|
|
60
68
|
const prior = byHash.get(row.hash);
|
|
61
69
|
if (prior !== undefined && prior !== id)
|
|
62
70
|
return true;
|
|
@@ -73,17 +81,25 @@ export function isGenerationInvalidated(host, row) {
|
|
|
73
81
|
}
|
|
74
82
|
export function m5Copy(host) {
|
|
75
83
|
const existing = new Map(host.existingV2().map((r) => [identity(r.profileId, r.requestDigest), r]));
|
|
84
|
+
// Track identities already in the `wanted` batch so a benign duplicate v1
|
|
85
|
+
// row (same identity, same hash) does not produce a duplicate v2 write that
|
|
86
|
+
// would later trip COUNT_MISMATCH in verify.
|
|
87
|
+
const batchSeen = new Set();
|
|
76
88
|
const wanted = [];
|
|
77
89
|
for (const v1 of host.v1Rows()) {
|
|
78
90
|
const fresh = deriveRequestHashRow(host, v1);
|
|
79
91
|
if (isGenerationInvalidated(host, fresh))
|
|
80
92
|
continue;
|
|
81
|
-
const
|
|
93
|
+
const id = identity(v1.profileId, v1.requestDigest);
|
|
94
|
+
if (batchSeen.has(id))
|
|
95
|
+
continue;
|
|
96
|
+
const stored = existing.get(id);
|
|
82
97
|
if (stored !== undefined &&
|
|
83
98
|
stored.hash === fresh.hash &&
|
|
84
99
|
stored.economicsVersion === fresh.economicsVersion) {
|
|
85
100
|
continue;
|
|
86
101
|
}
|
|
102
|
+
batchSeen.add(id);
|
|
87
103
|
wanted.push(fresh);
|
|
88
104
|
}
|
|
89
105
|
if (wanted.length > 0)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform/cross-read.ts — VC8C neutral stdin/stdout cross-conformance framing.
|
|
3
|
+
*
|
|
4
|
+
* Both the TS reference and an external Rust binary speak ONE neutral wire
|
|
5
|
+
* format: a sequence of length-prefixed JSON records. Each record is:
|
|
6
|
+
*
|
|
7
|
+
* [4-byte big-endian length][exactly that many bytes of canonical JSON]
|
|
8
|
+
*
|
|
9
|
+
* The TS side encodes and decodes this framing; the external runner (a local
|
|
10
|
+
* subprocess, PREVENT-PI-004: never a URL) reads the same frames on stdin and
|
|
11
|
+
* writes them back on stdout. Parity is then byte-for-byte: the canonical JSON
|
|
12
|
+
* bytes of each record and the failure code must match in both directions.
|
|
13
|
+
*
|
|
14
|
+
* `outputBytes` is the OCAML-free canonical representation of a fixture's
|
|
15
|
+
* produced bytes as a HEX STRING, so byte-equality is a plain string compare and
|
|
16
|
+
* the wire JSON never carries raw binary.
|
|
17
|
+
*
|
|
18
|
+
* Everything here is PURE: no clock, no storage, no network, no flag read. The
|
|
19
|
+
* flag gates only the reporter seam in emit.ts.
|
|
20
|
+
*
|
|
21
|
+
* PREVENT-011: no `any` type. PREVENT-PI-004: no network.
|
|
22
|
+
*/
|
|
23
|
+
import { RUST_FRAME_TRUNCATED, RUST_PARITY_MISMATCH } from "./types.js";
|
|
24
|
+
/** Canonical JSON bytes for a neutral record (the wire form of a record body). */
|
|
25
|
+
export function encodeRecordJson(record) {
|
|
26
|
+
return new TextEncoder().encode(JSON.stringify(record));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Encode a list of neutral records into the length-framed neutral wire format.
|
|
30
|
+
* Each record is written as a 4-byte big-endian length followed by exactly that
|
|
31
|
+
* many canonical JSON bytes, concatenated in order.
|
|
32
|
+
*/
|
|
33
|
+
export function encodeNeutralFrame(fixtures) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
for (const fixture of fixtures) {
|
|
36
|
+
const body = encodeRecordJson(fixture);
|
|
37
|
+
const header = new Uint8Array(4);
|
|
38
|
+
new DataView(header.buffer).setUint32(0, body.length, false);
|
|
39
|
+
parts.push(header, body);
|
|
40
|
+
}
|
|
41
|
+
const total = parts.reduce((acc, p) => acc + p.length, 0);
|
|
42
|
+
const out = new Uint8Array(total);
|
|
43
|
+
let offset = 0;
|
|
44
|
+
for (const part of parts) {
|
|
45
|
+
out.set(part, offset);
|
|
46
|
+
offset += part.length;
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decode a neutral frame stream back into records. A partial trailing frame
|
|
52
|
+
* (a length prefix with fewer body bytes than declared) returns
|
|
53
|
+
* `{ ok: false, code: "RUST_FRAME_TRUNCATED" }` — the invariant the sprint's
|
|
54
|
+
* unique failure injection exercises.
|
|
55
|
+
*/
|
|
56
|
+
export function decodeNeutralFrame(bytes) {
|
|
57
|
+
const records = [];
|
|
58
|
+
let offset = 0;
|
|
59
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
60
|
+
const decoder = new TextDecoder();
|
|
61
|
+
while (offset + 4 <= bytes.byteLength) {
|
|
62
|
+
const len = view.getUint32(offset, false);
|
|
63
|
+
offset += 4;
|
|
64
|
+
if (offset + len > bytes.byteLength) {
|
|
65
|
+
return { ok: false, code: RUST_FRAME_TRUNCATED };
|
|
66
|
+
}
|
|
67
|
+
const body = decoder.decode(bytes.subarray(offset, offset + len));
|
|
68
|
+
offset += len;
|
|
69
|
+
try {
|
|
70
|
+
records.push(JSON.parse(body));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return { ok: false, code: RUST_FRAME_TRUNCATED };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (offset !== bytes.byteLength) {
|
|
77
|
+
// Trailing bytes fewer than one length prefix — the frame was cut mid-header.
|
|
78
|
+
return { ok: false, code: RUST_FRAME_TRUNCATED };
|
|
79
|
+
}
|
|
80
|
+
return { ok: true, records };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Compare one expected record against one actual record. Both the canonical
|
|
84
|
+
* output bytes (as hex strings) and the failure code must match. Any byte or
|
|
85
|
+
* code difference returns `{ ok: false, code: "RUST_PARITY_MISMATCH" }`.
|
|
86
|
+
*/
|
|
87
|
+
export function compareFixtureOutput(expected, actual) {
|
|
88
|
+
if (expected.fixtureId !== actual.fixtureId) {
|
|
89
|
+
return { ok: false, code: RUST_PARITY_MISMATCH };
|
|
90
|
+
}
|
|
91
|
+
if (expected.outputBytes !== actual.outputBytes) {
|
|
92
|
+
return { ok: false, code: RUST_PARITY_MISMATCH };
|
|
93
|
+
}
|
|
94
|
+
if (expected.failureCode !== actual.failureCode) {
|
|
95
|
+
return { ok: false, code: RUST_PARITY_MISMATCH };
|
|
96
|
+
}
|
|
97
|
+
return { ok: true };
|
|
98
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform/emit.ts — VC8C engine parity/selection reporter seam (FLAG-GATED).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the VC8B policy-emit pattern: a thin `safe()` wrapper around an
|
|
5
|
+
* optional injected `emit`, and the two event names the sprint spec requires:
|
|
6
|
+
* - `vector_cortex_engine_parity_checked` — a parity report was resolved.
|
|
7
|
+
* - `vector_cortex_engine_selection_demoted` — the triad dropped from A.
|
|
8
|
+
*
|
|
9
|
+
* FLAG SEMANTICS. The engine selector and cross-conformance runner STILL RUN
|
|
10
|
+
* regardless of `MEGACOMPACT_VC8C`. The flag gates ONLY this reporting +
|
|
11
|
+
* dashboard seam: flag-off is byte-identical to the predecessor (VC8B).
|
|
12
|
+
*
|
|
13
|
+
* PAYLOAD DISCIPLINE. These events carry only ids, the finite mode, the machine
|
|
14
|
+
* code, and counts — never artifact bytes, output bytes, or free-text.
|
|
15
|
+
*
|
|
16
|
+
* PREVENT-PI-004: no network. PREVENT-011: no `any` type.
|
|
17
|
+
*/
|
|
18
|
+
import { VC8C_ENABLED } from "../../config/vector-cortex.js";
|
|
19
|
+
/** Run `fn` only when an emit exists; a reporting failure is never fatal. */
|
|
20
|
+
function safe(emit, fn) {
|
|
21
|
+
if (emit === undefined)
|
|
22
|
+
return;
|
|
23
|
+
try {
|
|
24
|
+
fn(emit);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Non-fatal: a reporting failure must never break the agent loop.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Report a resolved engine parity check. Gated by the flag. */
|
|
31
|
+
export function reportEngineParityChecked(emit, parity) {
|
|
32
|
+
if (!VC8C_ENABLED())
|
|
33
|
+
return;
|
|
34
|
+
safe(emit, (e) => e("vector_cortex_engine_parity_checked", {
|
|
35
|
+
ts: undefined,
|
|
36
|
+
event: "vector_cortex_engine_parity_checked",
|
|
37
|
+
reportId: parity.reportId,
|
|
38
|
+
fixtureCount: parity.fixtureCount,
|
|
39
|
+
passed: parity.passed,
|
|
40
|
+
failed: parity.failed,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
/** Report an engine selection demotion away from mode A. Gated by the flag. */
|
|
44
|
+
export function reportEngineSelectionDemoted(emit, demotion) {
|
|
45
|
+
if (!VC8C_ENABLED())
|
|
46
|
+
return;
|
|
47
|
+
safe(emit, (e) => e("vector_cortex_engine_selection_demoted", {
|
|
48
|
+
ts: undefined,
|
|
49
|
+
event: "vector_cortex_engine_selection_demoted",
|
|
50
|
+
from: demotion.from,
|
|
51
|
+
to: demotion.to,
|
|
52
|
+
code: demotion.code,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform/select.ts — VC8C canary-selection engine selector (PURE).
|
|
3
|
+
*
|
|
4
|
+
* `selectEngine` decides the failure triad mode from a reviewer-accepted
|
|
5
|
+
* `ParityReportV1` and the current host platform. It admits mode A (qualified
|
|
6
|
+
* external Rust artifact) ONLY when every piece of evidence lines up:
|
|
7
|
+
*
|
|
8
|
+
* 1. The report's ABI version matches ABI_VERSION (RUST-ABI-001).
|
|
9
|
+
* 2. URL metadata is present (artifactUrl is non-empty).
|
|
10
|
+
* 3. A commit hash is present (commit is a non-empty hex-ish string).
|
|
11
|
+
* 4. The artifact's Cargo.lock digest matches the report's evidence digest
|
|
12
|
+
* (RUST-META-003) — a digest mismatch MUST reject the artifact.
|
|
13
|
+
* 5. The platform is in SUPPORTED_PLATFORMS (RUST-PLATFORM-*).
|
|
14
|
+
* 6. EVERY fixture in the report's matrix resolved ok (RUST-001..030).
|
|
15
|
+
*
|
|
16
|
+
* Any failure demotes to B (TS reference). If the TS reference breaker has
|
|
17
|
+
* opened (`allowLegacy` is set by the caller), the selector demotes further to
|
|
18
|
+
* C (legacy path) instead — the two-bytes-of-safety pyramid never runs an
|
|
19
|
+
* unqualified artifact and never silently rides a broken reference.
|
|
20
|
+
*
|
|
21
|
+
* Everything here is PURE: no clock, no storage, no network, no flag read. The
|
|
22
|
+
* flag gates only the reporter seam in emit.ts.
|
|
23
|
+
*
|
|
24
|
+
* PREVENT-002/011/PI-004 honored.
|
|
25
|
+
*/
|
|
26
|
+
import { ABI_VERSION, RUST_ABI_MISMATCH, RUST_ARTIFACT_MISSING, RUST_CARGO_DIGEST_MISMATCH, RUST_PARITY_MISMATCH, RUST_PLATFORM_UNSUPPORTED, SUPPORTED_PLATFORMS, } from "./types.js";
|
|
27
|
+
/** Construct a selection failure. */
|
|
28
|
+
function fail(code) {
|
|
29
|
+
return { code };
|
|
30
|
+
}
|
|
31
|
+
/** Type guard: is this a supported host platform? */
|
|
32
|
+
export function isSupportedPlatform(platform) {
|
|
33
|
+
return SUPPORTED_PLATFORMS.includes(platform);
|
|
34
|
+
}
|
|
35
|
+
/** A 40-char lowercase hex string is the canonical bare git SHA-256 commit. */
|
|
36
|
+
const COMMIT_RE = /^[0-9a-f]{40}$/;
|
|
37
|
+
/** Validate the ABI version matches EngineAbiV1 exactly. Throws on mismatch. */
|
|
38
|
+
export function validateAbi(abi) {
|
|
39
|
+
if (abi.version !== ABI_VERSION)
|
|
40
|
+
throw fail(RUST_ABI_MISMATCH);
|
|
41
|
+
}
|
|
42
|
+
/** Validate URL metadata + commit + Cargo.lock evidence are all present. */
|
|
43
|
+
function validateEvidence(report) {
|
|
44
|
+
if (report.artifactUrl.length === 0)
|
|
45
|
+
throw fail(RUST_ARTIFACT_MISSING);
|
|
46
|
+
if (!COMMIT_RE.test(report.commit))
|
|
47
|
+
throw fail(RUST_ARTIFACT_MISSING);
|
|
48
|
+
// SHA-256 hex digests are exactly 64 chars; anything else is not evidence.
|
|
49
|
+
if (report.cargoLockDigest.length !== 64) {
|
|
50
|
+
throw fail(RUST_ARTIFACT_MISSING);
|
|
51
|
+
}
|
|
52
|
+
if (report.artifactCargoLockDigest.length !== 64) {
|
|
53
|
+
throw fail(RUST_ARTIFACT_MISSING);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** True when every fixture in the matrix resolved ok. */
|
|
57
|
+
export function matrixAllOk(report) {
|
|
58
|
+
if (report.matrix.length === 0)
|
|
59
|
+
return false;
|
|
60
|
+
return report.matrix.every((f) => f.ok && f.code === null);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Select the engine mode from a parity report and the host platform.
|
|
64
|
+
*
|
|
65
|
+
* Returns mode A only when all six admission checks pass and the digest (the
|
|
66
|
+
* report's own evidence) is internally consistent with the Cargo.lock the
|
|
67
|
+
* artifact claims. Otherwise demotes to B; if the TS reference breaker is open
|
|
68
|
+
* (`allowLegacy`), demotes to C.
|
|
69
|
+
*/
|
|
70
|
+
export function selectEngine(abi, report, platform, allowLegacy = false) {
|
|
71
|
+
try {
|
|
72
|
+
validateAbi(abi);
|
|
73
|
+
validateEvidence(report);
|
|
74
|
+
if (!isSupportedPlatform(platform))
|
|
75
|
+
throw fail(RUST_PLATFORM_UNSUPPORTED);
|
|
76
|
+
if (report.platform !== platform)
|
|
77
|
+
throw fail(RUST_PLATFORM_UNSUPPORTED);
|
|
78
|
+
// RUST-META-003: the artifact's own Cargo.lock digest must match the
|
|
79
|
+
// reviewer-accepted evidence; a mismatch rejects the artifact outright.
|
|
80
|
+
if (report.artifactCargoLockDigest !== report.cargoLockDigest) {
|
|
81
|
+
throw fail(RUST_CARGO_DIGEST_MISMATCH);
|
|
82
|
+
}
|
|
83
|
+
if (!matrixAllOk(report)) {
|
|
84
|
+
throw fail(RUST_PARITY_MISMATCH);
|
|
85
|
+
}
|
|
86
|
+
const artifact = {
|
|
87
|
+
url: report.artifactUrl,
|
|
88
|
+
commit: report.commit,
|
|
89
|
+
cargoLockDigest: report.cargoLockDigest,
|
|
90
|
+
platform: report.platform,
|
|
91
|
+
qualified: true,
|
|
92
|
+
};
|
|
93
|
+
return { mode: "A", reason: "qualified", artifact };
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
const code = typeof e === "object" && e !== null && "code" in e
|
|
97
|
+
? String(e.code)
|
|
98
|
+
: RUST_PARITY_MISMATCH;
|
|
99
|
+
if (allowLegacy) {
|
|
100
|
+
return { mode: "C", reason: code, artifact: null };
|
|
101
|
+
}
|
|
102
|
+
return { mode: "B", reason: code, artifact: null };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform/types.ts — VC8C engine ABI + parity report + selection types.
|
|
3
|
+
*
|
|
4
|
+
* These are the CANARY-SELECTION contracts. This repo has NO Rust workspace and
|
|
5
|
+
* creates none: an external Rad repo supplies the artifact URL, commit, and
|
|
6
|
+
* Cargo.lock digest/evidence as `ParityReportV1`. The selector only ever admits
|
|
7
|
+
* mode A (qualified external Rust) when every piece of that evidence matches;
|
|
8
|
+
* otherwise it demotes to B (TS reference) or C (legacy).
|
|
9
|
+
*
|
|
10
|
+
* EngineAbiV1 is the FINITE, versioned envelope both sides speak: an input
|
|
11
|
+
* envelope in, an output envelope out, and a machine-coded error envelope. There
|
|
12
|
+
* is deliberately no free-text field and no unbounded version string — an ABI
|
|
13
|
+
* whose version or error space can drift at runtime cannot be cross-checked
|
|
14
|
+
* against a foreign binary.
|
|
15
|
+
*
|
|
16
|
+
* Failure triad (private to the runtime; mirrored here for the selector):
|
|
17
|
+
* A = qualified external Rust artifact
|
|
18
|
+
* B = TS reference (forced by a parity or metadata failure)
|
|
19
|
+
* C = legacy path (forced when the TS reference breaker opens)
|
|
20
|
+
*
|
|
21
|
+
* Conformance IDs RUST-001..030 are registered here as the single source of
|
|
22
|
+
* truth for the sprint's conformance rows; the three named fixtures
|
|
23
|
+
* (RUST-ABI-001, RUST-ERR-002, RUST-META-003) are the headline assertions.
|
|
24
|
+
*
|
|
25
|
+
* PREVENT-PI-004: type definitions only, no network code.
|
|
26
|
+
* PREVENT-011: no `any` type.
|
|
27
|
+
*/
|
|
28
|
+
/** ABI version string shared by every engine implementation. */
|
|
29
|
+
export const ABI_VERSION = "engine-abi-v1";
|
|
30
|
+
/** Supported host platforms; an artifact for any other platform is rejected. */
|
|
31
|
+
export const SUPPORTED_PLATFORMS = [
|
|
32
|
+
"linux-x64",
|
|
33
|
+
"linux-arm64",
|
|
34
|
+
"darwin-x64",
|
|
35
|
+
"darwin-arm64",
|
|
36
|
+
"win32-x64",
|
|
37
|
+
];
|
|
38
|
+
/** Failure code: canonical bytes or failure codes disagreed across runners. */
|
|
39
|
+
export const RUST_PARITY_MISMATCH = "RUST_PARITY_MISMATCH";
|
|
40
|
+
/** Failure code: a neutral frame ended mid-record (partial write/read). */
|
|
41
|
+
export const RUST_FRAME_TRUNCATED = "RUST_FRAME_TRUNCATED";
|
|
42
|
+
/** Failure code: the artifact ABI version does not match ABI_VERSION. */
|
|
43
|
+
export const RUST_ABI_MISMATCH = "RUST_ABI_MISMATCH";
|
|
44
|
+
/** Failure code: the artifact Cargo.lock digest does not match the evidence. */
|
|
45
|
+
export const RUST_CARGO_DIGEST_MISMATCH = "RUST_CARGO_DIGEST_MISMATCH";
|
|
46
|
+
/** Failure code: the artifact targets a platform outside SUPPORTED_PLATFORMS. */
|
|
47
|
+
export const RUST_PLATFORM_UNSUPPORTED = "RUST_PLATFORM_UNSUPPORTED";
|
|
48
|
+
/** Failure code: the report names no artifact (URL/commit missing). */
|
|
49
|
+
export const RUST_ARTIFACT_MISSING = "RUST_ARTIFACT_MISSING";
|
|
50
|
+
/** Conformance IDs RUST-001..RUST-030 for the 30 numbered conformance rows. */
|
|
51
|
+
export const RUST_CONFORMANCE_IDS = Array.from({ length: 30 }, (_v, i) => `RUST-${String(i + 1).padStart(3, "0")}`);
|
|
52
|
+
/** Named conformance fixtures for the sprint's headline assertions. */
|
|
53
|
+
export const RUST_NAMED_FIXTURES = [
|
|
54
|
+
"RUST-ABI-001",
|
|
55
|
+
"RUST-ERR-002",
|
|
56
|
+
"RUST-META-003",
|
|
57
|
+
];
|