test: strengthen uok lifecycle parity contracts

This commit is contained in:
Mikael Hugo 2026-05-06 01:12:49 +02:00
parent fec9292104
commit cfde65fdd5
2 changed files with 213 additions and 9 deletions

View file

@ -1,13 +1,70 @@
import assert from "node:assert/strict";
import { test } from "vitest";
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, test } from "vitest";
import { runAutoLoopWithUok } from "../uok/kernel.js";
import {
buildParityReport,
hasCurrentParityWarning,
parseParityEvents,
UNMATCHED_RUN_STALE_MS,
} from "../uok/parity-report.js";
const NOW = Date.parse("2026-05-06T00:00:00.000Z");
const tmpRoots = [];
afterEach(() => {
for (const dir of tmpRoots.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
function makeProject() {
const root = mkdtempSync(join(tmpdir(), "sf-uok-parity-"));
tmpRoots.push(root);
mkdirSync(join(root, ".sf", "runtime"), { recursive: true });
return root;
}
function testDeps(preferences = {}) {
return {
loadEffectiveSFPreferences() {
return {
preferences: {
uok: {
enabled: true,
audit_envelope: { enabled: false },
audit_unified: { enabled: false },
...preferences.uok,
},
},
};
},
};
}
function testCtx(sessionId = "session-test") {
return {
sessionManager: {
getSessionId() {
return sessionId;
},
},
};
}
function readProjectParityEvents(projectRoot) {
const path = join(projectRoot, ".sf", "runtime", "uok-parity.jsonl");
assert.equal(existsSync(path), true);
return parseParityEvents(readFileSync(path, "utf-8"));
}
test("buildParityReport_legacy_anonymous_missing_exit_is_historical_not_current", () => {
const report = buildParityReport(
@ -96,3 +153,135 @@ test("buildParityReport_run_exit_balances_enter", () => {
assert.deepEqual(report.unmatchedRuns, []);
assert.equal(hasCurrentParityWarning(report), false);
});
test("buildParityReport_fresh_error_is_current_but_stale_error_is_historical", () => {
const report = buildParityReport(
[
{
ts: new Date(NOW - 5_000).toISOString(),
runId: "uok-fresh-error",
path: "uok-kernel",
phase: "exit",
status: "error",
error: "fresh failure",
},
{
ts: new Date(NOW - UNMATCHED_RUN_STALE_MS - 1_000).toISOString(),
runId: "uok-old-error",
path: "uok-kernel",
phase: "exit",
status: "error",
error: "old failure",
},
],
"/tmp/uok-parity.jsonl",
NOW,
);
assert.equal(report.currentErrorEvents, 1);
assert.equal(report.historicalErrorEvents, 1);
assert.deepEqual(report.criticalMismatches, ["fresh failure"]);
assert.deepEqual(report.historicalCriticalMismatches, ["old failure"]);
assert.equal(hasCurrentParityWarning(report), true);
});
test("buildParityReport_stale_parity_diff_is_historical_not_current", () => {
const report = buildParityReport(
[
{
kind: "parity-diff",
ts: new Date(NOW - UNMATCHED_RUN_STALE_MS - 1_000).toISOString(),
plane: "gitops",
turnId: "T01",
match: false,
divergence: "legacy=commit uok=status-only",
},
],
"/tmp/uok-parity.jsonl",
NOW,
);
assert.equal(report.divergencesByPlane.gitops, 1);
assert.deepEqual(report.criticalMismatches, []);
assert.deepEqual(report.historicalCriticalMismatches, [
"[gitops] legacy=commit uok=status-only",
]);
assert.equal(hasCurrentParityWarning(report), false);
});
test("runAutoLoopWithUok_success_writes_balanced_run_id_heartbeats", async () => {
const projectRoot = makeProject();
const state = { basePath: projectRoot, autoStartTime: NOW };
let observerProvided = false;
await runAutoLoopWithUok({
ctx: testCtx("session-success"),
pi: {},
s: state,
deps: testDeps(),
async runKernelLoop(_ctx, _pi, _s, deps) {
observerProvided = Boolean(deps.uokObserver);
},
async runStandardLoop() {
throw new Error("standard loop should not run when uok is enabled");
},
});
assert.equal(observerProvided, true);
assert.equal(state.currentUokRunId, undefined);
const events = readProjectParityEvents(projectRoot);
assert.equal(events.length, 2);
assert.equal(events[0].phase, "enter");
assert.equal(events[1].phase, "exit");
assert.equal(events[1].status, "ok");
assert.equal(events[0].runId, events[1].runId);
const report = JSON.parse(
readFileSync(
join(projectRoot, ".sf", "runtime", "uok-parity-report.json"),
"utf-8",
),
);
assert.equal(report.missingExitEvents, 0);
assert.equal(hasCurrentParityWarning(report), false);
});
test("runAutoLoopWithUok_throw_still_writes_exit_and_current_error_report", async () => {
const projectRoot = makeProject();
const state = { basePath: projectRoot, autoStartTime: NOW };
await assert.rejects(
() =>
runAutoLoopWithUok({
ctx: testCtx("session-error"),
pi: {},
s: state,
deps: testDeps(),
async runKernelLoop() {
throw new Error("boom");
},
async runStandardLoop() {
throw new Error("standard loop should not run when uok is enabled");
},
}),
/boom/,
);
assert.equal(state.currentUokRunId, undefined);
const events = readProjectParityEvents(projectRoot);
assert.equal(events.length, 2);
assert.equal(events[0].phase, "enter");
assert.equal(events[1].phase, "exit");
assert.equal(events[1].status, "error");
assert.equal(events[1].error, "boom");
assert.equal(events[0].runId, events[1].runId);
const report = JSON.parse(
readFileSync(
join(projectRoot, ".sf", "runtime", "uok-parity-report.json"),
"utf-8",
),
);
assert.equal(report.missingExitEvents, 0);
assert.equal(report.currentErrorEvents, 1);
assert.deepEqual(report.criticalMismatches, ["boom"]);
assert.equal(hasCurrentParityWarning(report), true);
});

View file

@ -63,7 +63,10 @@ export function buildParityReport(
const paths = {};
const statuses = {};
const criticalMismatches = [];
const historicalCriticalMismatches = [];
const runs = new Map();
let currentErrorEvents = 0;
let historicalErrorEvents = 0;
let enterEvents = 0;
let exitEvents = 0;
let legacyEnterEvents = 0;
@ -82,12 +85,13 @@ export function buildParityReport(
if (!event.match) {
divergencesByPlane[event.plane] =
(divergencesByPlane[event.plane] ?? 0) + 1;
const target = isFreshTimestamp(event.ts, nowMs, staleMs)
? criticalMismatches
: historicalCriticalMismatches;
if (event.divergence) {
criticalMismatches.push(`[${event.plane}] ${event.divergence}`);
target.push(`[${event.plane}] ${event.divergence}`);
} else {
criticalMismatches.push(
`[${event.plane}] divergence (turn=${event.turnId})`,
);
target.push(`[${event.plane}] divergence (turn=${event.turnId})`);
}
}
continue;
@ -139,7 +143,14 @@ export function buildParityReport(
}
}
if (heartbeat.status === "error") {
criticalMismatches.push(heartbeat.error ?? "parity event reported error");
const message = heartbeat.error ?? "parity event reported error";
if (isFreshTimestamp(heartbeat.ts, nowMs, staleMs)) {
currentErrorEvents += 1;
criticalMismatches.push(message);
} else {
historicalErrorEvents += 1;
historicalCriticalMismatches.push(message);
}
}
}
const unmatchedRuns = Array.from(runs.values()).filter(
@ -172,6 +183,9 @@ export function buildParityReport(
paths,
statuses,
criticalMismatches,
historicalCriticalMismatches,
currentErrorEvents,
historicalErrorEvents,
enterEvents,
exitEvents,
missingExitEvents,
@ -186,8 +200,9 @@ export function buildParityReport(
export function hasCurrentParityWarning(report) {
const criticalMismatches = report?.criticalMismatches ?? [];
const errors = report?.statuses?.error ?? 0;
return criticalMismatches.length > 0 || errors > 0;
const currentErrors =
report?.currentErrorEvents ?? report?.statuses?.error ?? 0;
return criticalMismatches.length > 0 || currentErrors > 0;
}
export function writeParityReport(basePath) {