ci(smoke): date the main-thread block with a heartbeat - #1416
Merged
Merged
Conversation
#1415 established WHICH side hangs on win32-arm64: Browser.getVersion on the browser endpoint went unanswered while the DevTools HTTP endpoint still served /json/list, so the main process's JS thread is blocked, not the renderer. It did not establish WHAT blocks it. Agent detection is already excluded - it completes in 12278ms and the block outlives it, and the app's last line is kickoff.telemetry about 12s after window creation, then silence for the remaining 600s. A blocked JS thread cannot fire its own timer, so the timer is the probe. A tick arriving late by more than its own period measures a stall the event loop actually suffered; the last tick before silence dates a block that never ends, which is enough to name whatever logged just before it. Gated on WAYLAND_PACKAGE_SMOKE_MARKER, which only the packaged smoke sets, so no shipped run pays for it. Extracted to its own module rather than buried in index.ts so it can be tested at all - the same reason describeDirtyShutdown was extracted. Gates: full unit suite 1769 passed 0 failed, typecheck 0, scoped oxfmt clean, oxlint 0 warnings. Mutation-proven on BOTH halves: removing the smoke gate fails with "expected [Function] to be null", and disabling stall detection fails because the stall logs as an ordinary tick. A fourth test pins that ordinary timer jitter is NOT reported as a stall, so the warning means something when it appears. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 free
to 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.
#1415 established WHICH side hangs on win32-arm64. This dates WHAT blocks it.
Where the investigation stands
The DevTools HTTP endpoint still served /json/list in that same failure, which is served without the main JS thread. So the main process's JS thread is blocked.
What is already excluded: agent detection. It completes in 12278ms and the block outlives it. The app's last log line is kickoff.telemetry about 12s after window creation, then silence for the remaining 600s of the readiness window.
The probe
A blocked JS thread cannot fire its own timer, so the timer is the measurement. A tick that arrives late by more than its own period measures a stall the event loop genuinely suffered. The last tick before silence dates a block that never ends, which is enough to name whatever ran immediately before it.
Gated on WAYLAND_PACKAGE_SMOKE_MARKER, set only by the packaged smoke, so no shipped run pays for it.
Extracted into its own module rather than left inline in index.ts so it can be tested at all. That is the same reason describeDirtyShutdown was extracted.
Three outcomes, all useful
Verification
A watchdog that cannot fail would be worse than no watchdog, hence mutating both halves rather than one.
🤖 Generated with Claude Code