feat(webviews): report visible page loops

TE
6d ago
+282-0

Summary

“cmuxDebug.loops reporting and hidden_loops==0 gate, shared visible page clock if absent.”

Adds a read-only window.cmuxDebug.loops() diagnostic to the shared desktop bootstrap, visible-page clock primitives, and a common hidden-page CSS animation pause. The browser regression exercises the real diagnostic and visibility listener across hide/show, asserting hidden_loops == 0.

The diagnostic counts registered page clocks and running infinite DOM animations.

window.cmuxDebug.loops is an intentional, read-only production diagnostic: it computes only when called, installs no listener or timer of its own, and exists so the live hidden_loops gate can read pages. It does not intercept arbitrary timers; existing clock consumers and ChangesStatus timers are separate follow-ups. parked exposes the host's initial pooled-page marker, not a new claim lifecycle. Native #24806 is separate.

Validation

Published head: d0022855faa5bd345e310175738d56c29dad3d0a.

cmux-ci run 41125624718 completed successfully: page-clock.test.ts and static-status-loops.test.ts recorded 12 passing tests, 0 failures, and 40 assertions. The receipt tested the published head exactly.

Performance

metricbeforeafterdeltaharness
Running infinite CSS animations in hidden fixture90-9Same Chromium fixture, measurement run
Running infinite CSS animations in visible fixture990Same fixture and run

Baseline CSS is byte-identical to 844a99b91c474ef412604e2412ab157377d9654c (SHA256 9a4e6a464ba411642bbe2c52605bce9f0db29254bdf4c6bf548823ac80a5b4b2). These observed numbers were collected at 7832b156; the fixture inputs are unchanged; the root selector broadens hidden pause coverage. The root-selector change is covered by the final-head focused browser run. This measures the CSS fixture only; no CPU, wakeup, or application-wide timer reduction is claimed.

Timer ownership and cleanup:

  • visibleInterval clears its timeout when the document becomes hidden and starts a fresh deadline on show; disposal clears the timeout, removes the visibility listener, and unregisters the clock.
  • Shared second/minute clocks release their interval and listener when the last subscriber leaves.
  • Diagnostics run only when called and add no polling timer or observer.

Before / after

Before/after fixture screenshot artifact: base-visible.png, head-visible.png, and the corresponding hidden captures.

I viewed the after image and the before fixture: the visible layout and styles are unchanged. These are synthetic CSS fixtures, not full application screenshots.

Changelog

Added visible-page loop diagnostics and shared timer primitives; hidden desktop pages pause CSS animations.

Agent session: agent session