settled() asks which, not when

The timestamp comparison lost the race between one test's closing push
and the next test's opening one: the old apply's report landed newer
than the new send and settled() passed for a declaration the machine
had not read. The report names its declaration now, the mesh says
whether it is the current one, and this reads the answer instead of
inferring it.
This commit is contained in:
2026-09-02 00:03:00 +02:00
parent a65115fc81
commit 81e5f31910
+6 -8
View File
@@ -135,7 +135,7 @@ async function settled(node: string, withinMs = 240_000): Promise<void> {
wrong: { node: string; outcome: string; refused?: string;
failed?: { id: string; error: string }[] }[];
waiting: { node: string; never: boolean }[];
reported: { node: string; outcome: string; at?: string; sent?: string }[];
reported: { node: string; outcome: string; current: boolean }[];
} | undefined;
let said = "";
try {
@@ -161,14 +161,12 @@ async function settled(node: string, withinMs = 240_000): Promise<void> {
.filter(Boolean).join("\n ");
throw new Error(`${node} did not apply what it was sent (${bad.outcome}):\n ${why}`);
}
// Current is not caught up. The sent digest is recorded at send, so "not waiting" holds
// from the moment push returns, while the machine is still applying — this test asserted on
// containers the instant the declaration was current and found them not created yet. Caught
// up is the machine's own report being newer than what was sent to it: two timestamps the
// mesh recorded itself, compared.
// Caught up is an equality, not an ordering. This compared timestamps once — report newer
// than send — and lost the race it invited: the previous test's closing apply reported
// after this test's push, newer and still about the old declaration. The report now names
// the declaration it applied, and the mesh says whether that is the one it last sent.
const word = state.reported.find((r) => r.node === node);
const acted = word?.outcome === "applied" && !!word.at && !!word.sent &&
Date.parse(word.at) > Date.parse(word.sent);
const acted = word?.outcome === "applied" && word.current;
if (!state.waiting.some((w) => w.node === node) && acted) return;
last = said;
// Unhurried on purpose: each poll is an exec into a container on the machine that is busy