Merge pull request #867 from marcreynolds/feat/menubar-degraded-device-indicator

feat(menubar): mark badge when a paired device is unreachable in combined scope
This commit is contained in:
Resham Joshi 2026-08-03 12:35:17 -07:00 committed by GitHub
commit dc3ea24b1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 86 additions and 1 deletions

View file

@ -285,6 +285,17 @@ final class AppStore {
return cache[menubarCombinedKey]?.payload.combined?.combined
}
/// `(reachable, total)` only when combined scope is active and fewer paired
/// devices reported than are paired i.e. the badge total is degraded to
/// the reachable subset (a peer is asleep/off-network this cycle). The badge
/// shows this so a momentary drop to the local figure reads as "peer
/// unreachable", not a glitch. `nil` when every paired device reported (or
/// there is only one), and under local scope.
var menubarBadgeDeviceShortfall: (reachable: Int, total: Int)? {
guard let totals = menubarBadgeCombined, totals.reachableCount < totals.deviceCount else { return nil }
return (totals.reachableCount, totals.deviceCount)
}
/// Refresh the payloads the badge renders for `period`: always the local
/// figure, plus the combined cross-device total when combined scope is
/// active. Combined is best-effort a slow or unreachable peer degrades to

View file

@ -1058,10 +1058,27 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate, NSM
textAttrs[.foregroundColor] = NSColor.secondaryLabelColor
}
composed.append(NSAttributedString(string: valueText, attributes: textAttrs))
// Combined scope, but a paired device didn't report this cycle: append
// a dimmed "reachable/total" so the reduced total reads as "peer
// unreachable" rather than a glitch (mirrors the popover's device list).
if let shortfall = store.menubarBadgeDeviceShortfall {
let marker = " · \(shortfall.reachable)/\(shortfall.total)"
let markerAttrs: [NSAttributedString.Key: Any] = [
.font: font,
.baselineOffset: -1.0,
.foregroundColor: NSColor.secondaryLabelColor,
]
composed.append(NSAttributedString(string: marker, attributes: markerAttrs))
}
}
button.attributedTitle = composed
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel)"
if let shortfall = store.menubarBadgeDeviceShortfall {
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel) · \(shortfall.reachable) of \(shortfall.total) devices reporting"
} else {
button.toolTip = "CodeBurn \(menubarPeriod.menubarMetricLabel)"
}
persistBadgeStatusFile()
}

View file

@ -234,6 +234,63 @@ struct AppStoreRefreshRecoveryTests {
#expect(store.menubarBadgeCombined?.cost == 75)
}
@Test("badge reports a device shortfall when a paired peer is unreachable")
func menubarBadgeReportsDeviceShortfall() {
let store = AppStore()
store.suppressRefreshesForTesting()
let period = store.menubarPeriod
// Combined payload where only 1 of 2 paired devices reported this cycle
// (the peer is asleep/off-network), so the aggregate is degraded to local.
let degraded = CombinedUsage(
perDevice: [],
combined: CombinedUsageTotals(
cost: 30,
calls: 3,
sessions: 2,
inputTokens: 100,
outputTokens: 50,
cacheCreateTokens: 10,
cacheReadTokens: 20,
totalTokens: 180,
deviceCount: 2,
reachableCount: 1
)
)
store.setCachedPayloadForTesting(
menubarPayload(cost: 30, combined: degraded),
scope: .combined,
period: period,
provider: .all,
fetchedAt: Date()
)
store.selectedScope = .combined
let shortfall = store.menubarBadgeDeviceShortfall
#expect(shortfall?.reachable == 1)
#expect(shortfall?.total == 2)
}
@Test("badge reports no shortfall when every paired device reports")
func menubarBadgeNoShortfallWhenAllReachable() {
let store = AppStore()
store.suppressRefreshesForTesting()
let period = store.menubarPeriod
// combinedUsage() carries deviceCount == reachableCount == 1.
store.setCachedPayloadForTesting(
menubarPayload(cost: 30, combined: combinedUsage(cost: 30)),
scope: .combined,
period: period,
provider: .all,
fetchedAt: Date()
)
store.selectedScope = .combined
#expect(store.menubarBadgeDeviceShortfall == nil)
// Local scope never reports a shortfall.
store.selectedScope = .local
#expect(store.menubarBadgeDeviceShortfall == nil)
}
@Test("menubar badge falls back to local when no combined payload is cached")
func menubarBadgeFallsBackWhenCombinedMissing() {
let store = AppStore()