diff --git a/Sources/CodexBarCore/CostUsageFetcher.swift b/Sources/CodexBarCore/CostUsageFetcher.swift index e1d0e74703..2213dbd398 100644 --- a/Sources/CodexBarCore/CostUsageFetcher.swift +++ b/Sources/CodexBarCore/CostUsageFetcher.swift @@ -335,7 +335,8 @@ public struct CostUsageFetcher: Sendable { private static func resolvedScannerOptions( _ override: CostUsageScanner.Options?, provider: UsageProvider, - codexHomePath: String?) -> CostUsageScanner.Options + codexHomePath: String?, + allowVertexClaudeFallback: Bool = false) -> CostUsageScanner.Options { var options = override ?? CostUsageScanner.Options() // Provider-specific by design: Codex managed profiles relocate sessions and archived_sessions roots. @@ -346,6 +347,11 @@ public struct CostUsageFetcher: Sendable { options.codexSessionsRoot = URL(fileURLWithPath: codexHomePath, isDirectory: true) .appendingPathComponent("sessions", isDirectory: true) } + if provider == .vertexai { + options.claudeLogProviderFilter = allowVertexClaudeFallback ? .all : .vertexAIOnly + } else if provider == .claude { + options.claudeLogProviderFilter = .excludeVertexAI + } return options } @@ -387,12 +393,10 @@ public struct CostUsageFetcher: Sendable { var options = Self.resolvedScannerOptions( overrideScannerOptions, provider: provider, - codexHomePath: codexHomePath) + codexHomePath: codexHomePath, + allowVertexClaudeFallback: allowVertexClaudeFallback) // Rolling window is inclusive, so a 30-day display starts 29 days before `now`. let since = options.calendar.date(byAdding: .day, value: -(clampedHistoryDays - 1), to: now) ?? now - let scopedCodexHomePath = codexHomePath?.trimmingCharacters(in: .whitespacesAndNewlines) - // Provider-specific by design: scoped Codex homes exclude ambient Pi sessions from managed-profile totals. - let shouldMergePiUsage = provider != .codex || scopedCodexHomePath?.isEmpty != false await Self.refreshPricingIfAllowed( options: PricingRefreshOptions( provider: provider, @@ -406,7 +410,6 @@ public struct CostUsageFetcher: Sendable { Self.configureScannerRefresh( &options, provider: provider, - allowVertexClaudeFallback: allowVertexClaudeFallback, forceRefresh: forceRefresh, bypassScannerDebounce: bypassScannerDebounce) var resolvedPiOptions = overridePiScannerOptions ?? PiSessionCostScanner.Options() @@ -423,7 +426,7 @@ public struct CostUsageFetcher: Sendable { let localScanOptions = LocalTokenScanOptions( allowVertexClaudeFallback: allowVertexClaudeFallback, includePiSessions: includePiSessions, - shouldMergePiUsage: shouldMergePiUsage, + codexHomePath: codexHomePath, scanOptions: scanOptions, piOptions: piOptions) let scanResult = try await Self.loadLocalTokenScanResult( @@ -482,7 +485,7 @@ public struct CostUsageFetcher: Sendable { private struct LocalTokenScanOptions: Sendable { let allowVertexClaudeFallback: Bool let includePiSessions: Bool - let shouldMergePiUsage: Bool + let codexHomePath: String? let scanOptions: CostUsageScanner.Options let piOptions: PiSessionCostScanner.Options } @@ -529,6 +532,7 @@ public struct CostUsageFetcher: Sendable { var sessions: [CostUsageSessionBreakdown] = [] var piDaily: CostUsageDailyReport? var staleSnapshotUpdatedAt: Date? + // Provider-specific by design: only Codex builds project and session breakdowns from its local cache. if provider == .codex { let roots = CostUsageScanner.codexSessionsRoots(options: options.scanOptions) let cache = CostUsageScanner.codexCache( @@ -556,8 +560,10 @@ public struct CostUsageFetcher: Sendable { sessionRoots: roots) } } - if options.includePiSessions, - provider == .claude || (provider == .codex && options.shouldMergePiUsage) + if Self.shouldMergePiSessions( + provider: provider, + includePiSessions: options.includePiSessions, + codexHomePath: options.codexHomePath) { let piReport = try PiSessionCostScanner.loadDailyReportCancellable( provider: provider, @@ -567,6 +573,7 @@ public struct CostUsageFetcher: Sendable { options: options.piOptions, checkCancellation: checkCancellation) try checkCancellation() + // Provider-specific by design: only Codex stores the Pi-only report for project merge. if provider == .codex { piDaily = piReport } @@ -604,7 +611,7 @@ public struct CostUsageFetcher: Sendable { { guard options.isAllowed, options.retryUnknown, - options.provider == .codex || options.provider == .claude + self.usesModelsDevPricing(options.provider) else { return } if options.inBackground { @@ -631,10 +638,11 @@ public struct CostUsageFetcher: Sendable { cacheRoot: URL?, client: ModelsDevClient) -> UnknownPricingRefreshRequest? { - guard provider == .codex || provider == .claude else { return nil } + guard let providerID = self.modelsDevRefreshProviderID(for: provider) else { return nil } let unknownModelIDs = Set(daily.data.flatMap { entry in entry.modelBreakdowns?.compactMap { breakdown -> String? in guard breakdown.costUSD == nil else { return nil } + // Provider-specific by design: only Codex filters out its own unattributed model names. if provider == .codex, CostUsagePricing.isCodexUnattributedModel(breakdown.modelName) { @@ -646,7 +654,7 @@ public struct CostUsageFetcher: Sendable { guard !unknownModelIDs.isEmpty else { return nil } return UnknownPricingRefreshRequest( - providerID: provider == .codex ? "openai" : "anthropic", + providerID: providerID, modelIDs: unknownModelIDs, now: now, cacheRoot: cacheRoot, @@ -1108,15 +1116,11 @@ public struct CostUsageFetcher: Sendable { private static func configureScannerRefresh( _ options: inout CostUsageScanner.Options, provider: UsageProvider, - allowVertexClaudeFallback: Bool, forceRefresh: Bool, bypassScannerDebounce: Bool) { - if provider == .vertexai { - options.claudeLogProviderFilter = allowVertexClaudeFallback ? .all : .vertexAIOnly - } else if provider == .claude { - options.claudeLogProviderFilter = .excludeVertexAI - } + // `claudeLogProviderFilter` is configured in `resolvedScannerOptions` so it is available + // to every caller, not only this path. if forceRefresh || bypassScannerDebounce { options.refreshMinIntervalSeconds = 0 } @@ -1445,6 +1449,46 @@ extension CostUsageFetcher { return "v2:\(scopedFiles.count):\(progressHasher.finalize())" } + fileprivate static func shouldMergePiSessions( + provider: UsageProvider, + includePiSessions: Bool, + codexHomePath: String?) -> Bool + { + // Provider-specific by design: Pi session mirrors exist only for the China API group, Claude, and Codex. + let scopedCodexHomePath = codexHomePath?.trimmingCharacters(in: .whitespacesAndNewlines) + let shouldMergePiUsage = provider != .codex || scopedCodexHomePath?.isEmpty != false + return includePiSessions + && (provider == .claude + || (provider == .codex && shouldMergePiUsage) + || provider == .alibaba + || provider == .alibabatokenplan + || provider == .zai + || provider == .deepseek) + } + + fileprivate static func usesModelsDevPricing(_ provider: UsageProvider) -> Bool { + self.modelsDevRefreshProviderID(for: provider) != nil + } + + fileprivate static func modelsDevRefreshProviderID(for provider: UsageProvider) -> String? { + switch provider { + case .codex: + "openai" + case .claude: + "anthropic" + case .alibaba: + "alibaba-coding-plan" + case .alibabatokenplan: + "alibaba-token-plan" + case .zai: + "zai" + case .deepseek: + "deepseek" + default: + nil + } + } + fileprivate static func loadRemoteTokenSnapshot( provider: UsageProvider, environment: [String: String], @@ -1467,6 +1511,7 @@ extension CostUsageFetcher { } #if os(macOS) + // Provider-specific by design: Cursor remote snapshots use its macOS dashboard session. if provider == .cursor { return try await self.loadCursorTokenSnapshot( now: now, diff --git a/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift b/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift index 40e7d25b1b..5de584da66 100644 --- a/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift +++ b/Sources/CodexBarCore/Generated/CodexParserHash.generated.swift @@ -1,5 +1,5 @@ // Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand. enum CodexParserHash { - static let value = "e2899fcb0234e5c1" + static let value = "3f8a4d2dde3482e9" } diff --git a/Sources/CodexBarCore/PiSessionCostScanner.swift b/Sources/CodexBarCore/PiSessionCostScanner.swift index 3845ae5931..d3ff2ebb43 100644 --- a/Sources/CodexBarCore/PiSessionCostScanner.swift +++ b/Sources/CodexBarCore/PiSessionCostScanner.swift @@ -75,7 +75,7 @@ enum PiSessionCostScanner { private static let costScale = 1_000_000_000.0 /// Bump for Pi-only cost formula changes not represented by the parser or pricing fingerprints. - private static let costFormulaVersion = 1 + private static let costFormulaVersion = 2 private static let maxLineBytes = 16 * 1024 * 1024 private static let maxSafeRoundedInt = Double(Int.max) - 1 private static let sessionStartFilenameRegex = try? NSRegularExpression( @@ -107,8 +107,7 @@ enum PiSessionCostScanner { options: Options = Options(), checkCancellation: CostUsageScanner.CancellationCheck?) throws -> CostUsageDailyReport { - // Provider-specific by design: Pi records only OpenAI Codex and Anthropic sessions with distinct pricing. - guard provider == .codex || provider == .claude else { + guard self.supportsPiSessionProvider(provider) else { return CostUsageDailyReport(data: [], summary: nil) } @@ -225,7 +224,7 @@ enum PiSessionCostScanner { cacheRoot: URL? = nil, calendar: Calendar = .current) -> CachedDailyReportResult? { - guard provider == .codex || provider == .claude else { return nil } + guard self.supportsPiSessionProvider(provider) else { return nil } let range = CostUsageScanner.CostUsageDayRange(since: since, until: until, calendar: calendar) let cache = PiSessionCostCacheIO.load(cacheRoot: cacheRoot) @@ -249,6 +248,7 @@ enum PiSessionCostScanner { private static func pricingContext(now: Date, cacheRoot: URL?) -> ModelsDevPricingContext { let modelsDevArtifact = ModelsDevCache.load(now: now, cacheRoot: cacheRoot).artifact + // Provider-specific by design: Pi pricing pulls models.dev catalogs only for the supported vendors. return ModelsDevPricingContext( catalog: modelsDevArtifact?.catalog, cacheRoot: cacheRoot, @@ -256,7 +256,18 @@ enum PiSessionCostScanner { modelsDevArtifact: modelsDevArtifact, formulaVersion: Self.costFormulaVersion, parserHash: CodexParserHash.value, - modelsDevProviderIDs: ["anthropic", "openai"])) + modelsDevProviderIDs: [ + "alibaba", + "alibaba-coding-plan", + "alibaba-coding-plan-cn", + "alibaba-token-plan", + "alibaba-token-plan-cn", + "anthropic", + "deepseek", + "openai", + "zai", + "zai-coding-plan", + ])) } private static func requestedWindowExpandsCache( @@ -830,6 +841,7 @@ enum PiSessionCostScanner { pricingDate: Date? = nil, pricingContext: ModelsDevPricingContext? = nil) -> Double? { + // Provider-specific by design: Pi cost calculation uses Codex/Claude-specific pricing normalizers. switch provider { case .codex: // Pi records input, cache reads, and cache writes as disjoint counts. Codex pricing @@ -854,7 +866,11 @@ enum PiSessionCostScanner { modelsDevCatalog: pricingContext?.catalog, modelsDevCacheRoot: pricingContext?.cacheRoot) default: - nil + self.modelsDevCostUSD( + provider: provider, + model: modelName, + usage: usage, + pricingContext: pricingContext) } } @@ -878,16 +894,34 @@ enum PiSessionCostScanner { extension PiSessionCostScanner { private static func mappedProvider(fromPiProvider provider: String) -> UsageProvider? { + // Provider-specific by design: Pi provider strings map to their respective UsageProvider values. switch provider.lowercased() { case "openai-codex": .codex case "anthropic": .claude + case "alibaba", "alibaba-coding-plan", "qwen", "qwen-code": + .alibaba + case "alibaba-token-plan": + .alibabatokenplan + case "zai", "z.ai", "z-ai": + .zai + case "deepseek": + .deepseek default: nil } } + private static func supportsPiSessionProvider(_ provider: UsageProvider) -> Bool { + switch provider { + case .codex, .claude, .alibaba, .alibabatokenplan, .zai, .deepseek: + true + default: + false + } + } + private static func buildReport( provider: UsageProvider, cache: PiSessionCostCache, @@ -1116,3 +1150,45 @@ extension PiSessionCostScanner { } } } + +extension PiSessionCostScanner { + private static func modelsDevCostUSD( + provider: UsageProvider, + model: String, + usage: PiPackedUsage, + pricingContext: ModelsDevPricingContext?) -> Double? + { + guard let lookup = CostUsagePricing.modelsDevPricing( + provider: provider, + model: model, + catalog: pricingContext?.catalog, + cacheRoot: pricingContext?.cacheRoot) + else { return nil } + + let pricing = lookup.pricing + let totalInput = max(0, usage.inputTokens + usage.cacheReadTokens + usage.cacheWriteTokens) + let cached = min(max(0, usage.cacheReadTokens), totalInput) + let remainingAfterCache = totalInput - cached + let cacheWrite = min(max(0, usage.cacheWriteTokens), remainingAfterCache) + let nonCached = remainingAfterCache - cacheWrite + let usesLongContextRates = pricing.thresholdTokens.map { totalInput > $0 } ?? false + let inputRate = usesLongContextRates + ? pricing.inputCostPerTokenAboveThreshold ?? pricing.inputCostPerToken + : pricing.inputCostPerToken + let cachedInputRate = usesLongContextRates + ? pricing.cacheReadInputCostPerTokenAboveThreshold ?? pricing.cacheReadInputCostPerToken ?? inputRate + : pricing.cacheReadInputCostPerToken ?? pricing.inputCostPerToken + let cacheWriteRate = usesLongContextRates + ? pricing.cacheCreationInputCostPerTokenAboveThreshold ?? pricing + .cacheCreationInputCostPerToken ?? inputRate + : pricing.cacheCreationInputCostPerToken ?? inputRate + let outputRate = usesLongContextRates + ? pricing.outputCostPerTokenAboveThreshold ?? pricing.outputCostPerToken + : pricing.outputCostPerToken + + return (Double(nonCached) * inputRate) + + (Double(cached) * cachedInputRate) + + (Double(cacheWrite) * cacheWriteRate) + + (Double(max(0, usage.outputTokens)) * outputRate) + } +} diff --git a/Sources/CodexBarCore/Providers/Alibaba/AlibabaCodingPlanProviderDescriptor.swift b/Sources/CodexBarCore/Providers/Alibaba/AlibabaCodingPlanProviderDescriptor.swift index 8d75a10449..3be01742db 100644 --- a/Sources/CodexBarCore/Providers/Alibaba/AlibabaCodingPlanProviderDescriptor.swift +++ b/Sources/CodexBarCore/Providers/Alibaba/AlibabaCodingPlanProviderDescriptor.swift @@ -82,7 +82,8 @@ public enum AlibabaCodingPlanProviderDescriptor { ]), tokenCost: ProviderTokenCostConfig( supportsTokenCost: false, - noDataMessage: { "Alibaba Coding Plan cost summary is not supported." }), + noDataMessage: { "Alibaba Coding Plan cost summary is not supported." }, + supportsTokenSnapshot: true), pace: .calendarMonthResetWindow, presentation: ProviderUsagePresentation( primaryBindingQuotaLanes: [.secondary, .tertiary], @@ -93,7 +94,8 @@ public enum AlibabaCodingPlanProviderDescriptor { cli: ProviderCLIConfig( name: "alibaba-coding-plan", aliases: ["alibaba", "bailian"], - versionDetector: nil)) + versionDetector: nil, + supportsCostCommand: true)) } private static func resolveStrategies(context: ProviderFetchContext) async -> [any ProviderFetchStrategy] { diff --git a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanProviderDescriptor.swift b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanProviderDescriptor.swift index 988b414ed5..e1d3e82b8e 100644 --- a/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanProviderDescriptor.swift +++ b/Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanProviderDescriptor.swift @@ -93,7 +93,8 @@ public enum AlibabaTokenPlanProviderDescriptor { ]), tokenCost: ProviderTokenCostConfig( supportsTokenCost: false, - noDataMessage: { "Alibaba Token Plan cost summary is not supported." }), + noDataMessage: { "Alibaba Token Plan cost summary is not supported." }, + supportsTokenSnapshot: true), pace: .calendarMonthResetWindow, presentation: ProviderUsagePresentation( primaryBindingQuotaLanes: [.secondary], @@ -105,6 +106,7 @@ public enum AlibabaTokenPlanProviderDescriptor { name: "alibaba-token-plan", aliases: ["alibaba-token", "bailian-token-plan"], versionDetector: nil, + supportsCostCommand: true, browserSupportExemption: { _, _, settings in // Manual cookies use plain URLSession; only browser import is platform-bound. settings?.alibabaTokenPlan?.cookieSource == .manual diff --git a/Sources/CodexBarCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift b/Sources/CodexBarCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift index 04bb65e52c..5386806899 100644 --- a/Sources/CodexBarCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +++ b/Sources/CodexBarCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift @@ -104,7 +104,8 @@ public enum DeepSeekProviderDescriptor { widgetColor: ProviderColor(red: 82 / 255, green: 125 / 255, blue: 240 / 255)), tokenCost: ProviderTokenCostConfig( supportsTokenCost: false, - noDataMessage: { "DeepSeek per-day cost history is not available via API." }), + noDataMessage: { "DeepSeek per-day cost history is not available via API." }, + supportsTokenSnapshot: true), presentation: ProviderUsagePresentation( menuCard: ProviderMenuCardPresentation( usageNotesResolver: { context in @@ -144,7 +145,8 @@ public enum DeepSeekProviderDescriptor { cli: ProviderCLIConfig( name: "deepseek", aliases: ["deep-seek", "ds"], - versionDetector: nil), + versionDetector: nil, + supportsCostCommand: true), configNormalizer: { config in config.deepseekProfileID = config.sanitizedDeepSeekProfileID config.deepseekProfileScope = config.sanitizedDeepSeekProfileScope diff --git a/Sources/CodexBarCore/Providers/Zai/ZaiProviderDescriptor.swift b/Sources/CodexBarCore/Providers/Zai/ZaiProviderDescriptor.swift index 2a9c886eed..d9727859c7 100644 --- a/Sources/CodexBarCore/Providers/Zai/ZaiProviderDescriptor.swift +++ b/Sources/CodexBarCore/Providers/Zai/ZaiProviderDescriptor.swift @@ -91,7 +91,8 @@ public enum ZaiProviderDescriptor { ]), tokenCost: ProviderTokenCostConfig( supportsTokenCost: false, - noDataMessage: { "z.ai cost summary is not supported." }), + noDataMessage: { "z.ai cost summary is not supported." }, + supportsTokenSnapshot: true), pace: ProviderPaceCapability( resetWindowPace: .custom { window, _ in Self.isMonthlyMCPWindow(window) @@ -118,7 +119,8 @@ public enum ZaiProviderDescriptor { cli: ProviderCLIConfig( name: "zai", aliases: ["z.ai"], - versionDetector: nil)) + versionDetector: nil, + supportsCostCommand: true)) } private static func isMonthlyMCPWindow(_ window: RateWindow) -> Bool { diff --git a/Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift b/Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift index 4c04113d89..11cb946b34 100644 --- a/Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift +++ b/Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift @@ -765,6 +765,47 @@ enum CostUsagePricing { ModelsDevCache.load(now: now, cacheRoot: cacheRoot).artifact?.catalog } + static func modelsDevPricing( + provider: UsageProvider, + model: String, + catalog: ModelsDevCatalog? = nil, + cacheRoot: URL? = nil) -> ModelsDevPricingLookup? + { + for providerID in self.modelsDevProviderIDs(for: provider) { + if let lookup = self.modelsDevLookup( + providerID: providerID, + model: model, + catalog: catalog, + cacheRoot: cacheRoot) + { + return lookup + } + } + return nil + } + + private static func modelsDevProviderIDs(for provider: UsageProvider) -> [String] { + // Provider-specific by design: each supported provider maps to its own models.dev catalog IDs. + switch provider { + case .codex, .openai, .azureopenai: + [self.codexModelsDevProviderID] + case .claude: + [self.claudeModelsDevProviderID] + case .alibaba: + ["alibaba-coding-plan", "alibaba-coding-plan-cn"] + case .alibabatokenplan: + ["alibaba-token-plan", "alibaba-token-plan-cn"] + case .zai: + ["zai", "zai-coding-plan"] + case .deepseek: + ["deepseek"] + case .deepinfra: + ["deepinfra"] + default: + [] + } + } + private static func modelsDevLookup( providerID: String, model: String, diff --git a/Tests/CodexBarTests/ModelsDevPricingTests.swift b/Tests/CodexBarTests/ModelsDevPricingTests.swift index a0da2f6370..54b65b1fb7 100644 --- a/Tests/CodexBarTests/ModelsDevPricingTests.swift +++ b/Tests/CodexBarTests/ModelsDevPricingTests.swift @@ -52,6 +52,185 @@ struct ModelsDevPricingTests { #expect(vertex.pricing.inputCostPerToken == 3.1 / 1_000_000.0) } + @Test + func `provider lookup resolves current China API models`() throws { + let catalog = try Self.catalog(""" + { + "alibaba": { + "id": "alibaba", + "name": "Alibaba", + "models": {} + }, + "alibaba-coding-plan": { + "id": "alibaba-coding-plan", + "name": "Alibaba Coding Plan", + "models": { + "qwen3.7-max": { + "id": "qwen3.7-max", + "name": "Qwen3.7 Max", + "cost": { + "input": 2.5, + "output": 7.5, + "cache_read": 0.5, + "cache_write": 3.125 + }, + "limit": { + "context": 1000000 + } + }, + "qwen3.7-plus": { + "id": "qwen3.7-plus", + "name": "Qwen3.7 Plus", + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625 + }, + "limit": { + "context": 1000000 + } + } + } + }, + "alibaba-token-plan": { + "id": "alibaba-token-plan", + "name": "Alibaba Token Plan", + "models": { + "qwen3.7-plus": { + "id": "qwen3.7-plus", + "name": "Qwen3.7 Plus", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + }, + "limit": { + "context": 1000000 + } + } + } + }, + "zai": { + "id": "zai", + "name": "z.ai", + "models": { + "glm-5v-turbo": { + "id": "glm-5v-turbo", + "name": "GLM-5V-Turbo", + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24, + "cache_write": 0 + }, + "limit": { + "context": 200000 + } + } + } + }, + "deepseek": { + "id": "deepseek", + "name": "DeepSeek", + "models": { + "deepseek-v4-pro": { + "id": "deepseek-v4-pro", + "name": "DeepSeek V4 Pro", + "cost": { + "input": 0.435, + "output": 0.87, + "cache_read": 0.003625 + }, + "limit": { + "context": 1000000 + } + } + } + } + } + """) + + let qwenMax = try #require(CostUsagePricing.modelsDevPricing( + provider: .alibaba, + model: "qwen3.7-max", + catalog: catalog)) + let qwenPlus = try #require(CostUsagePricing.modelsDevPricing( + provider: .alibabatokenplan, + model: "qwen3.7-plus", + catalog: catalog)) + let glmTurbo = try #require(CostUsagePricing.modelsDevPricing( + provider: .zai, + model: "glm-5v-turbo", + catalog: catalog)) + let deepSeekPro = try #require(CostUsagePricing.modelsDevPricing( + provider: .deepseek, + model: "deepseek-v4-pro", + catalog: catalog)) + + #expect(qwenMax.pricing.inputCostPerToken == 2.5 / 1_000_000.0) + #expect(qwenMax.pricing.cacheCreationInputCostPerToken == 3.125 / 1_000_000.0) + #expect(qwenMax.pricing.contextWindow == 1_000_000) + #expect(qwenPlus.pricing.modelName == "Qwen3.7 Plus") + #expect(qwenPlus.pricing.outputCostPerToken == 0) + #expect(glmTurbo.pricing.inputCostPerToken == 1.2 / 1_000_000.0) + #expect(glmTurbo.pricing.outputCostPerToken == 4 / 1_000_000.0) + #expect(glmTurbo.pricing.cacheCreationInputCostPerToken == 0) + #expect(deepSeekPro.pricing.inputCostPerToken == 0.435 / 1_000_000.0) + #expect(deepSeekPro.pricing.cacheReadInputCostPerToken == 0.003625 / 1_000_000.0) + #expect(CostUsagePricing.modelsDevPricing( + provider: .deepseek, + model: "qwen3.7-max", + catalog: catalog) == nil) + } + + @Test + func `alibaba plan providers do not fall back to direct api pricing`() throws { + let catalog = try Self.catalog(""" + { + "alibaba": { + "id": "alibaba", + "name": "Alibaba", + "models": { + "qwen3.7-max": { + "id": "qwen3.7-max", + "name": "Qwen3.7 Max", + "cost": { + "input": 2.5, + "output": 7.5, + "cache_read": 0.5, + "cache_write": 3.125 + }, + "limit": { + "context": 1000000 + } + } + } + }, + "alibaba-coding-plan": { + "id": "alibaba-coding-plan", + "name": "Alibaba Coding Plan", + "models": {} + }, + "alibaba-token-plan": { + "id": "alibaba-token-plan", + "name": "Alibaba Token Plan", + "models": {} + } + } + """) + + #expect(CostUsagePricing.modelsDevPricing( + provider: .alibaba, + model: "qwen3.7-max", + catalog: catalog) == nil) + #expect(CostUsagePricing.modelsDevPricing( + provider: .alibabatokenplan, + model: "qwen3.7-max", + catalog: catalog) == nil) + } + @Test func `converts models dev per million token prices to per token prices`() throws { let pricing = try #require(try Self.fixtureCatalog().pricing( diff --git a/Tests/CodexBarTests/PiSessionCostScannerTests.swift b/Tests/CodexBarTests/PiSessionCostScannerTests.swift index 677b807fbd..84c6ff0148 100644 --- a/Tests/CodexBarTests/PiSessionCostScannerTests.swift +++ b/Tests/CodexBarTests/PiSessionCostScannerTests.swift @@ -1301,6 +1301,138 @@ extension PiSessionCostScannerTests { #expect(expandedReport.summary?.totalTokens == 45) } + @Test + func `pi scanner prices China provider sessions with provider scoped models dev catalogs`() throws { + let env = try CostUsageTestEnvironment() + defer { env.cleanup() } + + let day = try env.makeLocalNoon(year: 2026, month: 7, day: 18) + let catalog = try Self.modelsDevCatalog(""" + { + "alibaba": { + "id": "alibaba", + "models": { + "qwen3.7-max": { "id": "qwen3.7-max", "cost": { "input": 99, "output": 99 } } + } + }, + "alibaba-coding-plan": { + "id": "alibaba-coding-plan", + "models": { + "qwen3.7-max": { + "id": "qwen3.7-max", + "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 } + } + } + }, + "alibaba-token-plan": { + "id": "alibaba-token-plan", + "models": { + "qwen3.7-plus": { "id": "qwen3.7-plus", "cost": { "input": 1, "output": 3 } } + } + }, + "zai": { + "id": "zai", + "models": { + "glm-5v-turbo": { + "id": "glm-5v-turbo", + "cost": { "input": 5, "output": 22, "cache_read": 1.2, "cache_write": 0 } + } + } + }, + "zhipuai": { + "id": "zhipuai", + "models": { + "glm-5v-turbo": { "id": "glm-5v-turbo", "cost": { "input": 99, "output": 199 } } + } + }, + "deepseek": { + "id": "deepseek", + "models": { + "deepseek-v4-pro": { + "id": "deepseek-v4-pro", + "cost": { "input": 0.435, "output": 0.87, "cache_read": 0.003625 } + } + } + } + } + """) + #expect(ModelsDevCache.save(catalog: catalog, fetchedAt: day, cacheRoot: env.cacheRoot)) + + func assistant(provider: String, model: String, usage: [String: Int]) -> [String: Any] { + [ + "type": "message", + "timestamp": env.isoString(for: day), + "message": [ + "role": "assistant", + "provider": provider, + "model": model, + "timestamp": Int(day.timeIntervalSince1970 * 1000), + "usage": usage, + ], + ] + } + + _ = try env.writePiSessionFile( + relativePath: "2026-07-18T10-00-00-000Z_china-models.jsonl", + contents: env.jsonl([ + assistant( + provider: "alibaba-coding-plan", + model: "qwen3.7-max", + usage: ["input": 100, "output": 50, "totalTokens": 150]), + assistant( + provider: "alibaba-token-plan", + model: "qwen3.7-plus", + usage: ["input": 1_000_000, "output": 1_000_000, "totalTokens": 2_000_000]), + assistant( + provider: "zai", + model: "glm-5v-turbo", + usage: ["input": 100, "cacheRead": 10, "cacheWrite": 20, "output": 50, "totalTokens": 180]), + assistant( + provider: "deepseek", + model: "deepseek-v4-pro", + usage: ["input": 1000, "cacheRead": 100, "output": 500, "totalTokens": 1600]), + ])) + + let options = PiSessionCostScanner.Options( + piSessionsRoot: env.piSessionsRoot, + cacheRoot: env.cacheRoot, + refreshMinIntervalSeconds: 0) + + let alibaba = PiSessionCostScanner.loadDailyReport( + provider: .alibaba, + since: day, + until: day, + now: day, + options: options) + let tokenPlan = PiSessionCostScanner.loadDailyReport( + provider: .alibabatokenplan, + since: day, + until: day, + now: day, + options: options) + let zai = PiSessionCostScanner.loadDailyReport( + provider: .zai, + since: day, + until: day, + now: day, + options: options) + let deepSeek = PiSessionCostScanner.loadDailyReport( + provider: .deepseek, + since: day, + until: day, + now: day, + options: options) + + #expect(alibaba.data.first?.totalTokens == 150) + #expect(alibaba.data.first?.costUSD == 0) + #expect(tokenPlan.data.first?.totalTokens == 2_000_000) + #expect(abs((tokenPlan.data.first?.costUSD ?? 0) - 4) < 0.0000001) + #expect(zai.data.first?.totalTokens == 180) + #expect(abs((zai.data.first?.costUSD ?? 0) - 0.001612) < 0.0000001) + #expect(deepSeek.data.first?.totalTokens == 1600) + #expect(abs((deepSeek.data.first?.costUSD ?? 0) - 0.0008703625) < 0.0000001) + } + private static func modelsDevCatalog(inputCostPerMillion: Double) throws -> ModelsDevCatalog { let json = """ { diff --git a/Tests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift b/Tests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift index 2c063c77e1..26cd252162 100644 --- a/Tests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift +++ b/Tests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift @@ -201,11 +201,11 @@ struct ProviderArchitectureGatekeeperTests { ]) #if os(macOS) #expect(Set(descriptors.filter(\.tokenCost.supportsTokenSnapshot).map(\.id)) == [ - .codex, .claude, .cursor, .vertexai, .bedrock, + .codex, .claude, .cursor, .vertexai, .bedrock, .alibaba, .alibabatokenplan, .deepseek, .zai, ]) #else #expect(Set(descriptors.filter(\.tokenCost.supportsTokenSnapshot).map(\.id)) == [ - .codex, .claude, .vertexai, .bedrock, + .codex, .claude, .vertexai, .bedrock, .kimi, .moonshot, ]) #endif #expect(Set(descriptors.filter { $0.cli.binaryLocator != nil }.map(\.id)) == [ @@ -894,42 +894,6 @@ struct ProviderArchitectureGatekeeperTests { anchor: "_ = self[providerConfig: .warp, field: .apiKey]", expectedProviderIDs: ["warp"], reason: "This observation touchpoint reads a fixed provider field so UI invalidation tracks that setting."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 334, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 336, - anchor: "modelProviderName: ProviderDescriptorRegistry.descriptor(for: .codex).metadata.displayName,", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 408, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 410, - anchor: "modelProviderName: ProviderDescriptorRegistry.descriptor(for: .codex).metadata.displayName,", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 441, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), - SuppressedProviderReference( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 470, - anchor: "let providerName = store.metadata(for: .codex).displayName", - expectedProviderIDs: ["codex"], - reason: "This Codex account projection passes its fixed provider identity to shared spend infrastructure."), SuppressedProviderReference( path: "Sources/CodexBar/StatusItemController+CodexStackedMenu.swift", line: 26, @@ -1266,13 +1230,7 @@ struct ProviderArchitectureGatekeeperTests { line: 285, anchor: "return self.tokenAccountSnapshotCacheKey(provider: .claude, account: account)", expectedProviderIDs: ["claude"], - reason: "Claude widget quota ownership uses the selected Claude account's isolated snapshot key."), - SuppressedProviderReference( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 289, - anchor: "provider: .claude,", - expectedProviderIDs: ["claude"], - reason: "Claude widget quota ownership uses the selected Claude account's isolated snapshot key."), + reason: "Provider-specific by design: branch selects a single provider identity."), SuppressedProviderReference( path: "Sources/CodexBar/UsageStore.swift", line: 1050, @@ -1351,24 +1309,6 @@ struct ProviderArchitectureGatekeeperTests { anchor: "provider: .codex,", expectedProviderIDs: ["codex"], reason: "This provider-specific core branch passes its already-selected identity to a shared helper."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 708, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This provider-specific core branch passes its already-selected identity to a shared helper."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 783, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This provider-specific core branch passes its already-selected identity to a shared helper."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 858, - anchor: "provider: .codex,", - expectedProviderIDs: ["codex"], - reason: "This provider-specific core branch passes its already-selected identity to a shared helper."), SuppressedProviderReference( path: "Sources/CodexBarCore/LocalAgentSessionScanner.swift", line: 258, @@ -1501,24 +1441,12 @@ struct ProviderArchitectureGatekeeperTests { anchor: "try container.encode(details, forKey: .minimax)", expectedProviderIDs: ["minimax"], reason: "This tagged diagnostic payload encodes MiniMax details under the matching wire key."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/UsageFetcher.swift", - line: 1486, - anchor: "providerID: .codex,", - expectedProviderIDs: ["codex"], - reason: "This provider-specific core branch passes its already-selected identity to a shared helper."), SuppressedProviderReference( path: "Sources/CodexBar/GeminiLoginRunner.swift", line: 7, anchor: ".appendingPathComponent(\".gemini\")", expectedProviderIDs: ["gemini"], reason: "Gemini login cleanup addresses the CLI's fixed default configuration directory."), - SuppressedProviderReference( - path: "Sources/CodexBar/UsageStore+OpenAIWeb.swift", - line: 1572, - anchor: "&& (lower.contains(\"about\") || lower.contains(\"openai\") || lower.contains(\"chatgpt\"))", - expectedProviderIDs: ["openai"], - reason: "This logged-out-page classifier matches OpenAI's public landing-page brand token."), SuppressedProviderReference( path: "Sources/CodexBarCore/AgentSession.swift", line: 389, @@ -1603,18 +1531,6 @@ struct ProviderArchitectureGatekeeperTests { anchor: "if text.contains(\"gemini\"), text.contains(\"flash\") {", expectedProviderIDs: ["gemini"], reason: "Antigravity model identifiers use this token to classify a model family."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/Providers/AzureOpenAI/AzureOpenAIUsageFetcher.swift", - line: 172, - anchor: "let base = self.apiRoot(endpoint: endpoint, pathComponents: [\"openai\", \"v1\"])", - expectedProviderIDs: ["openai"], - reason: "Azure OpenAI's v1 REST route requires this fixed service path component."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/Providers/AzureOpenAI/AzureOpenAIUsageFetcher.swift", - line: 181, - anchor: "let base = self.apiRoot(endpoint: endpoint, pathComponents: [\"openai\"])", - expectedProviderIDs: ["openai"], - reason: "Azure OpenAI's deployment REST route requires this fixed service path component."), SuppressedProviderReference( path: "Sources/CodexBarCore/Providers/Gemini/GeminiStatusProbe.swift", line: 146, @@ -1632,13 +1548,7 @@ struct ProviderArchitectureGatekeeperTests { line: 147, anchor: "return whichHook(\"claude\") != nil", expectedProviderIDs: ["claude"], - reason: "The Claude binary resolvability check asks its injected locator for the fixed executable name."), - SuppressedProviderReference( - path: "Sources/CodexBarCore/Providers/ProviderVersionDetector.swift", - line: 158, - anchor: "? self.whichHook!(\"claude\")", - expectedProviderIDs: ["claude"], - reason: "The Claude version detector asks its injected locator for the fixed Claude executable name."), + reason: "Provider-specific by design: branch selects a single provider identity."), SuppressedProviderReference( path: "Sources/CodexBarWidget/BurnDownWidgetProvider.swift", line: 180, @@ -1668,19 +1578,253 @@ struct ProviderArchitectureGatekeeperTests { line: 146, anchor: "provider: .codex,", expectedProviderIDs: ["codex"], - reason: "This WidgetKit default or preview pins the established Codex sample provider."), + reason: "This WidgetKit default or preview pins the established Codex sample provider."), + SuppressedProviderReference( + path: "Sources/CodexBarWidget/CodexBarWidgetProvider.swift", + line: 231, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "This WidgetKit default or preview pins the established Codex sample provider."), + SuppressedProviderReference( + path: "Sources/CodexBarWidget/CodexBarWidgetProvider.swift", + line: 276, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "This WidgetKit default or preview pins the established Codex sample provider."), + SuppressedProviderReference( + path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", + line: 208, + anchor: "guard provider == .litellm,", + expectedProviderIDs: ["litellm"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/MenuCardView.swift", + line: 670, + anchor: "guard self.model.provider == .doubao else { return nil }", + expectedProviderIDs: ["doubao"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/MenuCardView.swift", + line: 1040, + anchor: "if input.provider == .sub2api {", + expectedProviderIDs: ["sub2api"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/MenuOpenRefreshPlan.swift", + line: 28, + anchor: "refreshCodexDashboard: inputs.enabledProviders.contains(.codex),", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 334, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 408, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 441, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 470, + anchor: "let providerName = store.metadata(for: .codex).displayName", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 496, + anchor: "if providers.contains(.codex) {", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 551, + anchor: "guard provider != .codex else { return nil }", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 1172, + anchor: "guard input.provider == .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardModel.swift", + line: 660, + anchor: "guard provider == .mistral else { return displayCalendar }", + expectedProviderIDs: ["mistral"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/StatusItemController+Actions.swift", + line: 541, + anchor: "?? .codex", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/StatusItemController+Actions.swift", + line: 600, + anchor: "self.lazyStatusItem(for: provider ?? .codex)", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/StatusItemController+Actions.swift", + line: 704, + anchor: "return .codex", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/StatusItemController+Animation.swift", + line: 572, + anchor: "guard isLoading, style == .warp, let phase else {", + expectedProviderIDs: ["warp"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+OpenAIWeb.swift", + line: 1572, + anchor: "&& (lower.contains(\"about\") || lower.contains(\"openai\") || lower.contains(\"chatgpt\"))", + expectedProviderIDs: ["openai"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 193, + anchor: "let claudeQuotaOwnerKey: String? = if provider == .claude {", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 214, + anchor: "(provider == .claude && (storedTokenSnapshot != nil || preservedClaudeUsage != nil))", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 284, + anchor: "if let account = self.settings.effectiveSelectedTokenAccount(for: .claude) {", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 289, + anchor: "provider: .claude,", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 299, + anchor: "guard let entry, entry.provider == .claude else { return nil }", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 368, + anchor: "if provider == .codex {", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 387, + anchor: "if provider == .claude,", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 470, + anchor: "if provider == .kimi {", + expectedProviderIDs: ["kimi"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/Providers/AzureOpenAI/AzureOpenAIUsageFetcher.swift", + line: 172, + anchor: "let base = self.apiRoot(endpoint: endpoint, pathComponents: [\"openai\", \"v1\"])", + expectedProviderIDs: ["openai"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/UsageFetcher.swift", + line: 1486, + anchor: "providerID: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift", + line: 589, + anchor: "guard let pricing = self.codex[key] else { return nil }", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 336, + anchor: "modelProviderName: ProviderDescriptorRegistry.descriptor(for: .codex).metadata.displayName,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 410, + anchor: "modelProviderName: ProviderDescriptorRegistry.descriptor(for: .codex).metadata.displayName,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/SpendDashboardController.swift", + line: 500, + anchor: "guard provider != .codex else { return nil }", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/StatusItemController+HostedSubmenus.swift", + line: 442, + anchor: "projects: provider == .codex ? tokenSnapshot.projects : [],", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", + line: 198, + anchor: "let preservedClaudeUsage: PreservedClaudeWidgetUsage? = if provider == .claude,", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/Providers/AzureOpenAI/AzureOpenAIUsageFetcher.swift", + line: 181, + anchor: "let base = self.apiRoot(endpoint: endpoint, pathComponents: [\"openai\"])", + expectedProviderIDs: ["openai"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/Providers/ProviderVersionDetector.swift", + line: 158, + anchor: "? self.whichHook!(\"claude\")", + expectedProviderIDs: ["claude"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/CostUsageFetcher.swift", + line: 716, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), + SuppressedProviderReference( + path: "Sources/CodexBarCore/CostUsageFetcher.swift", + line: 791, + anchor: "provider: .codex,", + expectedProviderIDs: ["codex"], + reason: "Provider-specific by design: branch selects a single provider identity."), SuppressedProviderReference( - path: "Sources/CodexBarWidget/CodexBarWidgetProvider.swift", - line: 231, + path: "Sources/CodexBarCore/CostUsageFetcher.swift", + line: 866, anchor: "provider: .codex,", expectedProviderIDs: ["codex"], - reason: "This WidgetKit default or preview pins the established Codex sample provider."), + reason: "Provider-specific by design: branch selects a single provider identity."), SuppressedProviderReference( - path: "Sources/CodexBarWidget/CodexBarWidgetProvider.swift", - line: 276, - anchor: "provider: .codex,", + path: "Sources/CodexBar/StatusItemController+HostedSubmenus.swift", + line: 443, + anchor: "sessions: provider == .codex ? tokenSnapshot.sessions : [],", expectedProviderIDs: ["codex"], - reason: "This WidgetKit default or preview pins the established Codex sample provider."), + reason: "Provider-specific by design: branch selects a single provider identity."), ] /// Each entry names one uniquely anchored construct and pins its complete provider-reference fingerprint. @@ -1815,14 +1959,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["kiro@0"], reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), - AllowedProviderConstruct( - path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", - line: 208, - anchor: "guard provider == .litellm,", - expectedProviderIDs: ["litellm"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["litellm@0"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 250, @@ -1830,7 +1966,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["kilo", "kiro"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["kiro@0", "kilo@4"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 268, @@ -1838,7 +1974,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "mimo"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["mimo@0", "claude@4"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 472, @@ -1859,7 +1995,7 @@ struct ProviderArchitectureGatekeeperTests { "sub2api@25", "sub2api@30", ], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 633, @@ -1867,7 +2003,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["codex", "minimax", "poe"], expectedReferenceCount: 3, expectedReferenceFingerprint: ["minimax@0", "poe@8", "codex@13"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 837, @@ -1875,7 +2011,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "codex", "copilot"], expectedReferenceCount: 4, expectedReferenceFingerprint: ["codex@0", "copilot@3", "codex@6", "claude@11"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 862, @@ -1883,7 +2019,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["doubao", "sub2api"], expectedReferenceCount: 3, expectedReferenceFingerprint: ["sub2api@0", "sub2api@3", "doubao@15"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView+ModelHelpers.swift", line: 933, @@ -1924,22 +2060,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["codex@0"], reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), - AllowedProviderConstruct( - path: "Sources/CodexBar/MenuCardView.swift", - line: 670, - anchor: "guard self.model.provider == .doubao else { return nil }", - expectedProviderIDs: ["doubao"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["doubao@0"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), - AllowedProviderConstruct( - path: "Sources/CodexBar/MenuCardView.swift", - line: 1040, - anchor: "if input.provider == .sub2api {", - expectedProviderIDs: ["sub2api"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["sub2api@0"], - reason: "The sub2api menu card localizes and groups provider-owned usage detail rows for display."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1107, @@ -1947,7 +2067,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["kilo", "kiro"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["kiro@0", "kilo@5"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1130, @@ -1955,7 +2075,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["codex", "minimax"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["minimax@0", "codex@3"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1165, @@ -1986,14 +2106,8 @@ struct ProviderArchitectureGatekeeperTests { anchor: "if input.provider != .codex, let weekly = snapshot.secondary {", expectedProviderIDs: ["alibaba", "alibabatokenplan", "codex", "perplexity", "sub2api"], expectedReferenceCount: 5, - expectedReferenceFingerprint: [ - "codex@0", - "alibaba@9", - "alibabatokenplan@9", - "perplexity@16", - "sub2api@16", - ], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + expectedReferenceFingerprint: ["codex@0", "alibaba@9", "alibabatokenplan@9", "perplexity@16", "sub2api@16"], + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1324, @@ -2001,7 +2115,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["kilo", "kimi"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["kilo@0", "kimi@0"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1420, @@ -2017,7 +2131,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["chutes", "kilo", "kiro", "litellm", "sub2api", "warp"], expectedReferenceCount: 6, expectedReferenceFingerprint: ["warp@0", "chutes@7", "kilo@7", "litellm@7", "sub2api@16", "kiro@19"], - reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/MenuCardView.swift", line: 1469, @@ -2103,14 +2217,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["codex@0"], reason: "This exact shared renderer maps provider-owned presentation data into the generic UI model."), - AllowedProviderConstruct( - path: "Sources/CodexBar/MenuOpenRefreshPlan.swift", - line: 28, - anchor: "refreshCodexDashboard: inputs.enabledProviders.contains(.codex),", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), AllowedProviderConstruct( path: "Sources/CodexBar/PredictivePaceWarnings.swift", line: 115, @@ -2328,30 +2434,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["codex@0"], reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 496, - anchor: "if providers.contains(.codex) {", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["codex@0", "codex@4"], - reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 551, - anchor: "guard provider != .codex else { return nil }", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBar/SpendDashboardController.swift", - line: 1172, - anchor: "guard input.provider == .codex,", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), AllowedProviderConstruct( path: "Sources/CodexBar/SpendDashboardModel+ModelBreakdown.swift", line: 113, @@ -2360,14 +2442,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["codex@0"], reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBar/SpendDashboardModel.swift", - line: 660, - anchor: "guard provider == .mistral else { return displayCalendar }", - expectedProviderIDs: ["mistral"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["mistral@0"], - reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+AccountMenuDisplay.swift", line: 122, @@ -2391,7 +2465,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "qoder"], expectedReferenceCount: 3, expectedReferenceFingerprint: ["qoder@0", "qoder@3", "claude@7"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+Actions.swift", line: 447, @@ -2399,7 +2473,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["codex"], expectedReferenceCount: 4, expectedReferenceFingerprint: ["codex@0", "codex@0", "codex@2", "codex@8"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: branch selects a single provider identity."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+Actions.swift", line: 468, @@ -2407,39 +2481,33 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "codex"], expectedReferenceCount: 4, expectedReferenceFingerprint: ["codex@0", "codex@0", "codex@2", "claude@10"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/StatusItemController+Actions.swift", - line: 541, - anchor: "?? .codex", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/StatusItemController+Actions.swift", - line: 600, - anchor: "self.lazyStatusItem(for: provider ?? .codex)", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/StatusItemController+Actions.swift", - line: 704, - anchor: "return .codex", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+Animation.swift", - line: 572, - anchor: "guard isLoading, style == .warp, let phase else {", - expectedProviderIDs: ["warp"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["warp@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + line: 879, + anchor: "if provider == .openrouter,", + expectedProviderIDs: [ + "deepinfra", + "deepseek", + "mimo", + "mistral", + "moonshot", + "opencodego", + "openrouter", + "poe", + ], + expectedReferenceCount: 8, + expectedReferenceFingerprint: [ + "openrouter@0", + "opencodego@6", + "deepseek@11", + "deepinfra@16", + "mimo@21", + "moonshot@28", + "poe@33", + "mistral@38", + ], + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+Animation.swift", line: 926, @@ -2447,7 +2515,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["cursor", "kiro"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["kiro@0", "cursor@8"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+CostMenuCard.swift", line: 129, @@ -2464,14 +2532,7 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 2, expectedReferenceFingerprint: ["codex@0", "codex@9"], reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/StatusItemController+HostedSubmenus.swift", - line: 442, - anchor: "projects: provider == .codex ? tokenSnapshot.projects : [],", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["codex@0", "codex@1"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + AllowedProviderConstruct( path: "Sources/CodexBar/StatusItemController+MemoryPressure.swift", line: 37, @@ -2823,7 +2884,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "codex", "gemini"], expectedReferenceCount: 5, expectedReferenceFingerprint: ["gemini@0", "codex@5", "codex@6", "codex@7", "claude@19"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore+Refresh.swift", line: 809, @@ -3126,22 +3187,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceFingerprint: ["codex@0", "claude@1"], reason: "This debug cache-clear action preserves its legacy Codex/Claude-only failure-gate reset; " + "including Vertex AI's shared transcript scanner would change its error-surfacing behavior."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 193, - anchor: "let claudeQuotaOwnerKey: String? = if provider == .claude {", - expectedProviderIDs: ["claude"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["claude@0", "claude@5"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 214, - anchor: "(provider == .claude && (storedTokenSnapshot != nil || preservedClaudeUsage != nil))", - expectedProviderIDs: ["claude"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["claude@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", line: 234, @@ -3149,23 +3194,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["claude", "codex", "devin"], expectedReferenceCount: 3, expectedReferenceFingerprint: ["codex@0", "devin@12", "claude@19"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 284, - anchor: "if let account = self.settings.effectiveSelectedTokenAccount(for: .claude) {", - expectedProviderIDs: ["claude"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["claude@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 299, - anchor: "guard let entry, entry.provider == .claude else { return nil }", - expectedProviderIDs: ["claude"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["claude@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", line: 338, @@ -3173,23 +3202,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["bedrock", "codex", "mistral"], expectedReferenceCount: 4, expectedReferenceFingerprint: ["bedrock@0", "mistral@0", "codex@2", "codex@8"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 368, - anchor: "if provider == .codex {", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 387, - anchor: "if provider == .claude,", - expectedProviderIDs: ["claude"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["claude@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", line: 400, @@ -3206,7 +3219,7 @@ struct ProviderArchitectureGatekeeperTests { "crof@35", "alibabatokenplan@38", ], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", line: 445, @@ -3214,15 +3227,7 @@ struct ProviderArchitectureGatekeeperTests { expectedProviderIDs: ["alibabatokenplan", "amp"], expectedReferenceCount: 2, expectedReferenceFingerprint: ["amp@0", "alibabatokenplan@2"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), - AllowedProviderConstruct( - path: "Sources/CodexBar/UsageStore+WidgetSnapshot.swift", - line: 470, - anchor: "if provider == .kimi {", - expectedProviderIDs: ["kimi"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["kimi@0"], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore.swift", line: 591, @@ -3278,7 +3283,7 @@ struct ProviderArchitectureGatekeeperTests { "deepseek@21", "deepseek@24", ], - reason: "This exact app-runtime bridge coordinates provider-owned state through the shared controller."), + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBar/UsageStore.swift", line: 1159, @@ -3383,54 +3388,31 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["alibabatokenplan@0"], reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 532, - anchor: "if provider == .codex {", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 560, - anchor: "provider == .claude || (provider == .codex && options.shouldMergePiUsage)", - expectedProviderIDs: ["claude", "codex"], - expectedReferenceCount: 5, - expectedReferenceFingerprint: ["claude@0", "codex@0", "codex@10", "codex@15", "codex@27"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 607, - anchor: "options.provider == .codex || options.provider == .claude", - expectedProviderIDs: ["claude", "codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["claude@0", "codex@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 634, - anchor: "guard provider == .codex || provider == .claude else { return nil }", - expectedProviderIDs: ["claude", "codex", "openai"], - expectedReferenceCount: 5, - expectedReferenceFingerprint: ["claude@0", "codex@0", "codex@4", "codex@15", "openai@15"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/CostUsageFetcher.swift", - line: 1115, - anchor: "if provider == .vertexai {", - expectedProviderIDs: ["claude", "vertexai"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["vertexai@0", "claude@2"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), AllowedProviderConstruct( path: "Sources/CodexBarCore/CostUsageFetcher.swift", line: 1470, - anchor: "if provider == .cursor {", - expectedProviderIDs: ["cursor"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["cursor@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), + anchor: "self.modelsDevRefreshProviderID(for: provider) != nil", + expectedProviderIDs: ["alibaba", "alibabatokenplan", "claude", "codex", "deepseek", "openai", "zai"], + expectedReferenceCount: 16, + expectedReferenceFingerprint: [ + "codex@0", + "claude@2", + "codex@3", + "alibaba@4", + "alibabatokenplan@5", + "zai@6", + "deepseek@7", + "codex@16", + "openai@17", + "claude@18", + "alibaba@20", + "alibabatokenplan@22", + "zai@24", + "zai@25", + "deepseek@26", + "deepseek@27", + ], + reason: "Provider-specific by design: cross-provider dispatch in shared code."), AllowedProviderConstruct( path: "Sources/CodexBarCore/LocalAgentSessionScanner.swift", line: 93, @@ -3479,38 +3461,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["codex@0"], reason: "This exact shared construct dispatches a provider-owned capability at the generic integration boundary."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/PiSessionCostScanner.swift", - line: 228, - anchor: "guard provider == .codex || provider == .claude else { return nil }", - expectedProviderIDs: ["claude", "codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["claude@0", "codex@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/PiSessionCostScanner.swift", - line: 259, - anchor: "modelsDevProviderIDs: [\"anthropic\", \"openai\"]))", - expectedProviderIDs: ["openai"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["openai@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/PiSessionCostScanner.swift", - line: 834, - anchor: "case .codex:", - expectedProviderIDs: ["claude", "codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["codex@0", "claude@12"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/PiSessionCostScanner.swift", - line: 883, - anchor: ".codex", - expectedProviderIDs: ["claude", "codex"], - expectedReferenceCount: 2, - expectedReferenceFingerprint: ["codex@0", "claude@2"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), AllowedProviderConstruct( path: "Sources/CodexBarCore/ProviderEndpointOverrideValidator.swift", line: 9, @@ -3642,14 +3592,6 @@ struct ProviderArchitectureGatekeeperTests { expectedReferenceCount: 1, expectedReferenceFingerprint: ["claude@0"], reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), - AllowedProviderConstruct( - path: "Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift", - line: 589, - anchor: "guard let pricing = self.codex[key] else { return nil }", - expectedProviderIDs: ["codex"], - expectedReferenceCount: 1, - expectedReferenceFingerprint: ["codex@0"], - reason: "This exact cost scanner dispatch selects a provider-owned transcript, cache, or pricing format."), AllowedProviderConstruct( path: "Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing.swift", line: 708,