Files
steipete--codexbar/Tests/CodexBarTests/HistoricalUsagePaceTests.swift
2026-07-13 12:22:33 +08:00

824 lines
32 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@Suite(.serialized)
struct HistoricalUsagePaceTests {
@Test
func `history store reconstructs deterministic monotone curve`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let resetsAt = Date().addingTimeInterval(-24 * 60 * 60)
let windowStart = resetsAt.addingTimeInterval(-duration)
let samples: [(u: Double, used: Double)] = [
(0.02, 3),
(0.10, 10),
(0.40, 40),
(0.60, 60),
(0.80, 80),
(0.98, 95),
]
for sample in samples {
let sampledAt = windowStart.addingTimeInterval(sample.u * duration)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: sampledAt,
accountKey: nil)
}
let dataset = await store.loadCodexDataset(accountKey: nil)
#expect(dataset?.weeks.count == 1)
let curve = try #require(dataset?.weeks.first?.curve)
#expect(curve.count == CodexHistoricalDataset.gridPointCount)
#expect(abs(curve[0]) < 0.001)
for index in 1..<curve.count {
#expect(curve[index] >= curve[index - 1])
}
// u=0.5 is index 84 in a 169-point grid.
#expect(abs(curve[84] - 50) < 0.5)
}
@Test
func `reconstruct week curve anchors at zero at window start`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let resetsAt = Date().addingTimeInterval(-24 * 60 * 60)
let windowStart = resetsAt.addingTimeInterval(-duration)
let samples: [(u: Double, used: Double)] = [
(0.10, 12),
(0.25, 25),
(0.50, 50),
(0.70, 70),
(0.90, 90),
(0.98, 96),
]
for sample in samples {
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: windowStart.addingTimeInterval(sample.u * duration),
accountKey: nil)
}
let curve = try #require(await store.loadCodexDataset(accountKey: nil)?.weeks.first?.curve)
#expect(abs(curve[0]) < 0.001)
#expect(curve[1] >= curve[0])
}
@Test
func `reconstruct week curve adds end anchor without breaking monotonicity`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let resetsAt = Date().addingTimeInterval(-24 * 60 * 60)
let windowStart = resetsAt.addingTimeInterval(-duration)
let samples: [(u: Double, used: Double)] = [
(0.02, 2),
(0.15, 18),
(0.35, 40),
(0.55, 58),
(0.80, 82),
(0.90, 88),
]
for sample in samples {
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: windowStart.addingTimeInterval(sample.u * duration),
accountKey: nil)
}
let curve = try #require(await store.loadCodexDataset(accountKey: nil)?.weeks.first?.curve)
for index in 1..<curve.count {
#expect(curve[index] >= curve[index - 1])
}
let last = try #require(curve.last)
#expect(abs(last - 88) < 1.5)
}
@Test
func `history store requires start and end coverage for complete week`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let resetsAt = Date().addingTimeInterval(-24 * 60 * 60)
let windowStart = resetsAt.addingTimeInterval(-duration)
// Missing first-24h coverage on purpose.
let lateOnlySamples: [(u: Double, used: Double)] = [
(0.30, 20),
(0.45, 35),
(0.60, 50),
(0.75, 65),
(0.90, 80),
(0.98, 92),
]
for sample in lateOnlySamples {
let sampledAt = windowStart.addingTimeInterval(sample.u * duration)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: sampledAt,
accountKey: nil)
}
#expect(await store.loadCodexDataset(accountKey: nil) == nil)
}
@Test
func `evaluator applies smoothed probability and hides risk below threshold`() throws {
let now = Date(timeIntervalSince1970: 0)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let currentResetsAt = now.addingTimeInterval(duration / 2)
let window = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: currentResetsAt,
resetDescription: nil)
let fiveTrueWeeks = (0..<5).map { index in
HistoricalWeekProfile(
resetsAt: currentResetsAt.addingTimeInterval(-duration * Double(index + 1)),
windowMinutes: windowMinutes,
curve: Self.linearCurve(end: 100))
}
let paceAllTrue = CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: CodexHistoricalDataset(weeks: fiveTrueWeeks))
let probabilityTrue = try #require(paceAllTrue?.runOutProbability)
#expect(probabilityTrue > 0)
#expect(probabilityTrue < 1)
let fiveFalseWeeks = (0..<5).map { index in
HistoricalWeekProfile(
resetsAt: currentResetsAt.addingTimeInterval(-duration * Double(index + 1)),
windowMinutes: windowMinutes,
curve: Self.linearCurve(end: 80))
}
let paceAllFalse = CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: CodexHistoricalDataset(weeks: fiveFalseWeeks))
let probabilityFalse = try #require(paceAllFalse?.runOutProbability)
#expect(probabilityFalse > 0)
#expect(probabilityFalse < 1)
let fourWeeks = Array(fiveTrueWeeks.prefix(4))
let paceFourWeeks = CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: CodexHistoricalDataset(weeks: fourWeeks))
#expect(paceFourWeeks?.runOutProbability == nil)
}
@Test
func `evaluator never returns negative eta with outlier week`() {
let now = Date(timeIntervalSince1970: 0)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let currentResetsAt = now.addingTimeInterval(duration / 2)
let window = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: currentResetsAt,
resetDescription: nil)
var weeks = (0..<4).map { index in
HistoricalWeekProfile(
resetsAt: currentResetsAt.addingTimeInterval(-duration * Double(index + 1)),
windowMinutes: windowMinutes,
curve: Self.linearCurve(end: 100))
}
weeks.append(HistoricalWeekProfile(
resetsAt: currentResetsAt.addingTimeInterval(-duration * 5),
windowMinutes: windowMinutes,
curve: Self.outlierCurve()))
let pace = CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: CodexHistoricalDataset(weeks: weeks))
#expect(pace != nil)
#expect((pace?.etaSeconds ?? 0) >= 0)
}
@Test
func `history store backfills from usage breakdown when history is empty`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 35, dailyCredits: 10)
let dataset = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((dataset?.weeks.count ?? 0) >= 3)
}
@Test
func `history store backfill is idempotent for existing weeks`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 35, dailyCredits: 10)
let first = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
let recordsAfterFirst = (try? Self.readHistoricalRecords(from: fileURL)) ?? []
let second = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
let recordsAfterSecond = (try? Self.readHistoricalRecords(from: fileURL)) ?? []
#expect((first?.weeks.count ?? 0) >= 3)
#expect(first?.weeks.count == second?.weeks.count)
#expect(recordsAfterSecond.count == recordsAfterFirst.count)
#expect(Self.recordDedupKeyCount(recordsAfterSecond) == recordsAfterSecond.count)
#expect(Self.datasetCurveSignature(first) == Self.datasetCurveSignature(second))
}
@Test
func `history store backfill is idempotent across minute scale reset jitter`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let canonicalReset = Self.normalizeReset(now.addingTimeInterval(2 * 24 * 60 * 60))
let firstWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: canonicalReset.addingTimeInterval(-90),
resetDescription: nil)
let secondWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: canonicalReset.addingTimeInterval(90),
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 35, dailyCredits: 10)
let first = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: firstWindow,
now: now,
accountKey: nil)
let recordsAfterFirst = (try? Self.readHistoricalRecords(from: fileURL)) ?? []
let second = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: secondWindow,
now: now,
accountKey: nil)
let recordsAfterSecond = (try? Self.readHistoricalRecords(from: fileURL)) ?? []
#expect((first?.weeks.count ?? 0) >= 3)
#expect(first?.weeks.count == second?.weeks.count)
#expect(recordsAfterSecond.count == recordsAfterFirst.count)
#expect(Self.datasetCurveSignature(first) == Self.datasetCurveSignature(second))
}
@Test
func `history store backfill fills incomplete existing week`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: resetsAt,
resetDescription: nil)
let incompleteReset = resetsAt.addingTimeInterval(-2 * duration)
let incompleteStart = incompleteReset.addingTimeInterval(-duration)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: 42,
windowMinutes: windowMinutes,
resetsAt: incompleteReset,
resetDescription: nil),
sampledAt: incompleteStart.addingTimeInterval(duration * 0.5),
accountKey: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 29, dailyCredits: 10)
let dataset = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((dataset?.weeks.count ?? 0) >= 3)
}
@Test
func `history store should accept does not cross window minutes regimes`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let sampledAt = Date(timeIntervalSince1970: 1_770_000_000)
let resetsAt = sampledAt.addingTimeInterval(3 * 24 * 60 * 60)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: 20,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: sampledAt,
accountKey: nil)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: 20,
windowMinutes: 20160,
resetsAt: resetsAt,
resetDescription: nil),
sampledAt: sampledAt.addingTimeInterval(60),
accountKey: nil)
let data = try Data(contentsOf: fileURL)
let text = String(data: data, encoding: .utf8) ?? ""
let lines = text
.split(separator: "\n", omittingEmptySubsequences: true)
.map(String.init)
#expect(lines.count == 2)
}
@Test
func `weeks with reset jitter are grouped together`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let canonicalReset = Self.normalizeReset(Date(timeIntervalSince1970: 1_770_000_000))
let windowStart = canonicalReset.addingTimeInterval(-duration)
let samples: [(u: Double, used: Double)] = [
(0.02, 2),
(0.10, 10),
(0.30, 30),
(0.50, 50),
(0.80, 80),
(0.98, 95),
]
for (index, sample) in samples.enumerated() {
let jitteredReset = canonicalReset.addingTimeInterval(index.isMultiple(of: 2) ? -100 : 100)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: jitteredReset,
resetDescription: nil),
sampledAt: windowStart.addingTimeInterval(sample.u * duration),
accountKey: nil)
}
let dataset = await store.loadCodexDataset(accountKey: nil)
#expect(dataset?.weeks.count == 1)
}
@Test
func `backfill matches incomplete week when reset jitter exists`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let currentReset = now.addingTimeInterval(2 * 24 * 60 * 60)
let targetReset = currentReset.addingTimeInterval(-2 * duration)
let targetStart = targetReset.addingTimeInterval(-duration)
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: 35,
windowMinutes: windowMinutes,
resetsAt: targetReset.addingTimeInterval(120),
resetDescription: nil),
sampledAt: targetStart.addingTimeInterval(duration * 0.5),
accountKey: nil)
let datasetBefore = await store.loadCodexDataset(accountKey: nil)
#expect(datasetBefore == nil)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: currentReset,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 29, dailyCredits: 10)
let datasetAfter = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((datasetAfter?.weeks.count ?? 0) >= 3)
let normalizedTargetReset = Self.normalizeReset(targetReset)
let records = try Self.readHistoricalRecords(from: fileURL)
let matching = records.filter { $0.accountKey == nil && $0.resetsAt == normalizedTargetReset }
#expect(matching.count > 1)
}
@Test
func `backfill does not stop at three weeks when more backfillable weeks exist`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let currentReset = now.addingTimeInterval(2 * 24 * 60 * 60)
// Seed 3 complete weeks.
for weekOffset in 1...3 {
let reset = currentReset.addingTimeInterval(-duration * Double(weekOffset))
let start = reset.addingTimeInterval(-duration)
let samples: [(u: Double, used: Double)] = [
(0.02, 2), (0.10, 10), (0.30, 30), (0.50, 50), (0.80, 80), (0.98, 95),
]
for sample in samples {
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: sample.used,
windowMinutes: windowMinutes,
resetsAt: reset,
resetDescription: nil),
sampledAt: start.addingTimeInterval(sample.u * duration),
accountKey: nil)
}
}
let pre = try #require(await store.loadCodexDataset(accountKey: nil))
#expect(pre.weeks.count == 3)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: windowMinutes,
resetsAt: currentReset,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 56, dailyCredits: 10)
let post = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((post?.weeks.count ?? 0) > 3)
}
@Test
func `load dataset uses only current account key`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let windowMinutes = 10080
let duration = TimeInterval(windowMinutes) * 60
let reset = Date(timeIntervalSince1970: 1_770_000_000)
let start = reset.addingTimeInterval(-duration)
let samples: [Double] = [0.02, 0.10, 0.30, 0.50, 0.80, 0.98]
for u in samples {
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: u * 100,
windowMinutes: windowMinutes,
resetsAt: reset,
resetDescription: nil),
sampledAt: start.addingTimeInterval(u * duration),
accountKey: "acct-a")
}
for u in samples {
_ = await store.recordCodexWeekly(
window: RateWindow(
usedPercent: min(100, (u * 100) + 10),
windowMinutes: windowMinutes,
resetsAt: reset,
resetDescription: nil),
sampledAt: start.addingTimeInterval(u * duration),
accountKey: "acct-b")
}
let aDataset = try #require(await store.loadCodexDataset(accountKey: "acct-a"))
let bDataset = try #require(await store.loadCodexDataset(accountKey: "acct-b"))
let nilDataset = await store.loadCodexDataset(accountKey: nil)
#expect(aDataset.weeks.count == 1)
#expect(bDataset.weeks.count == 1)
#expect(nilDataset == nil)
#expect(abs(aDataset.weeks[0].curve[84] - bDataset.weeks[0].curve[84]) > 0.1)
}
@Test
func `backfill filters by account key`() async throws {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 35, dailyCredits: 10)
_ = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: "acct-a")
_ = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: "acct-b")
let records = try Self.readHistoricalRecords(from: fileURL)
#expect(records.contains { $0.accountKey == "acct-a" })
#expect(records.contains { $0.accountKey == "acct-b" })
let aDataset = await store.loadCodexDataset(accountKey: "acct-a")
let bDataset = await store.loadCodexDataset(accountKey: "acct-b")
#expect((aDataset?.weeks.count ?? 0) >= 3)
#expect((bDataset?.weeks.count ?? 0) >= 3)
}
@Test
func `coverage tolerance allows day boundary shift without no op`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Date(timeIntervalSince1970: 1_770_000_000)
let breakdown = Self.syntheticBreakdown(endingAt: now, days: 35, dailyCredits: 10)
let coverageStart = Self.dayStart(for: breakdown.last?.day ?? "")!
let priorBackfillStart = coverageStart.addingTimeInterval(-10 * 60 * 60)
let priorBackfillReset = priorBackfillStart.addingTimeInterval(7 * 24 * 60 * 60)
let resetsAt = priorBackfillReset.addingTimeInterval(7 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil)
let dataset = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((dataset?.weeks.count ?? 0) >= 1)
}
@Test
func `backfill treats omitted recent zero usage days as coverage`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Self.gregorianDate(year: 2026, month: 2, day: 26, hour: 20)
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(
endingAt: now,
days: 35,
dailyCredits: 10,
overridesByDayOffset: [
0: 0,
1: 0,
])
.filter { $0.totalCreditsUsed > 0 }
let dataset = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((dataset?.weeks.count ?? 0) >= 3)
}
@Test
func `backfill treats omitted leading zero usage days as coverage`() async {
let fileURL = Self.makeTempURL()
let store = HistoricalUsageHistoryStore(fileURL: fileURL)
let now = Self.gregorianDate(year: 2026, month: 2, day: 26, hour: 20)
let resetsAt = now.addingTimeInterval(2 * 24 * 60 * 60)
let referenceWindow = RateWindow(
usedPercent: 50,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil)
let breakdown = Self.syntheticBreakdown(
endingAt: now,
days: 35,
dailyCredits: 10,
overridesByDayOffset: [
3: 0,
4: 0,
5: 0,
])
.filter { $0.totalCreditsUsed > 0 }
let dataset = await store.backfillCodexWeeklyFromUsageBreakdown(
breakdown,
referenceWindow: referenceWindow,
now: now,
accountKey: nil)
#expect((dataset?.weeks.count ?? 0) >= 3)
}
@Test
func `partial day credits are not undercounted at as of time`() {
let asOf = Self.gregorianDate(year: 2026, month: 2, day: 26, hour: 12)
let start = Self.gregorianDate(year: 2026, month: 2, day: 20, hour: 0)
let breakdown = Self.syntheticBreakdown(
endingAt: asOf,
days: 35,
dailyCredits: 1,
overridesByDayOffset: [
0: 20,
7: 20,
])
let credits = HistoricalUsageHistoryStore._creditsUsedForTesting(
breakdown: breakdown,
asOf: asOf,
start: start,
end: asOf)
#expect(abs(credits - 26) < 0.001)
}
@Test
func `gregorian day parsing is stable for YYYYMMDD`() {
let parsed = HistoricalUsageHistoryStore._dayStartForTesting("2026-02-26")
let expected = Self.gregorianDate(year: 2026, month: 2, day: 26, hour: 0)
#expect(parsed == expected)
}
@MainActor
@Test
func `backfill skips when timestamp mismatch exceeds5 minutes`() async throws {
let store = try Self.makeUsageStoreForBackfillTests(
suite: "HistoricalUsagePaceTests-backfill-mismatch",
historyFileURL: Self.makeTempURL())
store._setCodexHistoricalDatasetForTesting(nil)
let snapshotNow = Date(timeIntervalSince1970: 1_770_000_000)
let weekly = RateWindow(
usedPercent: 55,
windowMinutes: 10080,
resetsAt: snapshotNow.addingTimeInterval(2 * 24 * 60 * 60),
resetDescription: nil)
let snapshot = UsageSnapshot(
primary: nil,
secondary: weekly,
tertiary: nil,
providerCost: nil,
updatedAt: snapshotNow,
identity: nil)
store._setSnapshotForTesting(snapshot, provider: .codex)
let dashboard = OpenAIDashboardSnapshot(
signedInEmail: nil,
codeReviewRemainingPercent: nil,
creditEvents: [],
dailyBreakdown: [],
usageBreakdown: Self.syntheticBreakdown(endingAt: snapshotNow, days: 35, dailyCredits: 10),
creditsPurchaseURL: nil,
primaryLimit: nil,
secondaryLimit: nil,
creditsRemaining: nil,
accountPlan: nil,
updatedAt: snapshotNow.addingTimeInterval(-10 * 60))
store.backfillCodexHistoricalFromDashboardIfNeeded(
dashboard,
authorityDecision: CodexDashboardAuthorityDecision(
disposition: .attach,
reason: .trustedEmailMatchNoCompetingOwner,
allowedEffects: [.historicalBackfill],
cleanup: []),
attachedAccountEmail: "attached@example.com")
try await Task.sleep(for: .milliseconds(250))
#expect(store.codexHistoricalDataset == nil)
}
@Test
func `exhausted historical weeks extend linearly and don't flatline at 100`() throws {
// Build a historical dataset where a week reaches 100% at u = 0.5
var earlyExhaustedCurve = [Double]()
for i in 0..<CodexHistoricalDataset.gridPointCount {
let u = Double(i) / Double(CodexHistoricalDataset.gridPointCount - 1)
if u <= 0.5 {
earlyExhaustedCurve.append((u / 0.5) * 100)
} else {
earlyExhaustedCurve.append(100)
}
}
let now = Date()
let week = HistoricalWeekProfile(
resetsAt: now.addingTimeInterval(-10080 * 60),
windowMinutes: 10080,
curve: earlyExhaustedCurve)
let dataset = CodexHistoricalDataset(weeks: [week, week, week, week, week])
let window = RateWindow(
usedPercent: 80,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(0.25 * 10080 * 60),
resetDescription: nil)
let pace = try #require(CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: dataset))
#expect(pace.willLastToReset == false)
#expect(pace.runOutProbability != nil)
#expect(try #require(pace.runOutProbability) > 0)
#expect(pace.deltaPercent > 0)
let detail = UsagePaceText.weeklyDetail(provider: .codex, pace: pace, now: now)
#expect(detail.leftLabel == "5% in deficit")
#expect(detail.rightLabel?.contains("Lasts until reset") == false)
}
@Test
func `exhausted actual returns zero eta`() throws {
let now = Date()
let resetsAt = now.addingTimeInterval(3600)
let week = HistoricalWeekProfile(
resetsAt: now.addingTimeInterval(-10080 * 60),
windowMinutes: 10080,
curve: Array(repeating: 100.0, count: 169))
let dataset = CodexHistoricalDataset(weeks: [week, week, week])
for usedPercent in [100.0, 120.0] {
let window = RateWindow(
usedPercent: usedPercent,
windowMinutes: 10080,
resetsAt: resetsAt,
resetDescription: nil,
nextRegenPercent: nil)
let pace = try #require(CodexHistoricalPaceEvaluator.evaluate(
window: window,
now: now,
dataset: dataset))
#expect(pace.willLastToReset == false)
#expect(pace.etaSeconds == 0)
#expect(pace.runOutProbability == 1)
let detail = UsagePaceText.weeklyDetail(provider: .codex, pace: pace, now: now)
#expect(detail.rightLabel == "Runs out now · ≈ 100% run-out risk")
}
}
}