Prepare scanner branch for merge

This commit is contained in:
AzuTear
2026-07-09 08:44:50 +02:00
parent f791d1464c
commit 8b73c01e46
69 changed files with 6700 additions and 3773 deletions
@@ -0,0 +1,18 @@
import { describe, expect, it } from "vitest";
import { confirmedReviewCorpus, ocrEvalCorpus, seedCorpus, validateConfirmedReviewCorpus } from ".";
describe("confirmed review corpus", () => {
it("contains only human-confirmed review labels", () => {
expect(validateConfirmedReviewCorpus()).toEqual([]);
});
it("does not duplicate eval case ids", () => {
const ids = ocrEvalCorpus.map((entry) => entry.id);
expect(new Set(ids).size).toBe(ids.length);
});
it("is included in the full OCR eval corpus", () => {
expect(ocrEvalCorpus).toHaveLength(seedCorpus.length + confirmedReviewCorpus.length);
});
});
+15
View File
@@ -0,0 +1,15 @@
import type { OcrEvalCase } from "../ocrEvalHarness";
export interface ConfirmedReviewEvalCase extends OcrEvalCase {
confirmed: true;
meta: NonNullable<OcrEvalCase["meta"]> & {
source: "review-sample";
note: string;
};
}
// Human-confirmed review samples belong here after their `expect` values were
// checked against the real artifact. Do not paste unconfirmed exporter output
// directly from outputs/review-eval-candidates/.
export const confirmedReviewCorpus: ConfirmedReviewEvalCase[] = [];
+24
View File
@@ -0,0 +1,24 @@
import { confirmedReviewCorpus, type ConfirmedReviewEvalCase } from "./confirmedReviewCorpus";
import { seedCorpus } from "./seedCorpus";
import type { OcrEvalCase } from "../ocrEvalHarness";
export { confirmedReviewCorpus, seedCorpus };
export type { ConfirmedReviewEvalCase };
export const ocrEvalCorpus: OcrEvalCase[] = [...seedCorpus, ...confirmedReviewCorpus];
export function validateConfirmedReviewCorpus(corpus: readonly ConfirmedReviewEvalCase[] = confirmedReviewCorpus) {
const errors: string[] = [];
const seen = new Set<string>();
for (const entry of corpus) {
if (seen.has(entry.id)) errors.push(`${entry.id}: duplicate id`);
seen.add(entry.id);
if (entry.confirmed !== true) errors.push(`${entry.id}: confirmed must be true`);
if (entry.meta.source !== "review-sample") errors.push(`${entry.id}: meta.source must be review-sample`);
if (!entry.meta.note?.trim()) errors.push(`${entry.id}: meta.note must describe the review source/reason`);
if (Object.keys(entry.expect).length === 0) errors.push(`${entry.id}: expect must label at least one field`);
if (Object.keys(entry.ocr).length === 0) errors.push(`${entry.id}: ocr must contain at least one field`);
}
return errors;
}
+56
View File
@@ -0,0 +1,56 @@
import { describe, expect, it } from "vitest";
const { formatSummary, parseWaitSeconds, validatePreflight } = require("../../scripts/live-preflight.cjs") as {
formatSummary: (result: unknown) => string;
parseWaitSeconds: (value: string) => number;
validatePreflight: (input: unknown) => { ok: boolean; errors: string[]; signature: string; isElevated?: boolean; genshinFound?: boolean };
};
function health(signature = "sig-current") {
return { ok: true, appBuild: { signature } };
}
function status(runtime = { isElevated: true, genshinFound: true, targetProcess: "GenshinImpact.exe", foregroundProcess: "GenshinImpact.exe" }) {
return { ok: true, status: { runtimeInfo: runtime } };
}
describe("live preflight script", () => {
it("accepts a matching elevated Genshin runtime", () => {
const result = validatePreflight({ health: health(), status: status(), expected: "sig-current" });
expect(result.ok).toBe(true);
expect(result.errors).toEqual([]);
expect(result.signature).toBe("sig-current");
});
it("rejects stale runtime signatures", () => {
const result = validatePreflight({ health: health("old"), status: status(), expected: "sig-current" });
expect(result.ok).toBe(false);
expect(result.errors.join("\n")).toContain("does not match");
});
it("rejects non-elevated or missing Genshin runtime by default", () => {
const result = validatePreflight({
health: health(),
status: status({ isElevated: false, genshinFound: false, targetProcess: "", foregroundProcess: "explorer.exe" }),
expected: "sig-current",
});
expect(result.ok).toBe(false);
expect(result.errors).toContain("Runtime is not elevated.");
expect(result.errors).toContain("Genshin process/window was not found.");
});
it("formats a concise human summary", () => {
const summary = formatSummary(validatePreflight({ health: health(), status: status(), expected: "sig-current" }));
expect(summary).toContain("live preflight: PASS");
expect(summary).toContain("elevated: yes");
expect(summary).toContain("genshin: yes");
});
it("parses optional wait seconds strictly", () => {
expect(parseWaitSeconds("")).toBe(0);
expect(parseWaitSeconds("120")).toBe(120);
expect(() => parseWaitSeconds("-1")).toThrow("--wait");
expect(() => parseWaitSeconds("1.5")).toThrow("--wait");
expect(() => parseWaitSeconds("soon")).toThrow("--wait");
});
});
+9 -9
View File
@@ -1,24 +1,24 @@
import { describe, expect, it } from "vitest";
import { formatReport, runOcrEval } from "./ocrEvalHarness";
import { seedCorpus } from "./corpus/seedCorpus";
import { ocrEvalCorpus } from "./corpus";
// Regression gate: the seed corpus is verified ground truth, so the parser must
// read every labeled field correctly. A drop here means an OCR/parser change
// regressed a previously-correct read - look at the printed failures. If a
// change intentionally alters a correct output, update the corpus label in the
// same commit (the label is the source of truth, not the code).
// Regression gate: every case in the combined corpus is verified ground truth,
// so the parser must read every labeled field correctly. A drop here means an
// OCR/parser change regressed a previously-correct read - look at the printed
// failures. If a change intentionally alters a correct output, update the corpus
// label in the same commit (the label is the source of truth, not the code).
describe("OCR eval harness", () => {
const report = runOcrEval(seedCorpus);
const report = runOcrEval(ocrEvalCorpus);
it("prints the accuracy report", () => {
// Surfaced in test output for humans; not an assertion.
// eslint-disable-next-line no-console
console.log("\n" + formatReport(report) + "\n");
expect(report.totalCases).toBe(seedCorpus.length);
expect(report.totalCases).toBe(ocrEvalCorpus.length);
});
it("reads every labeled field on the seed corpus correctly", () => {
it("reads every labeled field on the eval corpus correctly", () => {
const failureSummary = report.failures
.map((failure) => {
const wrong = failure.fields
+36
View File
@@ -0,0 +1,36 @@
import { describe, expect, it } from "vitest";
import { deflateSync } from "node:zlib";
import { pngBufferToBitmap } from "../../electron/services/pngBitmap";
import { lockSignalRatio } from "../lib/lockDetection";
function chunk(type: string, data: Buffer) {
const result = Buffer.alloc(12 + data.length);
result.writeUInt32BE(data.length, 0);
result.write(type, 4, 4, "ascii");
data.copy(result, 8);
return result;
}
function rgbPng1x1(r: number, g: number, b: number) {
const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(1, 0);
ihdr.writeUInt32BE(1, 4);
ihdr[8] = 8;
ihdr[9] = 2;
const raw = Buffer.from([0, r, g, b]);
return Buffer.concat([
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
chunk("IHDR", ihdr),
chunk("IDAT", deflateSync(raw)),
chunk("IEND", Buffer.alloc(0)),
]);
}
describe("pngBufferToBitmap", () => {
it("decodes RGB PNG pixels for lock detection", () => {
const bitmap = pngBufferToBitmap(rgbPng1x1(235, 92, 90));
expect(bitmap.width).toBe(1);
expect(bitmap.height).toBe(1);
expect(lockSignalRatio(bitmap)).toBe(1);
});
});
@@ -0,0 +1,91 @@
import { execFileSync } from "node:child_process";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
function writeCandidatePayload(dir: string) {
const inputPath = path.join(dir, "review-eval-candidates.json");
writeFileSync(
inputPath,
JSON.stringify({
summary: {},
candidates: [
{
id: "review-2026-07-08T15-02-39-765Z-152",
savedAt: "2026-07-08T15:02:39.765Z",
reason: "automatic:parser-notes:p1:r2c3",
resolution: "1920x1080",
ocr: {
"artifact-name": "Pristine Plume of the Blessed",
"artifact-slot": "Plume of Death",
"artifact-main-stat-label": "ATK",
"artifact-level": "+20",
"artifact-substats": "- Energy Recharge+10.4%",
},
},
],
}),
"utf8",
);
return inputPath;
}
describe("prepare confirmed review case script", () => {
it("creates a confirmed corpus snippet from a candidate and explicit labels", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-confirmed-review-"));
try {
const inputPath = writeCandidatePayload(dir);
const expectPath = path.join(dir, "expect.json");
const outputPath = path.join(dir, "snippet.ts");
writeFileSync(
expectPath,
`\uFEFF${JSON.stringify({
name: "Pristine Plume of the Blessed",
slot: "Plume of Death",
level: 20,
mainStat: "ATK",
setName: "Silken Moon's Serenade",
})}`,
"utf8",
);
execFileSync(
"node",
[
"scripts/prepare-confirmed-review-case.cjs",
`--input=${inputPath}`,
"--candidate=review-2026-07-08T15-02-39-765Z-152",
`--expect-file=${expectPath}`,
`--out=${outputPath}`,
],
{ cwd: process.cwd(), stdio: "pipe" },
);
const snippet = readFileSync(outputPath, "utf8");
expect(snippet).toContain("confirmed: true");
expect(snippet).toContain("Pristine Plume of the Blessed");
expect(snippet).toContain('"artifact-name": "Pristine Plume of the Blessed"');
expect(snippet).toContain("sourceCandidate=review-2026-07-08T15-02-39-765Z-152");
expect(snippet).not.toContain("confirmed: false");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects missing explicit labels", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-confirmed-review-"));
try {
const inputPath = writeCandidatePayload(dir);
expect(() =>
execFileSync(
"node",
["scripts/prepare-confirmed-review-case.cjs", `--input=${inputPath}`, "--candidate=review-2026-07-08T15-02-39-765Z-152"],
{ cwd: process.cwd(), stdio: "pipe" },
),
).toThrow();
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
});
@@ -0,0 +1,90 @@
import { execFileSync } from "node:child_process";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
function reviewRecord(savedAt: string, reason: string, ocr: Array<{ id: string; text: string }>, locked?: boolean) {
return {
savedAt,
sample: {
reason,
capture: {
width: 1920,
height: 1080,
ocr,
locked,
},
parsed: {
name: "Pristine Plume of the Blessed",
slot: ocr.some((entry) => entry.id === "artifact-slot") ? "Plume of Death" : "Unknown Slot",
level: 20,
mainStat: "ATK",
mainValue: "311",
setName: "Silken Moon's Serenade",
equipped: ocr.some((entry) => entry.id === "artifact-footer") ? "Aino" : "Not detected",
substats: ["Energy Recharge+10.4%"],
confidence: 0.9,
notes: [],
},
},
};
}
const completeOcr = [
{ id: "artifact-name", text: "Pristine Plume of the Blessed" },
{ id: "artifact-slot", text: "Plume of Death" },
{ id: "artifact-main-stat-label", text: "ATK" },
{ id: "artifact-level", text: "+20" },
{ id: "artifact-substats", text: "- Energy Recharge+10.4%" },
{ id: "artifact-footer", text: "Equipped: Aino" },
];
describe("review eval candidate exporter", () => {
it("exports deduplicated candidates with stats and stale markers", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-review-candidates-"));
try {
const inputPath = path.join(dir, "review-samples.jsonl");
const outDir = path.join(dir, "out");
const staleOcr = completeOcr.filter((entry) => entry.id !== "artifact-slot");
writeFileSync(
inputPath,
[
JSON.stringify(reviewRecord("2026-07-08T15:00:00.000Z", "automatic:missing-crops-or-ocr:p1:r0c0", completeOcr)),
JSON.stringify(reviewRecord("2026-07-08T15:00:00.000Z", "automatic:missing-crops-or-ocr:p1:r0c0", completeOcr)),
JSON.stringify(reviewRecord("2026-07-08T15:01:00.000Z", "automatic:capture-rejected:p1:r0c1", staleOcr, true)),
"{not json",
].join("\n"),
"utf8",
);
execFileSync("node", ["scripts/export-review-eval-candidates.cjs", `--input=${inputPath}`, `--out=${outDir}`, "--limit=10"], {
cwd: process.cwd(),
stdio: "pipe",
});
const payload = JSON.parse(readFileSync(path.join(outDir, "review-eval-candidates.json"), "utf8"));
const markdown = readFileSync(path.join(outDir, "review-eval-candidates.md"), "utf8");
expect(payload.summary.recordsRead).toBe(4);
expect(payload.summary.invalidRecords).toBe(1);
expect(payload.summary.uniqueCandidates).toBe(2);
expect(payload.summary.exportedCandidates).toBe(2);
expect(payload.summary.exportStats.completeFastFields).toBe(1);
expect(payload.summary.exportStats.likelyStaleCaptures).toBe(1);
expect(payload.summary.exportStats.equippedFooterCandidates).toBe(2);
expect(payload.summary.exportStats.lockedTrueCandidates).toBe(1);
expect(payload.candidates[0].missingFastFields).toEqual([]);
expect(payload.candidates[0].parsed.equipped).toBe("Aino");
expect(payload.candidates[0].reviewPrompt.expectedFields.equipped).toBe("Aino");
expect(payload.candidates[1].likelyStaleCapture).toBe(true);
expect(payload.candidates[1].locked).toBe(true);
expect(markdown).toContain("## Export stats");
expect(markdown).toContain("- artifact-slot: 1");
expect(markdown).toContain("equipped=Aino");
expect(markdown).toContain("Locked=true candidates: 1");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
});
+1 -1
View File
@@ -10,7 +10,7 @@ import type { OcrEvalCase } from "./ocrEvalHarness";
// itself). The intended flow is:
// 1. reviewSampleToEvalCase() extracts the OCR + the parser's current guess.
// 2. A human confirms or corrects `expect` in the produced case.
// 3. The corrected case is committed into src/eval/corpus/.
// 3. The corrected case is committed into src/eval/corpus/confirmedReviewCorpus.ts.
// The `confirmed` flag records whether step 2 happened.
export interface ReviewSampleEvalCase extends OcrEvalCase {
@@ -0,0 +1,355 @@
import { execFileSync } from "node:child_process";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
function validAssessment() {
return {
createdAt: "2026-07-08T12:00:00.000Z",
goal100Decision: "qualified-comparison: winner=ik-traineddata",
goal100: {
limit: 100,
comparisonComplete: true,
winnerEngine: "ik-traineddata",
winnerQualified: true,
winnerActiveAverageMsPerParsed: 820,
winnerActiveProjectedMsFor100: 82000,
winnerMissRate: 0,
winnerReviewRate: 0.04,
engines: [
{ engine: "ik-traineddata", qualified: true, missRate: 0, reviewRate: 0.04 },
{ engine: "current", qualified: true, missRate: 0, reviewRate: 0.06 },
],
},
limits: [
{
limit: 20,
comparisonComplete: true,
winnerEngine: "current",
winnerQualified: true,
winnerActiveAverageMsPerParsed: 390,
winnerActiveProjectedMsFor100: 39000,
winnerMissRate: 0,
winnerReviewRate: 0.05,
engines: [
{ engine: "current", qualified: true, missRate: 0, reviewRate: 0.05 },
{ engine: "ik-traineddata", qualified: true, missRate: 0, reviewRate: 0.1 },
],
},
],
};
}
function writeAssessment(dir: string, payload: unknown) {
const inputPath = path.join(dir, "scan-performance-assessment.json");
writeFileSync(inputPath, JSON.stringify(payload), "utf8");
return inputPath;
}
describe("scan assessment validator", () => {
it("accepts a qualified complete 100-artifact comparison", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
const output = execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(JSON.parse(output).ok).toBe(true);
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("accepts a matching expected winner", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
const output = execFileSync(
"node",
["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--expect-winner=ik-traineddata"],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
expect(JSON.parse(output).ok).toBe(true);
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("prints an opt-in human summary", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
const output = execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary"], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(output).toContain("scan assessment: PASS");
expect(output).toContain(`input: ${inputPath}`);
expect(output).toContain("createdAt: 2026-07-08T12:00:00.000Z");
expect(output).toContain("limit: 100");
expect(output).toContain("winner: ik-traineddata");
expect(output).toContain("activeAvg: 820ms/artifact");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("accepts a qualified complete 20-artifact comparison", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
const output = execFileSync(
"node",
["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary", "--limit=20"],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
expect(output).toContain("scan assessment: PASS");
expect(output).toContain("limit: 20");
expect(output).toContain("winner: current");
expect(output).toContain("activeAvg: 390ms/artifact");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects invalid requested limits", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary", "--limit=0"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("--limit must be a positive integer");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects a requested limit that is missing from the assessment", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary", "--limit=45"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("Missing limit=45 assessment");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("keeps the validated npm scripts wired through preflight and the correct assessment limit", () => {
const packageJson = JSON.parse(readFileSync(path.join(process.cwd(), "package.json"), "utf8"));
expect(packageJson.scripts["scan:goal:compare:validated"]).toBe(
"npm run scan:live:preflight && npm run scan:goal:compare && npm run scan:assessment:validate -- --latest --summary",
);
expect(packageJson.scripts["scan:goal:compare:validated:wait"]).toBe(
"npm run scan:live:preflight:wait && npm run scan:goal:compare && npm run scan:assessment:validate -- --latest --summary",
);
expect(packageJson.scripts["scan:iterate:compare"]).toBe(
"powershell -NoProfile -ExecutionPolicy Bypass -File scripts\\live-soak.ps1 -Limits 20 -ScanEngine compare -BenchmarkOcr",
);
expect(packageJson.scripts["scan:iterate:compare:validated"]).toBe(
"npm run scan:live:preflight && npm run scan:iterate:compare && npm run scan:assessment:validate -- --latest --summary --limit=20",
);
expect(packageJson.scripts["scan:iterate:compare:validated:wait"]).toBe(
"npm run scan:live:preflight:wait && npm run scan:iterate:compare && npm run scan:assessment:validate -- --latest --summary --limit=20",
);
});
it("rejects a mismatched expected winner", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
expect(() =>
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--expect-winner=current"], {
cwd: process.cwd(),
stdio: "pipe",
}),
).toThrow();
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("prints errors in summary mode for rejected assessments", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const inputPath = writeAssessment(dir, validAssessment());
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--expect-winner=current", "--summary"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("Expected winner");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects a single-engine 100-artifact run", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const payload = validAssessment();
payload.goal100Decision = "not-comparable: current and ik-traineddata were not both run";
payload.goal100.comparisonComplete = false;
payload.goal100.engines = [{ engine: "current", qualified: true, missRate: 0, reviewRate: 0 }];
const inputPath = writeAssessment(dir, payload);
expect(() =>
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`], {
cwd: process.cwd(),
stdio: "pipe",
}),
).toThrow();
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects an unqualified winner", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const payload = validAssessment();
payload.goal100Decision = "not-qualified: 100-artifact winner failed quality gates";
payload.goal100.winnerQualified = false;
payload.goal100.engines[0].qualified = false;
payload.goal100.engines[0].reviewRate = 0.3;
const inputPath = writeAssessment(dir, payload);
expect(() =>
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`], {
cwd: process.cwd(),
stdio: "pipe",
}),
).toThrow();
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects a winner with missing quality rates", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const payload = validAssessment();
delete (payload.goal100.engines[0] as { missRate?: number }).missRate;
delete (payload.goal100.engines[0] as { reviewRate?: number }).reviewRate;
const inputPath = writeAssessment(dir, payload);
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("Winner missRate must be a finite number");
expect(stdout).toContain("Winner reviewRate must be a finite number");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects a winner with missing summary quality rates", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const payload = validAssessment();
delete (payload.goal100 as { winnerMissRate?: number }).winnerMissRate;
delete (payload.goal100 as { winnerReviewRate?: number }).winnerReviewRate;
const inputPath = writeAssessment(dir, payload);
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("Winner summary missRate must be a finite number");
expect(stdout).toContain("Winner summary reviewRate must be a finite number");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("rejects a winner with missing speed timing", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const payload = validAssessment();
delete (payload.goal100 as { winnerActiveAverageMsPerParsed?: number }).winnerActiveAverageMsPerParsed;
delete (payload.goal100 as { winnerActiveProjectedMsFor100?: number }).winnerActiveProjectedMsFor100;
const inputPath = writeAssessment(dir, payload);
let stdout = "";
try {
execFileSync("node", ["scripts/validate-scan-assessment.cjs", `--input=${inputPath}`, "--summary"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: "pipe",
});
} catch (error) {
stdout = String((error as { stdout?: string }).stdout || "");
}
expect(stdout).toContain("scan assessment: FAIL");
expect(stdout).toContain("Winner active average timing must be a positive finite number");
expect(stdout).toContain("Winner projected100 timing must be a positive finite number");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
it("validates the latest assessment under a live-soak root", () => {
const dir = mkdtempSync(path.join(tmpdir(), "gaa-assessment-"));
try {
const older = path.join(dir, "2026-07-08T10-00-00");
const newer = path.join(dir, "2026-07-08T11-00-00");
mkdirSync(older);
mkdirSync(newer);
writeAssessment(older, { goal100Decision: "not-run: missing 100-artifact assessment" });
writeAssessment(newer, validAssessment());
const output = execFileSync("node", ["scripts/validate-scan-assessment.cjs", "--latest", `--root=${dir}`], {
cwd: process.cwd(),
encoding: "utf8",
});
const parsed = JSON.parse(output);
expect(parsed.ok).toBe(true);
expect(parsed.inputPath).toContain("2026-07-08T11-00-00");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
});