Skip to content

menubar: skip unchanged background refreshes, 120s AC idle cadence, utility QoS for tick spawns#704

Merged
iamtoruk merged 1 commit into
getagentseal:mainfrom
avs-io:fix/703-menubar-idle-energy
Jul 16, 2026
Merged

menubar: skip unchanged background refreshes, 120s AC idle cadence, utility QoS for tick spawns#704
iamtoruk merged 1 commit into
getagentseal:mainfrom
avs-io:fix/703-menubar-idle-energy

Conversation

@avs-io

@avs-io avs-io commented Jul 16, 2026

Copy link
Copy Markdown
Member

Problem

Items 2-4 of #703: even with #648's work, an idle menubar on AC still spawns a full Node re-parse every ~60s (measured ~10 CPU-s each, ~16% of a core sustained on a real user machine; details and raw numbers in #703). Items 1 (release) and 5 (CLI incremental parse) are intentionally not addressed here.

Fix

  1. Change-detection guard (Data/UsageDataChangeGuard.swift): before a background tick spawns the CLI, a shallow snapshot (root + first-level directory mtimes — deliberately not a recursive walk) of the provider data roots is compared against the snapshot taken at the last successful fetch; unchanged → skip the spawn. Interactive paths (popover open, Refresh Now) always bypass. The snapshot anchors only on fetch success, so failures can't mask changes. Backstop: unchanged-skips are honored for at most 30 minutes — the hand-maintained root list is a perf optimization, not a correctness contract; a provider missing from it degrades to a 30-minute refresh, never stale-forever.
  2. AC idle cadence (RefreshCadence.swift): closed-popover Auto on AC moves from 30s to 120s (battery 150s / low-power 300s from menubar: cut idle energy (video-call-class drain, fixes #647) #648 unchanged; popover-open stays 30s). Settings label updated.
  3. QoS (Security/CodeburnCLI.swift, threaded through DataClient/AppStore): background tick spawns run .utility (E-cores); interactive fetches keep .userInitiated.

Combined with the guard, an idle machine goes from ~120 spawns/hour (post-#648 AC behavior) to at most 2/hour, and genuine refreshes land on efficiency cores.

Tests

  • UsageDataChangeGuardTests (swift-testing): fresh-skip, stale-no-skip, first-run, force-bypass, and the 30-minute backstop boundary.
  • RefreshCadenceTests updated to pin the 120s closed-popover AC value.

Verification

swift build clean (Swift 6.3.3 toolchain). Test targets need XCTest (Xcode/CI) to execute — same constraint as #702.

Part of #703 (items 2-4).

@avs-io
avs-io marked this pull request as ready for review July 16, 2026 21:01
@avs-io
avs-io requested a review from iamtoruk July 16, 2026 21:01

@iamtoruk iamtoruk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally: swift build green, 81 tests across 17 suites green, and both load-bearing behaviors are mutation-pinned; inverting the change comparison and removing the 30-minute backstop each fail the guard tests, including the dedicated backstop-expiry case. The design reads right: the shallow snapshot is a perf optimization with the backstop as the correctness contract, interactive refreshes always bypass, and anchoring only on fetch success means failures cannot mask changes. The Swift-side provider root list duplicating TS path logic is unavoidable cross-language and is exactly what the backstop bounds. The CPU reduction figures rest on the #703 measurements; the mechanism they depend on is what is verified here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants