Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Sources/QuotaCore/QuotaModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ private enum ISO8601Date {
}
}

private enum QuotaProviders {
enum QuotaProviders {
struct Expected {
let key: String
let label: String
Expand Down Expand Up @@ -672,7 +672,12 @@ private enum QuotaProviders {
"minimax": "minimax", "minimax-code": "minimax",
"muse-assist": "muse-assist", "muse assist": "muse-assist", "muse_assist": "muse-assist", "muse-assistant": "muse-assist", "muse assistant": "muse-assist",
"muse-code": "muse-code", "muse code": "muse-code", "muse_code": "muse-code",
"muse": "muse-code", "muse-cli": "muse-code", "muse-sdk": "muse-code",
// `muse` is what `subscription-status-cli` reports, and its windows
// are "Additional tokens" / "Free weekly limit" -- Muse Assist, per
// the owner 2026-10-09. It was aliased to `muse-code` here, which
// filed every Assist reading under Muse Code: both rows then showed
// "no report" while the data sat in the handoff, correctly formed.
"muse": "muse-assist", "muse-cli": "muse-assist", "muse-sdk": "muse-assist",
"kimi": "kimi", "moonshot": "kimi", "moonshot-ai": "kimi",
"gemini-cli": "gemini-cli",
"copilot": "github-copilot", "github-copilot": "github-copilot", "github_copilot": "github-copilot",
Expand Down
54 changes: 54 additions & 0 deletions Tests/QuotaCoreTests/MuseProviderIdentityTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import XCTest
@testable import QuotaCore

/// Muse Assist and Muse Code are two different subscriptions, and the app
/// showed "no report" for both while the readings sat in the handoff.
///
/// The alias table mapped `muse` to `muse-code`. `subscription-status-cli`
/// reports Muse Assist's windows under the key `muse` ("Additional tokens",
/// "Free weekly limit"), so every one of them was rewritten to `muse-code`.
/// The expected-provider list asks for `muse-assist`, and nothing ever emitted
/// that key — so the Muse Assist row had no windows to show, and the rows that
/// did resolve carried the wrong subscription's numbers.
final class MuseProviderIdentityTests: XCTestCase {

/// The bug, stated directly: Muse Assist's own key must not be rewritten to
/// Muse Code's.
func testMuseIsMuseAssistNotMuseCode() {
XCTAssertEqual(QuotaProviders.canonicalKey(provider: "muse", providerKey: "muse", via: nil),
"muse-assist",
"'muse' is the key subscription-status-cli reports for Muse Assist")
}

/// The CLI spellings follow the same rule.
func testTheMuseCliAliasesFollowTheSameRule() {
for raw in ["muse-cli", "muse-sdk", "muse-assistant", "muse assistant"] {
XCTAssertEqual(QuotaProviders.canonicalKey(provider: raw, providerKey: raw, via: nil),
"muse-assist", "'\(raw)' should resolve to Muse Assist")
}
}

/// Muse Code keeps its own identity, from its own source.
func testMuseCodeKeepsItsOwnIdentity() {
for raw in ["muse-code", "muse code", "muse_code"] {
XCTAssertEqual(QuotaProviders.canonicalKey(provider: raw, providerKey: raw, via: nil),
"muse-code", "'\(raw)' should resolve to Muse Code")
}
}

/// Both rows are expected providers, so a missing reading reads as a real
/// absence rather than an unknown platform.
func testBothMuseProvidersAreExpected() {
let keys = Set(QuotaProviders.expected.map(\.key))
XCTAssertTrue(keys.contains("muse-assist"), "Muse Assist is missing from the expected list")
XCTAssertTrue(keys.contains("muse-code"), "Muse Code is missing from the expected list")
}

/// The regression that would bring the bug back: a window reported under
/// `muse` must land on the Muse Assist section, not Muse Code's.
func testAWindowKeyedMuseLandsOnMuseAssist() {
let canonical = QuotaProviders.canonicalKey(provider: "muse", providerKey: "muse", via: nil)
XCTAssertNotEqual(canonical, "muse-code",
"Muse Assist's readings are being filed under Muse Code again")
}
}
Loading