Skip to content

test(room-invite-preview): freeze the clock the render reads - #1840

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-invite-preview-clock-once
Oct 30, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-invite-preview-clock-once

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1839

Owner: Dev2
Written-by: Dev-2
Reviewer: Reviewer
Claim-Id: a497345b7dd544c0b87a56a96d6217cc
Base: f245520
Tip SHA: 3b8d239
Tree: 25d3f899aec104f2a0f95a83568bde15a1ea6a20
Diff: 2 files, +38/−18

What changed

core/test/room-invite-preview.test.js drew the card — the render itself calls Date.now()
inside inviteCountdown — and then compared the deadline line against
inviteCountdownAt(preview.expiresAt, 0, Date.now()). Two independent clock reads: when a
second boundary falls between them the expectation is one second ahead of the drawn line, so
the case flakes. Seen once on f245520c in a full verify as 37958984:53 left to join against
:52; 60 single-file runs never reproduced it.

The case now reads the clock once and freezes it for the whole assertion — one instant drives
both the render and the expectation:

const realNow = Date.now
const frozen = realNow()
Date.now = () => frozen
try {
  const tree = RoomInvitePreview({ h, preview, onJoin() {}, onClear() {} })
  // …
  assert.equal(tree.children[3].children.join(''), inviteCountdownAt(preview.expiresAt, 0, frozen))
  // …
} finally {
  Date.now = realNow
}

No tolerance: the comparison is still exact text at one instant, so a genuine off-by-one inside
inviteCountdown still fails. No production change — core/src/client/room-invite-preview.js
is untouched and no clock parameter is added.

patches/ds-bot/files/test/room-invite-preview.test.js is the whole-file mirror, byte-identical
(sha1 c172eb851f7b45b07b843fd90b61b04cf5569b35 both sides). No .patch regeneration and no
topics.json change: this file is a whole-file mirror, not an edited upstream file.

Red first

Probe 1 — the current assertion is clock-sensitive. Clock advanced 1000 ms per read, current
case unchanged, restored in finally:

not ok 1 - \#876: the card names the room, its lead, its people and the deadline
  + '37958977:48 left to join'
  - '37958977:47 left to join'
# tests 5
# pass 4
# fail 1

Probe 2 — the fixed assertion is immune and not vacuous:

  • frozen clock, file as committed: # tests 5 / # pass 5 / # fail 0.
  • the same case with the expectation mutated by one second (frozen - 1000) must fail, and does:
not ok 1 - \#876: the card names the room, its lead, its people and the deadline
  expected: '37958977:46 left to join'
  actual: '37958977:45 left to join'
# tests 5
# pass 4
# fail 1

200 consecutive runs of the file at this tip: runs=200 failures=0 elapsed=36s.

Verification at the tip

Ran: at 3b8d23941035fd80dc757f8982519480c40d0a30 (tree 25d3f899), git status --porcelain
empty before and after:

$ TZ=UTC ARCH_DOCS_BASE=f245520cbbcb7de1931a91c07c675e20dbe9fc79 npm run verify
$ node scripts/ds-bot-patches.mjs check
  • core: 2203/2203 pass, including test/room-invite-preview.test.js 5/5
  • plugins social 541/541, tree 127/127, timeline 135/135, workflow 294/294
  • .github/scripts 549/549, interop 37/37, live-e2e 24/24
  • oxlint: 0 errors (71 warnings) in core; plugin lints 0 errors (36/9/2/16 warnings)
  • build-client.mjs --check: clean
  • arch-docs: OK (2 changed file(s)), ARCH_DOCS_BASE=f245520cbbcb7de1931a91c07c675e20dbe9fc79
  • patch chain:
ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

One honest note on the run: the first full verify at this tip went red on an unrelated file —
core/test/room-external.test.js:79, "timed out waiting for the child" after 4.1 s — not on
anything this change touches; that file alone passed 3/3 afterwards and the rerun above is
green. Recorded rather than hidden.

Not run: the smoke bench (no index.js/src/host/ change), the CI package job (pack check,
typecheck, actionlint) and the merge-queue rebuild.

Checkpoint

{
  "pr": 1840,
  "claim": "Dev2",
  "issue": 1839,
  "summary": "The room-invite preview case drew the card, whose render reads Date.now() inside inviteCountdown, then compared the line against a second Date.now() read, so a second boundary put the expectation one second ahead. The case now reads the clock once, freezes it for the whole assertion and restores it in finally; the comparison stays exact text with no tolerance and no production file changes. An advancing-clock probe fails on the old assertion and passes on the new one, a one-second mutation still fails, 200 runs stayed clean. The whole-file mirror under patches/ds-bot/files is byte-identical.",
  "files": [
    "core/test/room-invite-preview.test.js",
    "patches/ds-bot/files/test/room-invite-preview.test.js"
  ],
  "checks": {
    "ran": "TZ=UTC ARCH_DOCS_BASE=f245520c npm run verify; node scripts/ds-bot-patches.mjs check; 200x node --test test/room-invite-preview.test.js",
    "result": "green",
    "at": "3b8d23941035fd80dc757f8982519480c40d0a30"
  },
  "next": "none — ready for review"
}

The card's deadline case rendered with Date.now() inside inviteCountdown and
then compared against inviteCountdownAt(..., Date.now()) - two independent
reads, so a second boundary between them made the expectation one second
ahead of the drawn line. It was seen once as "37958984:53 left to join"
against ":52" and never reproduced in 60 single-file runs (ThinkFlowLab#1839).

Read the clock once, freeze it for the whole case and drive both the render
and the expectation from that instant; restore the real clock in finally.
No tolerance and no production change: the assertion still compares exact
text, so an off-by-one inside the countdown would still fail.

Docs-not-needed: test-only; no subsystem behaviour or owned path changes.

Fixes ThinkFlowLab#1839
@Birfy
Birfy added this pull request to the merge queue Oct 30, 2026
Merged via the queue into ThinkFlowLab:main with commit 6cf554e Oct 30, 2026
14 of 15 checks passed
@Birfy
Birfy deleted the dev/2-invite-preview-clock-once branch October 30, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test flake: room-invite-preview compares a rendered countdown against a second Date.now(), losing a second at the boundary

2 participants