@@ -35,72 +35,50 @@ final class ModelQoSTests: XCTestCase {
3535 XCTAssertEqual ( ModelQoS . activeTier, . premium)
3636 }
3737
38- // MARK: - Claude models: premium tier
38+ // MARK: - Claude models are tier-independent
3939
40- func testClaudeModelsPremiumTier( ) {
41- ModelQoS . activeTier = . premium
42- XCTAssertEqual ( ModelQoS . Claude. chat, " claude-sonnet-4-6 " )
43- XCTAssertEqual ( ModelQoS . Claude. floatingBar, " claude-sonnet-4-6 " )
44- XCTAssertEqual ( ModelQoS . Claude. synthesis, " claude-sonnet-4-6 " )
45- }
46-
47- // MARK: - Claude models: max tier
48-
49- func testClaudeModelsMaxTier( ) {
50- ModelQoS . activeTier = . max
51- XCTAssertEqual ( ModelQoS . Claude. chat, " claude-opus-4-6 " )
52- XCTAssertEqual ( ModelQoS . Claude. floatingBar, " claude-sonnet-4-6 " )
53- XCTAssertEqual ( ModelQoS . Claude. synthesis, " claude-opus-4-6 " )
54- }
55-
56- // MARK: - Claude pinned models (tier-independent)
57-
58- func testClaudePinnedModelsIgnoreTier( ) {
40+ func testClaudeModelsIdenticalAcrossTiers( ) {
5941 for tier in ModelTier . allCases {
6042 ModelQoS . activeTier = tier
43+ XCTAssertEqual ( ModelQoS . Claude. chat, " claude-sonnet-4-6 " )
44+ XCTAssertEqual ( ModelQoS . Claude. floatingBar, " claude-sonnet-4-6 " )
45+ XCTAssertEqual ( ModelQoS . Claude. synthesis, " claude-haiku-4-5-20251001 " )
6146 XCTAssertEqual ( ModelQoS . Claude. chatLabQuery, " claude-sonnet-4-20250514 " )
6247 XCTAssertEqual ( ModelQoS . Claude. chatLabGrade, " claude-haiku-4-5-20251001 " )
6348 XCTAssertEqual ( ModelQoS . Claude. defaultSelection, " claude-sonnet-4-6 " )
6449 }
6550 }
6651
67- // MARK: - Available models reflect tier
68-
69- func testAvailableModelsPremiumTier( ) {
70- ModelQoS . activeTier = . premium
71- let ids = ModelQoS . Claude. availableModels. map ( \. id)
72- XCTAssertEqual ( ids, [ " claude-sonnet-4-6 " ] )
73- }
52+ // MARK: - Synthesis uses Haiku (extraction workloads)
7453
75- func testAvailableModelsMaxTier( ) {
76- ModelQoS . activeTier = . max
77- let ids = ModelQoS . Claude. availableModels. map ( \. id)
78- XCTAssertEqual ( ids, [ " claude-sonnet-4-6 " , " claude-opus-4-6 " ] )
54+ func testSynthesisUsesHaiku( ) {
55+ XCTAssertEqual ( ModelQoS . Claude. synthesis, " claude-haiku-4-5-20251001 " )
7956 }
8057
81- // MARK: - Gemini models: premium tier
58+ // MARK: - Chat uses Sonnet (user-facing)
8259
83- func testGeminiModelsPremiumTier( ) {
84- ModelQoS . activeTier = . premium
85- XCTAssertEqual ( ModelQoS . Gemini. proactive, " gemini-3-flash-preview " )
86- XCTAssertEqual ( ModelQoS . Gemini. taskExtraction, " gemini-3-flash-preview " )
87- XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-3-flash-preview " )
60+ func testChatUsesSonnet( ) {
61+ XCTAssertEqual ( ModelQoS . Claude. chat, " claude-sonnet-4-6 " )
8862 }
8963
90- // MARK: - Gemini models: max tier
64+ // MARK: - Available models (Sonnet only, both tiers)
9165
92- func testGeminiModelsMaxTier( ) {
93- ModelQoS . activeTier = . max
94- XCTAssertEqual ( ModelQoS . Gemini. proactive, " gemini-3-flash-preview " )
95- XCTAssertEqual ( ModelQoS . Gemini. taskExtraction, " gemini-pro-latest " )
96- XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-pro-latest " )
66+ func testAvailableModelsSonnetOnlyBothTiers( ) {
67+ for tier in ModelTier . allCases {
68+ ModelQoS . activeTier = tier
69+ let ids = ModelQoS . Claude. availableModels. map ( \. id)
70+ XCTAssertEqual ( ids, [ " claude-sonnet-4-6 " ] )
71+ }
9772 }
9873
99- // MARK: - Gemini pinned models ( tier-independent)
74+ // MARK: - Gemini models are tier-independent
10075
101- func testGeminiEmbeddingIgnoresTier ( ) {
76+ func testGeminiModelsIdenticalAcrossTiers ( ) {
10277 for tier in ModelTier . allCases {
10378 ModelQoS . activeTier = tier
79+ XCTAssertEqual ( ModelQoS . Gemini. proactive, " gemini-3-flash-preview " )
80+ XCTAssertEqual ( ModelQoS . Gemini. taskExtraction, " gemini-3-flash-preview " )
81+ XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-3-flash-preview " )
10482 XCTAssertEqual ( ModelQoS . Gemini. embedding, " gemini-embedding-001 " )
10583 }
10684 }
@@ -115,49 +93,21 @@ final class ModelQoSTests: XCTestCase {
11593 XCTAssertEqual ( ModelQoS . tierDescription, " Max (quality-optimized) " )
11694 }
11795
118- // MARK: - Tier switch dynamically changes accessors
119-
120- func testTierSwitchChangesModelsAtRuntime( ) {
121- ModelQoS . activeTier = . premium
122- XCTAssertEqual ( ModelQoS . Claude. chat, " claude-sonnet-4-6 " )
123- XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-3-flash-preview " )
124-
125- ModelQoS . activeTier = . max
126- XCTAssertEqual ( ModelQoS . Claude. chat, " claude-opus-4-6 " )
127- XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-pro-latest " )
128-
129- ModelQoS . activeTier = . premium
130- XCTAssertEqual ( ModelQoS . Claude. chat, " claude-sonnet-4-6 " )
131- XCTAssertEqual ( ModelQoS . Gemini. insight, " gemini-3-flash-preview " )
132- }
133-
134- // MARK: - Sanitized selection (stale model regression)
96+ // MARK: - Sanitized selection
13597
13698 func testSanitizedSelectionAllowsValidModel( ) {
137- ModelQoS . activeTier = . premium
13899 XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( " claude-sonnet-4-6 " ) , " claude-sonnet-4-6 " )
139-
140- ModelQoS . activeTier = . max
141- XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( " claude-opus-4-6 " ) , " claude-opus-4-6 " )
142100 }
143101
144- func testSanitizedSelectionFallsBackForStaleModel( ) {
145- // User previously selected Opus while on max tier
146- ModelQoS . activeTier = . max
147- XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( " claude-opus-4-6 " ) , " claude-opus-4-6 " )
148-
149- // Tier drops to premium — Opus is no longer available
150- ModelQoS . activeTier = . premium
102+ func testSanitizedSelectionFallsBackForUnknownModel( ) {
151103 XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( " claude-opus-4-6 " ) , " claude-sonnet-4-6 " )
152104 }
153105
154106 func testSanitizedSelectionHandlesNil( ) {
155- ModelQoS . activeTier = . premium
156107 XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( nil ) , " claude-sonnet-4-6 " )
157108 }
158109
159110 func testSanitizedSelectionHandlesUnknownModel( ) {
160- ModelQoS . activeTier = . premium
161111 XCTAssertEqual ( ModelQoS . Claude. sanitizedSelection ( " gpt-4o " ) , " claude-sonnet-4-6 " )
162112 }
163113
@@ -168,4 +118,22 @@ final class ModelQoSTests: XCTestCase {
168118 ModelQoS . activeTier = . max
169119 wait ( for: [ expectation] , timeout: 1.0 )
170120 }
121+
122+ // MARK: - Model count (5 unique model IDs)
123+
124+ func testOnlyFiveUniqueModelIDs( ) {
125+ let allModels : Set < String > = [
126+ ModelQoS . Claude. chat,
127+ ModelQoS . Claude. floatingBar,
128+ ModelQoS . Claude. synthesis,
129+ ModelQoS . Claude. chatLabQuery,
130+ ModelQoS . Claude. chatLabGrade,
131+ ModelQoS . Claude. defaultSelection,
132+ ModelQoS . Gemini. proactive,
133+ ModelQoS . Gemini. taskExtraction,
134+ ModelQoS . Gemini. insight,
135+ ModelQoS . Gemini. embedding,
136+ ]
137+ XCTAssertEqual ( allModels. count, 5 , " Expected exactly 5 unique model IDs: \( allModels) " )
138+ }
171139}
0 commit comments