perf(renderer): stop six timers from ticking behind a hidden window (#18134)

* perf(renderer): stop six timers from ticking behind a hidden window

IntensiveWakeUpThrottling is disabled in this app, so a renderer interval
really does fire at full rate with the window hidden. Six of them had
nothing to observe them:

- NativeChatWorkingStatus ran a 1s interval + setState per in-flight turn
  purely to advance an elapsed-seconds counter. Deleted the effect and
  derived elapsed during render from the shared, visibility-gated
  useNow(1_000) clock, so N turns collapse onto one tick.
- The chromium-error fallback poll (250ms) kept probing a stuck-loading
  guest to write a loadError nobody could see.
- The contextual-tour full-pass interval (500ms) woke twice a second to
  queue a rAF a hidden window never paints.
- Three feature-wall animation timers (3600/2400/2400ms) kept committing
  React renders for animations nobody was watching.
- The landing preflight poll (30s) kept forcing IPC refreshes.

All five gated timers reuse installWindowVisibilityInterval. Each either
resumes where it left off (animations) or re-derives from durable state on
the becoming-visible run, so hiding and re-showing is observationally
identical to never hiding.

* test(git): stop two empty commits in the divergence fixture from hashing alike

`counts drift in both directions` builds 100 empty commits, resets to the fork
point, then adds one more — expecting 100 ahead + 1 behind to clear the cap of
100. An empty commit's hash covers only parent, tree, message and a
one-second-granularity timestamp, and every commit in the fixture reuses
`commit ${index}` starting from 0. On a runner fast enough to finish the whole
build inside one wall-clock second (CI: 1059ms for the case, ~7ms per commit),
the post-reset `commit 0` hashed identically to the first `commit 0` of the
chain, so Git handed back that same object and left the branch 99/0 apart
instead of 100/1 — `within`, not `exceeded`.

Numbering the empty commits across calls makes the fixture build the 101
distinct commits it already claimed to. Reproduced deterministically by pinning
GIT_AUTHOR_DATE/GIT_COMMITTER_DATE, which forces the timestamp collision the
fast runner hits by chance: fails with the exact CI assertion before, passes
after.
This commit is contained in:
Neil
2026-09-02 14:35:48 -07:00
committed by GitHub
parent 6d8dc0c97a
commit 02a417c04b
13 changed files with 534 additions and 49 deletions
@@ -32,9 +32,17 @@ async function createRepo(): Promise<string> {
return repoPath
}
// Why unique across calls: an empty commit's hash covers only parent, tree, message and a
// one-second-granularity timestamp. On a fast runner the whole 100-commit build finishes inside
// one second, so a post-reset `commit 0` off the same fork point hashed identically to the first
// `commit 0` of the chain and Git handed back that same object — leaving the branch 99/0 apart
// instead of 100/1.
let emptyCommitSequence = 0
function commitEmpty(repoPath: string, count: number): void {
for (let index = 0; index < count; index += 1) {
git(repoPath, ['commit', '--quiet', '--allow-empty', '-m', `commit ${index}`])
emptyCommitSequence += 1
git(repoPath, ['commit', '--quiet', '--allow-empty', '-m', `commit ${emptyCommitSequence}`])
}
}