Context
Witnessed during #16425's pane leg (2026-08-03): the first DockFlip repair iteration used a 100ms main-thread timer dam to bound frame waits — sound under the synthetic rig (timers unclamped), but in the GENUINELY hidden agent pane the dam's setTimeout ticks were visibility-clamped and startTour sat wedged-in-practice for minutes (tourRunner.running: false, idle caption across 4 polls) until a document.hidden entry discriminator replaced waiting entirely for the hidden class.
The general law this exposed: main-thread timers are not starvation-proof carriers. Hidden documents clamp nested timers to >=1s/tick immediately, and intensively throttle chained timers to ~1 wake/minute once the page has been hidden >5 minutes (Chrome's budget-based intensive throttling). Workers are exempt — a dedicated/shared worker has no document and its timers never clamp.
The Problem
Every main-thread carrier that exists specifically to serve rendering-starved documents inherits the clamp it is trying to route around:
- ResizeObserver addon hidden poll (
src/main/addon/ResizeObserver.mjs — pollHiddenTargets re-arming via chained main-thread timers, observed in the #16425 probe stacks at :333-347): the poll is ARMED exactly when document.hidden === true — the same condition that clamps it. At the >5min horizon the geometry cadence for a hidden pane plausibly degrades toward one delivery per minute. NOT yet measured at that horizon — the >=1s clamp tier is witnessed, the 1/min intensive tier is documented browser policy awaiting a direct receipt. Fleet-cockpit panes and agent windows live hidden for HOURS, so the horizon is the common case, not the edge.
- DockFlip timer dam (
#nextFrame, landing via #16425): the hidden class now bypasses it via the entry discriminator; the dam remains the carrier for the occluded-but-visible class, whose timers are unclamped — correct by construction. Recorded here as the pattern precedent: dam-for-occluded + discriminator-for-hidden.
- Any future main-side timer cadence serving hidden documents will re-discover this law the hard way without a recorded audit trail.
The Architectural Reality
The starvation carrier hierarchy, by environment:
- Hidden documents (
document.hidden === true): rAF dead, RO deliveries dead, main timers clamped (>=1s, then ~1/min). Surviving carriers: postMessage delivery, and APP-WORKER timers (workers have no document). A hidden-document cadence must originate in a worker and ping main, or the hidden path must not wait at all (discriminator → instant/degraded-mode path).
- Occluded-but-visible windows: rAF dead, RO dead, main timers at normal clamps. Main-side timer dams are valid here.
- Presenting documents: everything lives; rAF is the fastest correct signal.
The Fix
- Instrument the RO addon hidden-poll cadence in a genuinely hidden pane past the 5-minute intensive-throttling horizon (pane route documented on #16402/#16425); record the measured inter-delivery gap.
- If the intensive tier bites (expected): relocate the poll's CADENCE to the app-worker side — a worker timer pings main (postMessage) to execute one poll pass; main keeps the measurement + synthetic-entry dispatch it owns today. Alternatively a visibility-keyed cadence downgrade with an explicit contract, if measurement shows the degraded cadence is acceptable for hidden-pane consumers.
- Encode the carrier hierarchy above at the owning seam's JSDoc (the RO addon class doc is the natural anchor, echoing the DockFlip two-layer doc) so the next starvation repair starts from the law instead of re-deriving it.
Acceptance Criteria
Out of Scope
- The overflow cue's starved leg — #16434.
- DockFlip choreography — #16425 (the discriminator+dam pattern already landing there).
- Orchestrator-side starvation cause taxonomy — #16382 (Vega's lane; conceptually adjacent, different substrate).
Related
Related: #16402 · #16425 · #16434 · #16382
Live latest-open sweep: checked latest 20 open issues at 2026-08-03T10:57Z; no equivalent found. A2A in-flight claim sweep: latest 30 messages spanning the herd window — no overlapping claim (#16382 is orchestrator-substrate starvation detection, different seam).
Origin Session ID: f01a83b0-dab9-4fa9-a3a1-279f3e2336dd
Retrieval Hint: "main-thread timer visibility throttling starvation carrier hidden poll cadence"
Context
Witnessed during #16425's pane leg (2026-08-03): the first DockFlip repair iteration used a 100ms main-thread timer dam to bound frame waits — sound under the synthetic rig (timers unclamped), but in the GENUINELY hidden agent pane the dam's
setTimeoutticks were visibility-clamped andstartToursat wedged-in-practice for minutes (tourRunner.running: false, idle caption across 4 polls) until adocument.hiddenentry discriminator replaced waiting entirely for the hidden class.The general law this exposed: main-thread timers are not starvation-proof carriers. Hidden documents clamp nested timers to >=1s/tick immediately, and intensively throttle chained timers to ~1 wake/minute once the page has been hidden >5 minutes (Chrome's budget-based intensive throttling). Workers are exempt — a dedicated/shared worker has no document and its timers never clamp.
The Problem
Every main-thread carrier that exists specifically to serve rendering-starved documents inherits the clamp it is trying to route around:
src/main/addon/ResizeObserver.mjs—pollHiddenTargetsre-arming via chained main-thread timers, observed in the #16425 probe stacks at :333-347): the poll is ARMED exactly whendocument.hidden === true— the same condition that clamps it. At the >5min horizon the geometry cadence for a hidden pane plausibly degrades toward one delivery per minute. NOT yet measured at that horizon — the >=1s clamp tier is witnessed, the 1/min intensive tier is documented browser policy awaiting a direct receipt. Fleet-cockpit panes and agent windows live hidden for HOURS, so the horizon is the common case, not the edge.#nextFrame, landing via #16425): the hidden class now bypasses it via the entry discriminator; the dam remains the carrier for the occluded-but-visible class, whose timers are unclamped — correct by construction. Recorded here as the pattern precedent: dam-for-occluded + discriminator-for-hidden.The Architectural Reality
The starvation carrier hierarchy, by environment:
document.hidden === true): rAF dead, RO deliveries dead, main timers clamped (>=1s, then ~1/min). Surviving carriers: postMessage delivery, and APP-WORKER timers (workers have no document). A hidden-document cadence must originate in a worker and ping main, or the hidden path must not wait at all (discriminator → instant/degraded-mode path).The Fix
Acceptance Criteria
Out of Scope
Related
Related: #16402 · #16425 · #16434 · #16382
Live latest-open sweep: checked latest 20 open issues at 2026-08-03T10:57Z; no equivalent found. A2A in-flight claim sweep: latest 30 messages spanning the herd window — no overlapping claim (#16382 is orchestrator-substrate starvation detection, different seam).
Origin Session ID: f01a83b0-dab9-4fa9-a3a1-279f3e2336dd
Retrieval Hint: "main-thread timer visibility throttling starvation carrier hidden poll cadence"