Skip to content

ci(smoke): date the main-thread block with a heartbeat - #1416

Merged
FerroxLabs merged 1 commit into
mainfrom
ci/main-thread-heartbeat
Sep 20, 2026
Merged

FerroxLabs merged 1 commit into
mainfrom
ci/main-thread-heartbeat

Conversation

@FerroxLabs

Copy link
Copy Markdown
Owner

#1415 established WHICH side hangs on win32-arm64. This dates WHAT blocks it.

Where the investigation stands

readiness stall diagnostics: targets=1 [page:file:///C:/.../wayland-install]
| browser endpoint did NOT answer (CDP command timed out: Browser.getVersion)
- the main process is blocked, not the renderer

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

  • win-arm64 passes, and v0.13.2 tags immediately
  • the heartbeat gaps, and names what ran immediately before the block
  • the heartbeat ticks straight through the failure, which falsifies the model - the main thread would not be blocked after all, and the browser endpoint would be unanswered for some other reason

Verification

  • 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"; 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

A watchdog that cannot fail would be worse than no watchdog, hence mutating both halves rather than one.

🤖 Generated with Claude Code

#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>
@github-actions github-actions Bot added the area:core Wayland Core engine / backends label Sep 20, 2026
@FerroxLabs
FerroxLabs merged commit 1c720cc into main Sep 20, 2026
24 checks passed
@FerroxLabs
FerroxLabs deleted the ci/main-thread-heartbeat branch September 20, 2026 06:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core Wayland Core engine / backends

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant