fix(release): require terminal frozen QA evidence

This commit is contained in:
Dallin Romney
2026-08-20 21:56:50 -07:00
parent 1b5da636f7
commit a7dcb21dde
2 changed files with 47 additions and 20 deletions
+24 -13
View File
@@ -168,6 +168,21 @@ function requireCanonicalRuntimePair(runtimePair: unknown) {
);
}
function matchesFrozenRuntimePairManifest(
options: { targetSha?: string; lane?: string },
scenarioIds: unknown[],
skippedScenarioIds: unknown[],
) {
const manifest = FROZEN_RUNTIME_PAIR_MANIFESTS.get(`${options.targetSha}:${options.lane}`);
return (
manifest !== undefined &&
manifest.scenarioIds.length === scenarioIds.length &&
manifest.scenarioIds.every((scenarioId, index) => scenarioId === scenarioIds[index]) &&
manifest.gapScenarioIds.length === skippedScenarioIds.length &&
manifest.gapScenarioIds.every((scenarioId, index) => scenarioId === skippedScenarioIds[index])
);
}
export function validateQaRuntimePairSummary(
summary: unknown,
options: { requireExplicitGap?: boolean; targetSha?: string; lane?: string } = {},
@@ -175,11 +190,7 @@ export function validateQaRuntimePairSummary(
if (!isRecord(summary) || !isRecord(summary.run) || !Array.isArray(summary.scenarios)) {
throw new Error("runtime-pair summary is missing run or scenario evidence");
}
const completedLegacyRun =
summary.run.status === undefined &&
typeof summary.run.finishedAt === "string" &&
Number.isFinite(Date.parse(summary.run.finishedAt));
if (summary.run.status !== "completed" && !completedLegacyRun) {
if (summary.run.status !== "completed" && summary.run.status !== undefined) {
throw new Error("runtime-pair summary is not completed");
}
if (!requireCanonicalRuntimePair(summary.run.runtimePair)) {
@@ -218,6 +229,13 @@ export function validateQaRuntimePairSummary(
}
}
if (
run.status === undefined &&
!matchesFrozenRuntimePairManifest(options, scenarioIds, skippedScenarioIds)
) {
throw new Error("runtime-pair summary is not completed");
}
const expectedCounts = {
total: summary.scenarios.length,
passed,
@@ -239,14 +257,7 @@ export function validateQaRuntimePairSummary(
throw new Error("nonzero candidate suite exit requires an explicit Codex-native harness gap");
}
if (options.requireExplicitGap === true) {
const manifest = FROZEN_RUNTIME_PAIR_MANIFESTS.get(`${options.targetSha}:${options.lane}`);
if (
!manifest ||
manifest.scenarioIds.length !== scenarioIds.length ||
manifest.scenarioIds.some((scenarioId, index) => scenarioId !== scenarioIds[index]) ||
manifest.gapScenarioIds.length !== skippedScenarioIds.length ||
manifest.gapScenarioIds.some((scenarioId, index) => scenarioId !== skippedScenarioIds[index])
) {
if (!matchesFrozenRuntimePairManifest(options, scenarioIds, skippedScenarioIds)) {
throw new Error("nonzero candidate exit is not covered by a trusted frozen-lane manifest");
}
}
@@ -135,16 +135,20 @@ describe("frozen QA runtime-pair summary validation", () => {
);
});
it("accepts a completed legacy summary that used its finish timestamp", () => {
const fixture = summary([scenario({ name: "legacy terminal", status: "pass" })]);
it("accepts a statusless summary only for an exact frozen terminal manifest", () => {
const fixture = frozenCoreSummary();
Reflect.deleteProperty(fixture.run, "status");
Object.assign(fixture.run, { finishedAt: "2026-08-21T03:34:17.434Z" });
expect(validateQaRuntimePairSummary(fixture)).toEqual({
total: 1,
passed: 1,
expect(
validateQaRuntimePairSummary(fixture, {
targetSha: "311047822ecdde24e824d839ab105ef08f17be00",
lane: "core",
}),
).toEqual({
total: 27,
passed: 19,
failed: 0,
skipped: 0,
skipped: 8,
});
});
@@ -157,6 +161,18 @@ describe("frozen QA runtime-pair summary validation", () => {
);
});
it("rejects a partial statusless artifact for a frozen candidate", () => {
const fixture = summary([scenario({ name: frozenCoreScenarioIds[0], status: "pass" })]);
Reflect.deleteProperty(fixture.run, "status");
expect(() =>
validateQaRuntimePairSummary(fixture, {
targetSha: "311047822ecdde24e824d839ab105ef08f17be00",
lane: "core",
}),
).toThrow("runtime-pair summary is not completed");
});
it("accepts only passing scenarios and explicit one-sided Codex-native gaps", () => {
const fixture = summary([
scenario({ name: "passing", status: "pass" }),