From 3c9b5a848b3dad47230576670afd68c292452b07 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 1 Sep 2026 22:03:44 +0200 Subject: [PATCH] The receipt names what was built, not what git says at the end whatWasTested read the repositories when the run ended, so a commit landing during the twenty minutes a suite takes was recorded as tested without ever being in the binaries. It happened: one receipt named a commit made mid-run, and the verdict it carried belonged to an older tree. The heads are read once, right after the build, and carried to the receipt. A verdict is only worth something attributed to one exact state, which is the receipt's whole reason to exist. --- src/lastrun.ts | 7 ++++++- src/suite.ts | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/lastrun.ts b/src/lastrun.ts index 9d76fe4..cfcebb4 100644 --- a/src/lastrun.ts +++ b/src/lastrun.ts @@ -103,12 +103,17 @@ export function record( failed: number, ran: string[], env = process.env, + builtAgainst?: Against, ): Receipt { const receipt: Receipt = { at: new Date().toISOString(), passed, failed, - against: whatWasTested(env), + // What was BUILT, when the caller says — not what the repositories are at when the run ends. + // A receipt read at record time names whatever was committed during the twenty minutes the + // suite took, and it did: one run's receipt claimed a commit that landed mid-run and was + // never in the binaries. A verdict is only worth something attributed to one exact state. + against: builtAgainst ?? whatWasTested(env), ran, }; const path = receiptPath(); diff --git a/src/suite.ts b/src/suite.ts index 7eb57fc..8496026 100644 --- a/src/suite.ts +++ b/src/suite.ts @@ -10,7 +10,7 @@ */ import { spawn } from "node:child_process"; -import { endToEnd, record } from "./lastrun.ts"; +import { endToEnd, record, whatWasTested } from "./lastrun.ts"; import { rebuild } from "./rebuild.ts"; /** counted is what the runner said, or nulls when it said nothing recognisable. */ @@ -43,6 +43,9 @@ export async function runSuite(args: string[]): Promise { const built = rebuild(); if (built.length > 0) console.log(`built: ${built.join(", ")}\n`); } + // Read now, while it is true. The receipt names these, and reading them when the run ends + // names whatever was committed during the twenty minutes in between instead. + const against = whatWasTested(process.env); // **No canary.** There was one: a second scenario, one machine, raised first so a broken mesh // failed in two minutes rather than in forty. It walked exactly the path the first three tests @@ -55,7 +58,7 @@ export async function runSuite(args: string[]): Promise { // runs when it is named; it is no longer raised on the way to everything else. const { code, seen } = await runFiles(files); - console.log("\n" + reportOn(counted(seen), (p, f) => record(p, f, files))); + console.log("\n" + reportOn(counted(seen), (p, f) => record(p, f, files, process.env, against))); return code; }