diff --git a/clients/macos/vellum-assistantTests/BillingServiceSubscriptionTests.swift b/clients/macos/vellum-assistantTests/BillingServiceSubscriptionTests.swift index 987fe7a37da..e75db54eeca 100644 --- a/clients/macos/vellum-assistantTests/BillingServiceSubscriptionTests.swift +++ b/clients/macos/vellum-assistantTests/BillingServiceSubscriptionTests.swift @@ -67,14 +67,35 @@ final class BillingServiceSubscriptionTests: XCTestCase { { "id": "pro", "name": "Pro", - "price_cents": 2500, + "base_price_cents": 3000, + "base_lookup_key": "pro_base", "billing_interval": "month", + "machine_tiers": [ + { + "tier": "medium", + "label": "medium", + "price_cents": 0, + "lookup_key": "pro_machine_medium", + "cpu_limit": "2.5", + "memory_gib": 5, + "description": "Medium machine (2.5 vCPU, 5 GiB)" + } + ], + "storage_tiers": [ + { + "tier": "medium", + "label": "256 GiB", + "storage_gib": 256, + "price_cents": 0, + "lookup_key": "pro_storage_medium" + } + ], "included_features": [ - "Larger machine size", - "Bundled credits", - "Managed email subdomain", - "Managed Twilio phone numbers", - "90-day grace period on cancellation before managed resources are released" + "Pay-as-you-go credits", + "Custom LLM credentials", + "Configurable machine size", + "Configurable storage", + "Assistant email & subdomain" ] } ] @@ -93,12 +114,17 @@ final class BillingServiceSubscriptionTests: XCTestCase { XCTAssertFalse(base.included_features.isEmpty) XCTAssertEqual(base.included_features.first, "Pay-as-you-go credits") + // The Pro entry uses the server's tiered shape: no flat `price_cents`, + // with pricing split across `base_price_cents` + per-tier arrays the + // client doesn't model. Decoding must still succeed (extra keys are + // ignored, `price_cents` decodes to nil) — a regression here is what + // produced "Unable to load plan information." on the Plan card. let pro = decoded.plans[1] XCTAssertEqual(pro.id, "pro") XCTAssertEqual(pro.name, "Pro") - XCTAssertEqual(pro.price_cents, 2500) + XCTAssertNil(pro.price_cents) XCTAssertEqual(pro.billing_interval, "month") XCTAssertFalse(pro.included_features.isEmpty) - XCTAssertTrue(pro.included_features.contains("Larger machine size")) + XCTAssertTrue(pro.included_features.contains("Assistant email & subdomain")) } } diff --git a/clients/macos/vellum-assistantTests/PlanCardTests.swift b/clients/macos/vellum-assistantTests/PlanCardTests.swift index b8043b658ea..217d9f141fa 100644 --- a/clients/macos/vellum-assistantTests/PlanCardTests.swift +++ b/clients/macos/vellum-assistantTests/PlanCardTests.swift @@ -27,7 +27,7 @@ final class PlanCardTests: XCTestCase { PlanCatalogEntry( id: "pro", name: "Pro", - price_cents: 2500, + price_cents: nil, billing_interval: "month", included_features: [ "Larger machine size", diff --git a/clients/shared/App/Auth/AuthModels.swift b/clients/shared/App/Auth/AuthModels.swift index 567d03156cc..a9552a254be 100644 --- a/clients/shared/App/Auth/AuthModels.swift +++ b/clients/shared/App/Auth/AuthModels.swift @@ -350,7 +350,12 @@ public struct SubscriptionResponse: Codable, Sendable { public struct PlanCatalogEntry: Codable, Sendable { public let id: String // "base" | "pro" public let name: String // "Base" | "Pro" - public let price_cents: Int + /// Flat monthly price, in cents. Only present on flat-priced plans (Base); + /// tiered plans (Pro) omit it and split pricing across `base_price_cents` + + /// per-tier arrays on the server. MUST stay optional — making it required + /// hard-fails decoding of the whole catalog on the Pro entry, surfacing as + /// "Unable to load plan information." on the Plan card. + public let price_cents: Int? public let billing_interval: String // "month" public let included_features: [String] }