Uh oh!
There was an error while loading. Please reload this page.
test(driver-sql): make the update-stamp precision guard deterministic — drive §3's clock instead of racing it - #12112
Merged
os-warren merged 2 commits intoAug 25, 2026
Conversation
…racing it The precision guard's section 3 fired ROUNDS updates back to back and required that at least two landed on different values, which needs the wall clock to tick during the run -- a property of the machine, not of the code. Its whole margin was measured at one clock tick on this container, and it had already reddened CI on an unrelated diff with entirely correct stamping. The gap between updates is now forced and, more importantly, verified by re-reading the clock rather than trusting a timer, so the distinctness the section asserts is entailed by the spacing rather than hoped for. The assertion got stronger in the process (ROUNDS spaced updates must yield ROUNDS distinct stamps, where the old cell asked for two out of six), and the failure message now carries the measured gaps, the measured span and the arithmetic that rules a fast runner out -- so the red discriminates itself instead of being byte-identical to the defect it guards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o
…ss vacuously Math.min() of an empty list is Infinity, so a loop that stopped spacing its updates would satisfy the gap assertion instead of failing it. Pin the count of intervals as well as their size. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-warren
marked this pull request as ready for review
August 25, 2026 09:37
Uh oh!
There was an error while loading. Please reload this page.
os-warren
deleted the
claude/issue-11572-update-stamp-precision-determinism
branch
August 25, 2026 10:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#11572
The number the card asked for, before any edit
The card said the frequency was unmeasured — one observation on one runner — so this
started by counting. Three measurements on this container, all on the SQLite cell (no
live PG/MySQL is provisioned here, so those two cells report as named skips):
ROUNDS(6) sqlite update+read round-trips, warm path, 2000 trialssize=2(12 runs),3(18),4(8),5(2)size=2, span=1 ms§3 asserted
size > 1. So on this hardware nearly a third of runs cleared the bar by asingle millisecond, and a machine one tick faster lands on
size === 1— which is whatCI reported on PR #11570, a diff touching no file under
packages/drivers/.That is the whole case for building something rather than re-running: the guard's margin
was never more than one tick, and its red is byte-identical to the defect it guards.
What was built — direction 1, done so the assertion gets stronger
The clock is now driven and verified rather than raced.
awaitClockAdvance()re-reads the clock and keeps waiting until the clock itself agrees the gap elapsed, so §3
never assumes a tick happened — a timer is a request, and what the cell needs is a fact.
MIN_GAP_MS = 5is sized against both bounds §3 sits between: 5x above the millisecondthe audit columns are declared at, and three orders of magnitude below the second
truncation would need.
The assertion got stronger, not weaker:
ROUNDSspaced updates must now yieldROUNDSdistinct stamps, where the old cell asked for two out of six. §1, §2 and thespan < 1_000non-vacuity guard are untouched.Coverage traded away, stated plainly: §3 no longer fires its updates at the machine's
maximum write rate — there is now ~5 ms of idle between them. That coverage did not leave
the file. §1, §1b and §2 still create and update with no sleep between them ("No sleep and
no backdating", §1), so the same-millisecond path stays measured where it belongs.
Resolution — §3's actual subject — is not a rate property.
A second, smaller guard: the count of intervals is pinned as well as their size, because
Math.min()of an empty list isInfinity, so a loop that stopped spacing its updateswould have satisfied the gap bound instead of failing it.
The closing condition: the failure now discriminates itself
Previously the discriminator was "a genuine regression reds §1, §2 and §3; a fast run
reds only §3" — knowledge living in a docblock and in a human comparing sections. §3's
failure message now carries the measured evidence and does the arithmetic itself. Actual
output, captured under ablation B below:
Compare the old text it replaces:
expected 1 to be greater than 1.No
.skip, no quarantine, no retry, and no counted-skip bookkeeping — direction 1 removesthe probabilistic arm outright, so there is no skip to count.
Reverse verification — direction predicted in writing before either run
Both mutations were proven on disk by anchored grep counts of the text actually
changed (removed-text occurrences → 0, injected marker → 1) before any result was read,
and both were restored under
trap … EXIT INT TERMviagit checkout HEAD --given the file's ABSOLUTE path (never a repo-relative one after acd, and nevergit checkout --alone, which restores from the index the mutation stepitself wrote). Restore was then verified rather than trusted:
git hash-objectof theworking file equalled
git rev-parse HEAD:that same path — both6c12539f68c3266d371b0c0279d35c0be1cd6b8e— withgit status --porcelainempty.No rebuild is involved, and that is mechanical rather than assumed: the test reaches
the driver by a relative import (
./index.js→./sql-driver.js), andpackages/drivers/driver-sql/distdoes not exist in this worktree at all — only thedependency closure was built. A dist-resolved ablation could not have run here.
Ablation B — the defect class on the cell that is actually runnable.
Mutation: the SQLite branch truncated to whole seconds
(
new Date().toISOString()→.replace(/\.\d{3}Z$/, '.000Z')).Predicted: RED in three sections — §1, §2, §3 — with §4/§5 green.
Observed: RED in four — §1, §1b, §2, §3; §4 and §5 green (the
ISO_Zshape admits.000Z). The direction was as predicted; §1b, the bulk-door twin of §1, wasunder-enumerated in the prediction and also reds. The rebuilt §3 fails on the real defect,
and fails distinguishably — the message above is its output.
Ablation A — the card's literal ask, and an honest negative result.
Mutation:
main's pre-#11224 body restored(
this.isMysql ? this.knex.fn.now(3) : this.knex.fn.now()→this.knex.fn.now()).Predicted: NO CHANGE — the SQLite cell stays green.Observed: green, vitest exit 0.
This is not evidence the guard works: #11224 changed only the NON-sqlite branch, so
restoring
main's body is a no-op on the only cell this container can run. The file'sown docblock already says the reverse verification reds "on the live MySQL cell ONLY".
Ablation B is what makes A's green readable as a genuine no-op rather than an unreached
mutation — same file, same edit mechanism, and B reds.
The head docblock now records both, so the next reader is not left to rediscover that the
documented ablation is inert without a live MySQL.
Verification — all at the final commit
32638fbd3fEvery exit code captured before any pipe; each family's own verdict line quoted.
pnpm --filter @objectstack/driver-sql typecheck—tsc --noEmit, no output, exit 0Test Files 1 passed (1),Tests 7 passed | 2 skipped (9)(the 2 skips are the unprovisioned live cells)Test Files 131 passed | 8 skipped (139), 0 FAIL[#11572]messages, zero FAIL lines. A 33rd run was cut off mid-startup by the container's ~10-minute foreground cap (its log ends at the vitest banner, never reaching an assertion) — reported as a harness event, not a test outcome. Because the assertion istoBe(ROUNDS), each green is the statement that the run observed exactly 6 distinct stamps.pnpm lint— run in full, not narrowed:eslint . --no-inline-config, 5154 files, 0 errors, 0 warnings,VERDICT command-exit 0Gate union derived, not recalled (
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack,re-derived at
32638fbd3f; 8 path-matched + theadds or edits a test fileconvention kind).All green:
check:driver-conformanceOK — 45 covered cell(s), 0 in the DEBT ledger, 0 exempt.check:published-files✓ … 69 publishable package(s) of 78 workspace member(s) …check:slot-lookup✓ slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new·baseline key set verified against 8450eea: no files added.check:test-source-aliasOK — 72 packages with tests scannedcheck:type-source-resolutionOK — 93 tsc program(s) across 77 packages scannedcheck-plugin-teardown-shape✓ … 63 Plugin implementation(s) across 4675 source(s)check-affected-docs/check-drift-comment✓ check-drift-comment: 56 cases pass across 5 fixture diff(s).check:query-options-erasure✓ query-options-erasure ratchet holds: … none new·baseline key set verified against 8450eea: no files added.check:type-check-coverageOK — 65/78 workspace packages type-checkedcheck:engine-double-contractOK — 408 pinned, 133 in the DEBT ledger, 2 exempt.check:cross-package-test-inputsOK: 16 package(s) read outside themselves, all declaredcheck:where-matcher0 silently-wrong and 0 unjudged matcher(s) … none new.·baseline key set verified against 8450eea: no files added.check-nul-bytesOK (scanned 6707 text file(s) … no raw ASCII control bytes)Changeset
None — graded against
check-empty-changeset.mjs's own rule rather than assumed. Itsheader states the route directly: for a PR that releases nothing, "delete the changeset
and apply the
skip-changesetlabel"; an empty-frontmatter changeset is a real inputto
changesets/actionand an all-empty set stalls the release silently and greenly(#4898). This diff is one test file — no shipped behaviour, no public export moves — so it
takes the label and writes no
.changeset/*.md.Scope
One file:
packages/drivers/driver-sql/src/sql-driver-11224-update-stamp-precision.test.ts.No
sql-driver.tssource edit — the two mutations above were ablation-only and bothrestored byte-identically. The measurement found no evidence the product stamping is
wrong: §1, §2, §4, §5 and §6 are green throughout on the unmutated tree.
Generated by Claude Code