58 lines
2.4 KiB
Swift
58 lines
2.4 KiB
Swift
import AdaptiveRefreshCore
|
|
import Foundation
|
|
|
|
/// Replay adapter for the same canonical policy core used by the CodexBar app.
|
|
public struct AdaptiveReplayPolicy: ReplayPolicy, Sendable {
|
|
public let name = "adaptive"
|
|
|
|
/// Matches `UsageStore.noteMenuOpened(at:)`'s adaptive-only advance guard: this is the one
|
|
/// baseline that actually models the interaction-advance path, so it is the only one that
|
|
/// overrides the protocol's `false` default.
|
|
public let advancesOnInteraction = true
|
|
|
|
public init() {}
|
|
|
|
public func decide(_ input: ReplayPolicyInput) -> ReplayPolicyDecision {
|
|
let decision = AdaptiveRefreshPolicyCore().nextDelay(for: AdaptiveRefreshPolicyCore.Input(
|
|
now: input.now,
|
|
lastMenuOpenAt: input.lastMenuOpenAt,
|
|
lowPowerModeEnabled: input.lowPowerModeEnabled,
|
|
thermalPressure: input.thermalState.isConstrained ? .constrained : .nominal))
|
|
return ReplayPolicyDecision(
|
|
delaySeconds: TimeInterval(decision.delay.components.seconds),
|
|
reason: decision.reason.rawValue)
|
|
}
|
|
}
|
|
|
|
/// A fixed-cadence baseline: always waits the same interval, regardless of signals. Used to
|
|
/// compare the adaptive policy against the flat refresh frequencies CodexBar also offers
|
|
/// (2/5/15/30 minutes). Never advances on interaction (`advancesOnInteraction` stays the protocol
|
|
/// default of `false`), matching the real app: fixed-cadence refresh frequencies never wire up
|
|
/// `noteMenuOpened`'s advance check.
|
|
public struct FixedIntervalPolicy: ReplayPolicy, Sendable {
|
|
public let name: String
|
|
private let intervalSeconds: TimeInterval
|
|
|
|
public init(minutes: Int) {
|
|
self.name = "fixed-\(minutes)m"
|
|
self.intervalSeconds = TimeInterval(minutes) * 60
|
|
}
|
|
|
|
public func decide(_: ReplayPolicyInput) -> ReplayPolicyDecision {
|
|
ReplayPolicyDecision(delaySeconds: self.intervalSeconds, reason: "fixed")
|
|
}
|
|
}
|
|
|
|
/// The degenerate floor: never schedules a refresh. A trace replayed against this policy always
|
|
/// reports zero refreshes, which is the point — it establishes the worst-case staleness bound the
|
|
/// other policies are compared against.
|
|
public struct ManualPolicy: ReplayPolicy, Sendable {
|
|
public let name = "manual"
|
|
|
|
public init() {}
|
|
|
|
public func decide(_: ReplayPolicyInput) -> ReplayPolicyDecision {
|
|
ReplayPolicyDecision(delaySeconds: nil, reason: "manual")
|
|
}
|
|
}
|