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

934 lines
43 KiB
Swift

import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@MainActor
extension CodexAccountScopedRefreshTests {
@Test
func `single refresh persists provider snapshot for startup confirmation`() async throws {
let suite = "CodexWeeklyResetPublicationTests-single-startup-hydration"
let email = "startup-hydrated@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-startup-hydrated"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 69,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let initialLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.2,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let rebound = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 68,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-20))
let snapshotURL = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-weekly-round-trip-\(UUID().uuidString).json")
defer { try? FileManager.default.removeItem(at: snapshotURL) }
let snapshotStore = FileCodexAccountUsageSnapshotStore(fileURL: snapshotURL)
let firstStore = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
self.installContextualCodexProvider(on: firstStore) { _ in prior }
await firstStore.refreshProvider(.codex, allowDisabled: true)
let persistedSnapshots = snapshotStore.load(
for: settings.codexVisibleAccountProjection.visibleAccounts)
let persisted = try #require(persistedSnapshots.first)
#expect(persistedSnapshots.count == 1)
#expect(firstStore.codexAccountSnapshots.count == 1)
#expect(firstStore.codexAccountSnapshots.first?.id == persisted.id)
#expect(persisted.account.workspaceAccountID == "acct-startup-hydrated")
#expect(persisted.account.email == email)
#expect(persisted.snapshot?.updatedAt == prior.updatedAt)
#expect(persisted.snapshot?.accountEmail(for: .codex) == email)
#expect(persisted.sourceLabel == "test-codex")
let loader = SequencedCodexSnapshotLoader(steps: [
.success(initialLow),
.success(rebound, gated: true),
])
let store = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
#expect(store.snapshots[.codex] == nil)
#expect(store.codexAccountSnapshots.first?.snapshot?.updatedAt == prior.updatedAt)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) }
#expect(await loader.waitUntilCallCount(2))
#expect(store.snapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 69)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.lastSourceLabels[.codex] == "test-codex")
#expect(recorder.usedPercents.isEmpty)
await loader.release(call: 2)
await refreshTask.value
#expect(await loader.callCount == 2)
#expect(store.snapshots[.codex]?.updatedAt == rebound.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 68)
#expect(store.lastCodexAccountScopedRefreshGuard?.identity == .providerAccount(id: "acct-startup-hydrated"))
#expect(recorder.usedPercents.isEmpty)
}
@Test
func `single persistence rejects another member in the same workspace`() async {
let suite = "CodexWeeklyResetPublicationTests-single-persistence-member-isolation"
let email = "current-member@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-shared-workspace"))
defer { settings._test_liveSystemCodexAccount = nil }
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let otherMember = self.codexWeeklySnapshot(
email: "other-member@example.com",
weeklyUsedPercent: 42,
weeklyReset: Date().addingTimeInterval(2 * 24 * 60 * 60),
updatedAt: Date())
let store = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
self.installContextualCodexProvider(on: store) { _ in otherMember }
await store.refreshProvider(.codex, allowDisabled: true)
#expect(store.snapshots[.codex] == nil)
#expect(store.lastKnownResetSnapshots[.codex] == nil)
#expect(store.codexAccountSnapshots.isEmpty)
#expect(snapshotStore.storedSnapshots.isEmpty)
}
@Test
func `single startup rejects hydrated snapshot from another workspace`() async throws {
let suite = "CodexWeeklyResetPublicationTests-single-startup-workspace-isolation"
let email = "workspace-isolation@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-current-workspace"))
defer { settings._test_liveSystemCodexAccount = nil }
let currentAccount = try #require(settings.codexVisibleAccountProjection.visibleAccounts.first)
let otherWorkspaceAccount = CodexVisibleAccount(
id: currentAccount.id,
email: currentAccount.email,
workspaceLabel: currentAccount.workspaceLabel,
workspaceAccountID: "acct-other-workspace",
authFingerprint: currentAccount.authFingerprint,
storedAccountID: currentAccount.storedAccountID,
selectionSource: currentAccount.selectionSource,
isActive: currentAccount.isActive,
isLive: currentAccount.isLive,
canReauthenticate: currentAccount.canReauthenticate,
canRemove: currentAccount.canRemove)
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let otherWorkspacePrior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 71,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let currentSnapshot = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 42,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-20))
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [
CodexAccountUsageSnapshot(
account: otherWorkspaceAccount,
snapshot: otherWorkspacePrior,
error: nil,
sourceLabel: "wrong-workspace"),
])
let loader = SequencedCodexSnapshotLoader(steps: [.success(currentSnapshot, gated: true)])
let store = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) }
#expect(await loader.waitUntilCallCount(1))
#expect(store.snapshots[.codex] == nil)
#expect(store.lastKnownResetSnapshots[.codex] == nil)
await loader.release(call: 1)
await refreshTask.value
#expect(await loader.callCount == 1)
#expect(store.snapshots[.codex]?.updatedAt == currentSnapshot.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 42)
let persisted = try #require(snapshotStore.storedSnapshots.first)
#expect(snapshotStore.storedSnapshots.count == 1)
#expect(store.codexAccountSnapshots.count == 1)
#expect(store.codexAccountSnapshots.first?.id == persisted.id)
#expect(persisted.account.workspaceAccountID == "acct-current-workspace")
#expect(persisted.account.email == email)
#expect(persisted.snapshot?.updatedAt == currentSnapshot.updatedAt)
}
@Test
func `single refresh retains the weekly lane when a source omits it`() async {
let suite = "CodexWeeklyResetPublicationTests-single-missing-weekly"
let email = "missing-weekly@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-missing-weekly"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 57,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let partial = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: nil,
weeklyReset: nil,
updatedAt: now.addingTimeInterval(-20),
sessionUsedPercent: 31)
let loader = SequencedCodexSnapshotLoader(steps: [.success(partial)])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
_ = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior,
error: nil)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
await store.refreshProvider(.codex, allowDisabled: true)
#expect(await loader.callCount == 1)
#expect(store.snapshots[.codex]?.updatedAt == partial.updatedAt)
#expect(store.snapshots[.codex]?.primary?.usedPercent == 31)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 57)
#expect(store.snapshots[.codex]?.secondary?.resetsAt == priorBoundary)
#expect(store.lastKnownResetSnapshots[.codex]?.secondary?.usedPercent == 57)
}
@Test
func `single refresh keeps prior state private until rebound confirmation publishes`() async {
let suite = "CodexWeeklyResetPublicationTests-single-gated-rebound"
let email = "gated-rebound@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-gated-rebound"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(3 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 64,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let initialLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.2,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let rebound = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 63,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-20))
let loader = SequencedCodexSnapshotLoader(steps: [
.success(initialLow),
.success(rebound, gated: true),
])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
let priorRevision = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
let refreshTask = Task { await store.refreshProvider(.codex, allowDisabled: true) }
#expect(await loader.waitUntilCallCount(2))
#expect(store.snapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 64)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.lastKnownResetSnapshots[.codex]?.secondary?.usedPercent == 64)
#expect(store.errors[.codex] == "prior error")
#expect(store.lastSourceLabels[.codex] == "prior-source")
#expect(store.lastFetchAttempts[.codex]?.count == 1)
#expect(store.lastFetchAttempts[.codex]?.first?.strategyID == "prior-strategy")
#expect(store.lastFetchAttempts[.codex]?.first?.errorDescription == "prior diagnostic")
#expect(store.planUtilizationHistoryRevision == priorRevision)
#expect(recorder.usedPercents.isEmpty)
await loader.release(call: 2)
await refreshTask.value
#expect(await loader.callCount == 2)
#expect(store.snapshots[.codex]?.updatedAt == rebound.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 63)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == rebound.updatedAt)
#expect(store.lastKnownResetSnapshots[.codex]?.secondary?.usedPercent == 63)
#expect(store.errors[.codex] == nil)
#expect(store.lastSourceLabels[.codex] == "test-codex")
#expect(store.lastFetchAttempts[.codex]?.count == 1)
#expect(store.lastFetchAttempts[.codex]?.first?.strategyID == "contextual-test-codex")
#expect(recorder.usedPercents.isEmpty)
}
@Test
func `single refresh publishes the second matching low observation only`() async {
let suite = "CodexWeeklyResetPublicationTests-single-confirmed-low"
let email = "confirmed-low@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-confirmed-low"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 72,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let initialLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.2,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let confirmedLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.7,
weeklyReset: nextBoundary.addingTimeInterval(30),
updatedAt: now.addingTimeInterval(-20))
let loader = SequencedCodexSnapshotLoader(steps: [
.success(initialLow),
.success(confirmedLow),
])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
_ = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior,
error: nil)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
await store.refreshProvider(.codex, allowDisabled: true)
#expect(await loader.callCount == 2)
#expect(store.snapshots[.codex]?.updatedAt == confirmedLow.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 0.7)
#expect(store.snapshots[.codex]?.secondary?.usedPercent != initialLow.secondary?.usedPercent)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == confirmedLow.updatedAt)
#expect(recorder.count == 1)
#expect(recorder.usedPercents == [0.7])
}
@Test(arguments: CodexRejectedConfirmationCase.allCases)
func `rejected single confirmation preserves every prior public surface`(
rejection: CodexRejectedConfirmationCase) async
{
let suite = "CodexWeeklyResetPublicationTests-rejected-\(rejection.rawValue)"
let email = "rejected-\(rejection.rawValue)@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-rejected-\(rejection.rawValue)"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 81,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let initialLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.1,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let confirmationStep: SequencedCodexSnapshotLoadStep = switch rejection {
case .error:
.failure("soft confirmation failure")
case .missingBoundary:
.success(self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.4,
weeklyReset: nil,
updatedAt: now.addingTimeInterval(-20)))
case .mismatchedBoundary:
.success(self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.4,
weeklyReset: nextBoundary.addingTimeInterval(3 * 60),
updatedAt: now.addingTimeInterval(-20)))
case .differentMember:
.success(self.codexWeeklySnapshot(
email: "another-member@example.com",
weeklyUsedPercent: 0.4,
weeklyReset: nextBoundary.addingTimeInterval(30),
updatedAt: now.addingTimeInterval(-20)))
}
let loader = SequencedCodexSnapshotLoader(steps: [.success(initialLow), confirmationStep])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
let priorRevision = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior,
error: nil)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
await store.refreshProvider(.codex, allowDisabled: true)
#expect(await loader.callCount == 2)
#expect(store.snapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 81)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.lastKnownResetSnapshots[.codex]?.secondary?.usedPercent == 81)
#expect(store.errors[.codex] == nil)
#expect(store.lastSourceLabels[.codex] == "prior-source")
#expect(store.lastFetchAttempts[.codex]?.count == 1)
#expect(store.lastFetchAttempts[.codex]?.first?.strategyID == "prior-strategy")
#expect(store.lastFetchAttempts[.codex]?.first?.errorDescription == "prior diagnostic")
#expect(store.planUtilizationHistoryRevision == priorRevision)
#expect(recorder.usedPercents.isEmpty)
}
@Test
func `confirmed reset resists a later stale pre reset observation`() async {
let suite = "CodexWeeklyResetPublicationTests-post-reset-stale"
let email = "post-reset-stale@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-post-reset-stale"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 78,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let initialLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.2,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let confirmedLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.6,
weeklyReset: nextBoundary.addingTimeInterval(30),
updatedAt: now.addingTimeInterval(-20))
let stalePreReset = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 77,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-10))
let loader = SequencedCodexSnapshotLoader(steps: [
.success(initialLow),
.success(confirmedLow),
.success(stalePreReset),
])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
_ = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior,
error: nil)
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
await store.refreshProvider(.codex, allowDisabled: true)
let acceptedRevision = store.planUtilizationHistoryRevision
#expect(store.snapshots[.codex]?.updatedAt == confirmedLow.updatedAt)
#expect(recorder.usedPercents == [0.6])
await store.refreshProvider(.codex, allowDisabled: true)
#expect(await loader.callCount == 3)
#expect(store.snapshots[.codex]?.updatedAt == confirmedLow.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 0.6)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == confirmedLow.updatedAt)
#expect(store.planUtilizationHistoryRevision == acceptedRevision)
#expect(recorder.usedPercents == [0.6])
}
@Test
func `single refresh never compares a prior snapshot across provider owners`() async {
let suite = "CodexWeeklyResetPublicationTests-owner-transition"
let email = "owner-transition@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-owner-transition-a"))
defer { settings._test_liveSystemCodexAccount = nil }
let now = Date()
let priorBoundary = now.addingTimeInterval(2 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let prior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 82,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let newOwnerLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.3,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-20))
let confirmedNewOwnerLow = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.6,
weeklyReset: nextBoundary.addingTimeInterval(30),
updatedAt: now.addingTimeInterval(-10))
let loader = SequencedCodexSnapshotLoader(steps: [
.success(newOwnerLow),
.success(confirmedNewOwnerLow),
])
let store = self.makeCodexWeeklyPublicationStore(settings: settings, suite: suite)
_ = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: prior,
error: nil)
settings._test_liveSystemCodexAccount = self.liveAccount(
email: email,
identity: .providerAccount(id: "acct-owner-transition-b"))
self.installContextualCodexProvider(on: store) { _ in try await loader.load() }
let recorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { recorder.invalidate() }
await store.refreshProvider(.codex, allowDisabled: true)
#expect(await loader.callCount == 2)
#expect(store.snapshots[.codex]?.updatedAt == confirmedNewOwnerLow.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 0.6)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == confirmedNewOwnerLow.updatedAt)
#expect(recorder.usedPercents.isEmpty)
}
@Test
func `stacked refresh rejects a response explicitly owned by another member`() async throws {
let suite = "CodexWeeklyResetPublicationTests-stacked-response-email-mismatch"
let targetID = try #require(UUID(uuidString: "11111111-2222-3333-4444-555555555555"))
let siblingID = try #require(UUID(uuidString: "66666666-7777-8888-9999-AAAAAAAAAAAA"))
let targetHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-stacked-mismatch-target-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-stacked-mismatch-sibling-\(UUID().uuidString)", isDirectory: true)
let target = try self.makeManagedCodexWeeklyPublicationAccount(
id: targetID,
email: "target-member@example.com",
workspaceID: "shared-provider-workspace",
workspaceLabel: "Target Member",
homeURL: targetHome)
let sibling = try self.makeManagedCodexWeeklyPublicationAccount(
id: siblingID,
email: "sibling-member@example.com",
workspaceID: "sibling-provider-workspace",
workspaceLabel: "Sibling Member",
homeURL: siblingHome)
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.multiAccountMenuLayout = .stacked
let storeURL = try self.makeManagedAccountStoreURL(accounts: [target, sibling])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: storeURL)
try? FileManager.default.removeItem(at: targetHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = storeURL
settings.codexActiveSource = .managedAccount(id: targetID)
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: [])
let store = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
let now = Date()
let targetMismatch = self.codexWeeklySnapshot(
email: "another-member@example.com",
weeklyUsedPercent: 64,
weeklyReset: now.addingTimeInterval(2 * 24 * 60 * 60),
updatedAt: now)
let siblingSnapshot = self.codexWeeklySnapshot(
email: sibling.email,
weeklyUsedPercent: 22,
weeklyReset: now.addingTimeInterval(2 * 24 * 60 * 60),
updatedAt: now)
self.installContextualCodexProvider(on: store) { context in
let isTarget = context.env["CODEX_HOME"] == targetHome.path
return isTarget ? targetMismatch : siblingSnapshot
}
await store.refreshCodexVisibleAccountsForMenu()
#expect(store.snapshots[.codex] == nil)
#expect(!store.codexAccountSnapshots.contains { $0.account.storedAccountID == targetID })
#expect(store.codexAccountSnapshots.contains { $0.account.storedAccountID == siblingID })
#expect(!snapshotStore.storedSnapshots.contains { $0.account.storedAccountID == targetID })
#expect(snapshotStore.storedSnapshots.contains { $0.account.storedAccountID == siblingID })
}
@Test
func `stacked refresh never publishes or persists an unconfirmed account reset`() async throws {
let suite = "CodexWeeklyResetPublicationTests-stacked"
let email = "shared-stacked@example.com"
let settings = self.makeSettingsStore(suite: suite)
settings.refreshFrequency = .manual
settings.codexCookieSource = .off
settings.multiAccountMenuLayout = .stacked
let suspiciousID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-303030303030"))
let siblingID = try #require(UUID(uuidString: "AAAAAAAA-BBBB-CCCC-DDDD-313131313131"))
let suspiciousHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-weekly-suspicious-\(UUID().uuidString)", isDirectory: true)
let siblingHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-weekly-sibling-\(UUID().uuidString)", isDirectory: true)
let suspiciousAccount = try self.makeManagedCodexWeeklyPublicationAccount(
id: suspiciousID,
email: email,
workspaceID: "acct-stacked-suspicious",
workspaceLabel: "Suspicious Workspace",
homeURL: suspiciousHome)
let siblingAccount = try self.makeManagedCodexWeeklyPublicationAccount(
id: siblingID,
email: email,
workspaceID: "acct-stacked-sibling",
workspaceLabel: "Sibling Workspace",
homeURL: siblingHome)
let managedStoreURL = try self.makeManagedAccountStoreURL(accounts: [suspiciousAccount, siblingAccount])
defer {
settings._test_managedCodexAccountStoreURL = nil
try? FileManager.default.removeItem(at: managedStoreURL)
try? FileManager.default.removeItem(at: suspiciousHome)
try? FileManager.default.removeItem(at: siblingHome)
}
settings._test_managedCodexAccountStoreURL = managedStoreURL
settings.codexActiveSource = .managedAccount(id: suspiciousID)
let visibleAccounts = settings.codexVisibleAccountProjection.visibleAccounts
#expect(visibleAccounts.count == 2)
let suspiciousVisible = try #require(visibleAccounts.first {
$0.workspaceAccountID == "acct-stacked-suspicious"
})
let siblingVisible = try #require(visibleAccounts.first {
$0.workspaceAccountID == "acct-stacked-sibling"
})
let now = Date()
let priorBoundary = now.addingTimeInterval(3 * 24 * 60 * 60)
let nextBoundary = priorBoundary.addingTimeInterval(7 * 24 * 60 * 60)
let suspiciousPriorAccount = CodexVisibleAccount(
id: "prior-email-derived-row",
email: email,
workspaceLabel: suspiciousVisible.workspaceLabel,
workspaceAccountID: suspiciousVisible.workspaceAccountID,
authFingerprint: "prior-auth-fingerprint",
storedAccountID: suspiciousVisible.storedAccountID,
selectionSource: suspiciousVisible.selectionSource,
isActive: suspiciousVisible.isActive,
isLive: suspiciousVisible.isLive,
canReauthenticate: suspiciousVisible.canReauthenticate,
canRemove: suspiciousVisible.canRemove)
let suspiciousPrior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 84,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let siblingPrior = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 62,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-60))
let priorRows = [
CodexAccountUsageSnapshot(
account: suspiciousPriorAccount,
snapshot: suspiciousPrior,
error: nil,
sourceLabel: "cached-suspicious"),
CodexAccountUsageSnapshot(
account: siblingVisible,
snapshot: siblingPrior,
error: nil,
sourceLabel: "cached-sibling"),
]
let snapshotStore = RecordingCodexAccountUsageSnapshotStore(initialSnapshots: priorRows)
let store = self.makeCodexWeeklyPublicationStore(
settings: settings,
suite: suite,
snapshotStore: snapshotStore)
store.codexAccountSnapshots = priorRows
let priorRevision = await self.seedCodexWeeklyPublicationState(
store: store,
settings: settings,
snapshot: suspiciousPrior,
error: nil)
let suspiciousInitial = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.1,
weeklyReset: nextBoundary,
updatedAt: now.addingTimeInterval(-40))
let suspiciousRejected = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 0.4,
weeklyReset: nil,
updatedAt: now.addingTimeInterval(-20))
let siblingUpdated = self.codexWeeklySnapshot(
email: email,
weeklyUsedPercent: 63,
weeklyReset: priorBoundary,
updatedAt: now.addingTimeInterval(-20))
let suspiciousLoader = SequencedCodexSnapshotLoader(steps: [
.success(suspiciousInitial),
.success(suspiciousRejected, gated: true),
])
let siblingLoader = SequencedCodexSnapshotLoader(steps: [.success(siblingUpdated)])
let suspiciousHomePath = suspiciousHome.path
let siblingHomePath = siblingHome.path
self.installContextualCodexProvider(on: store) { context in
switch context.env["CODEX_HOME"] {
case suspiciousHomePath:
try await suspiciousLoader.load()
case siblingHomePath:
try await siblingLoader.load()
default:
throw TestRefreshError(message: "Unexpected CODEX_HOME routing")
}
}
let currentRecorder = CodexWeeklyPublicationEventRecorder(email: email)
defer { currentRecorder.invalidate() }
let refreshTask = Task { await store.refreshCodexVisibleAccountsForMenu() }
#expect(await suspiciousLoader.waitUntilCallCount(2))
#expect(await siblingLoader.waitUntilCompletedCallCount(1))
try self.expectBlockedStackedResetState(
store: store,
snapshotStore: snapshotStore,
prior: suspiciousPrior,
historyRevision: priorRevision,
recorder: currentRecorder)
await suspiciousLoader.release(call: 2)
await refreshTask.value
#expect(await suspiciousLoader.callCount == 2)
#expect(await siblingLoader.callCount == 1)
try self.expectFinalStackedResetState(
store: store,
snapshotStore: snapshotStore,
expectation: FinalStackedResetExpectation(
targetAccount: suspiciousVisible,
siblingAccount: siblingVisible,
targetPrior: suspiciousPrior,
siblingUpdated: siblingUpdated,
historyRevision: priorRevision),
recorder: currentRecorder)
}
private func expectBlockedStackedResetState(
store: UsageStore,
snapshotStore: RecordingCodexAccountUsageSnapshotStore,
prior: UsageSnapshot,
historyRevision: Int,
recorder: CodexWeeklyPublicationEventRecorder) throws
{
let target = try #require(store.codexAccountSnapshots.first {
$0.account.workspaceAccountID == "acct-stacked-suspicious"
})
#expect(target.snapshot?.updatedAt == prior.updatedAt)
#expect(target.snapshot?.secondary?.usedPercent == 84)
#expect(target.sourceLabel == "cached-suspicious")
#expect(snapshotStore.storedSnapshots.isEmpty)
#expect(store.snapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 84)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == prior.updatedAt)
#expect(store.errors[.codex] == nil)
#expect(store.lastSourceLabels[.codex] == "prior-source")
#expect(store.lastFetchAttempts[.codex]?.first?.strategyID == "prior-strategy")
#expect(store.planUtilizationHistoryRevision == historyRevision)
#expect(recorder.usedPercents.isEmpty)
}
private func expectFinalStackedResetState(
store: UsageStore,
snapshotStore: RecordingCodexAccountUsageSnapshotStore,
expectation: FinalStackedResetExpectation,
recorder: CodexWeeklyPublicationEventRecorder) throws
{
let target = try #require(store.codexAccountSnapshots.first {
$0.account.workspaceAccountID == "acct-stacked-suspicious"
})
#expect(target.account.id == expectation.targetAccount.id)
#expect(target.account.email == expectation.targetAccount.email)
#expect(target.snapshot?.accountEmail(for: .codex) == expectation.targetAccount.email)
#expect(target.snapshot?.updatedAt == expectation.targetPrior.updatedAt)
#expect(target.snapshot?.secondary?.usedPercent == 84)
#expect(target.error == nil)
#expect(target.sourceLabel == "cached-suspicious")
#expect(!store.codexAccountSnapshots.contains {
$0.account.workspaceAccountID == "acct-stacked-suspicious"
&& $0.snapshot?.secondary?.usedPercent == 0.1
})
let persistedTarget = try #require(snapshotStore.storedSnapshots.first {
$0.account.workspaceAccountID == "acct-stacked-suspicious"
})
#expect(persistedTarget.snapshot?.updatedAt == expectation.targetPrior.updatedAt)
#expect(persistedTarget.snapshot?.secondary?.usedPercent == 84)
#expect(persistedTarget.error == nil)
#expect(persistedTarget.sourceLabel == "cached-suspicious")
let sibling = try #require(store.codexAccountSnapshots.first {
$0.account.workspaceAccountID == "acct-stacked-sibling"
})
#expect(sibling.snapshot?.updatedAt == expectation.siblingUpdated.updatedAt)
#expect(sibling.snapshot?.secondary?.usedPercent == 63)
#expect(snapshotStore.storedSnapshots.count == 2)
#expect(Set(snapshotStore.storedSnapshots.map(\.id)) == Set([
expectation.targetAccount.id,
expectation.siblingAccount.id,
]))
#expect(!snapshotStore.storedSnapshots.contains {
$0.account.workspaceAccountID == "acct-stacked-suspicious"
&& $0.snapshot?.secondary?.usedPercent == 0.1
})
#expect(store.snapshots[.codex]?.updatedAt == expectation.targetPrior.updatedAt)
#expect(store.snapshots[.codex]?.secondary?.usedPercent == 84)
#expect(store.snapshots[.codex]?.accountEmail(for: .codex) == expectation.targetAccount.email)
#expect(store.lastKnownResetSnapshots[.codex]?.updatedAt == expectation.targetPrior.updatedAt)
#expect(
store.lastKnownResetSnapshots[.codex]?.accountEmail(for: .codex) == expectation.targetAccount.email)
#expect(store.errors[.codex] == nil)
#expect(store.lastSourceLabels[.codex] == "prior-source")
#expect(store.lastFetchAttempts[.codex]?.first?.strategyID == "prior-strategy")
#expect(store.planUtilizationHistoryRevision == expectation.historyRevision)
#expect(recorder.usedPercents.isEmpty)
}
}
private struct FinalStackedResetExpectation {
let targetAccount: CodexVisibleAccount
let siblingAccount: CodexVisibleAccount
let targetPrior: UsageSnapshot
let siblingUpdated: UsageSnapshot
let historyRevision: Int
}
enum CodexRejectedConfirmationCase: String, CaseIterable, Sendable {
case differentMember
case error
case missingBoundary
case mismatchedBoundary
}
private final class CodexWeeklyPublicationEventRecorder: @unchecked Sendable {
private let email: String
private let lock = NSLock()
private var observations: [Double] = []
private var token: NSObjectProtocol?
init(email: String) {
self.email = email
self.token = NotificationCenter.default.addObserver(
forName: .codexbarWeeklyLimitReset,
object: nil,
queue: nil)
{ [weak self] notification in
guard let self,
let event = notification.object as? WeeklyLimitResetEvent
else {
return
}
let usedPercent = MainActor.assumeIsolated { () -> Double? in
guard event.provider == .codex, event.accountLabel == self.email else { return nil }
return event.usedPercent
}
guard let usedPercent else { return }
self.lock.lock()
self.observations.append(usedPercent)
self.lock.unlock()
}
}
var count: Int {
self.lock.lock()
defer { self.lock.unlock() }
return self.observations.count
}
var usedPercents: [Double] {
self.lock.lock()
defer { self.lock.unlock() }
return self.observations
}
func invalidate() {
guard let token else { return }
NotificationCenter.default.removeObserver(token)
self.token = nil
}
deinit {
self.invalidate()
}
}