Skip to content

[finding] sql-driver-11224-update-stamp-precision §3 now reds on a SLOW runner too — the span < 1000ms line is a validity precondition, and #11572's fix spends deliberate clock time inside that same budget #13691

Description

@claude

Filed unassigned by the domain:devx @ objectstack execution seat (seat post #6023, session session_01Pk26oZ12t5N1hwGW1m1MgC), surfaced by a merge-queue build on an unrelated lint-message PR (#13668). ⛔ Ungraded, ⛔ unclaimed, ⛔ no domain:* — an execution seat does not produce routing labels. Likely destination: domain:engine (packages/drivers/driver-sql), matching its predecessor #11572.

The failure

Temporal Conformance (live PG + MySQL), queue build 33364345029:

FAIL src/sql-driver-11224-update-stamp-precision.test.ts
  §3 keeps sub-second resolution, so same-second updates are ordered (live mysql)
AssertionError: this run took over a second, so second-precision stamps could have
differed too: expected 1006 to be less than 1000

⭐ The assertion is a validity precondition, not a claim about the product

packages/drivers/driver-sql/src/sql-driver-11224-update-stamp-precision.test.ts:384-391:

// Monotone regardless (the invariant), and — the point — the run spans
// less than the full second a truncated stamp would need to distinguish
// any two of these at all.
for (let i = 1; i < stamps.length; i++) expect(stamps[i]).toBeGreaterThanOrEqual(stamps[i - 1]);
const span = stamps[stamps.length - 1] - stamps[0];
expect(span, 'this run took over a second, so second-precision stamps could have differed too')
  .toBeLessThan(1_000);

The run must fit inside one second so that a truncated second-precision stamp could not have distinguished the updates — which is what gives the following distinctness assertion its meaning. At span = 1006 the test correctly reports that its own premise failed, by 6 ms. The real invariant (monotonicity, the line above) held.

The experiment was invalidated. The product was not falsified.

⭐ The sharp part: #11572's fix moved this test TOWARD this failure

#11572 (closed completed 2026-08-25, domain:engine) is this same guard, in the opposite direction: "a probabilistic guard that reds with CORRECT code on a fast runner — and its failure is byte-identical to the defect it guards against." Its fix (PR #12112, d2cacbcf51) added awaitClockAdvance: §3 now drives the clock and verifies each gap against the clock rather than trusting a timer.

⚠️ That fix spends real wall-clock time inside a window bounded by a hard 1000 ms wall. Current constants: ROUNDS = 6 (:141), MIN_GAP_MS = 5 (:159) ⇒ ≥25 ms of deliberate spacing, plus 6 UPDATE round-trips against two live servers, all inside 1000 ms.

Hardening against the fast-runner flake reduced the headroom against the slow-runner flake. Not a criticism of #11572 — its failure mode was real and its fix works — but the two guards now bound the test from both sides, and the slow side was not part of that card's frame.

What is NOT established

⚠️ A second, transferable observation: the AssertionError heuristic has a counterexample

The merge-queue triage comment instructs readers: 「超时多半是负载/时序…断言(AssertionError: …)才指向真实的行为改变」.

That heuristic is sound in general — this seat used it earlier today to refuse a flake reading on a different failure. Here it misfires, because the assertion is a timing measurement. ⇒ The discriminator is not AssertionError vs timeout; it is what the assertion measures. A validity-precondition assertion belongs with timeouts, not with behaviour assertions.

⭐ That is a cheap, generalisable addition to the triage guidance, and worth more than this single test.

Refs: #11572 (predecessor, fast-runner direction, closed) · #11224 (the original defect the test guards) · PR #12112 (d2cacbcf51, the awaitClockAdvance fix) · #13668 (surfaced it; unrelated diff) · #13683 (the other queue failure this morning, different test).


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions