Repository navigation
Conversation
shawnla90
left a comment
There was a problem hiding this comment.
Built and ran this same feature on my own machine last week (branch linked in #200), so two notes from that experience:
1. The multiple mixes subscriptions. monthAPIEquivalentCost sums every costIsEstimate provider (Claude, Codex, Gemini, ...) but subscriptionLeverage gates on the Claude plan and divides by one plan price. A Max user who also runs Codex CLI (covered by a ChatGPT subscription, not the Claude plan) gets an inflated 'leverage' number: on my machine, August is ~$2,783 of Claude API-equivalent, and Codex estimates on top would push the displayed multiple past what the Max plan actually delivered. Two clean fixes: scope the numerator to claude_code (the plan the gate reads), or keep the mixed sum and make the row's copy say what it covers. I'd do the former — the hint text says the price is for the Max/Pro/Team row, so users will type their Claude plan price.
2. The price field writes defaults per keystroke. TextField("0", value: $store.monthlyPlanPrice, ...) binds straight to the store, and the didSet writes to UserDefaults on every edit. The scan-roots field from #187 established the draft + commit-on-submit/blur pattern for exactly this reason, and CustomScanRootsTests.testSettingsUsesProviderPickerAndCommitsOnSubmit locks it there ('direct TextField binding to the store writes on every keystroke'). Worth matching that pattern here so the convention holds.
Neither blocks the shape — per-provider costIsEstimate is the right structure and matches the #224 close. Happy to test the branch on my dual-login setup once these land.
|
Landed in c8d7c71. 1. Mixed subscriptions. 2. Per-keystroke defaults. Plan price uses a local draft and commits on submit, blur, and leaving Settings — same pattern as custom scan roots (#187). Happy to have you run the dual-login setup against this commit. |
chattymin
left a comment
There was a problem hiding this comment.
Please keep this PR scoped to Claude subscription leverage for now and align the PR description, tests, and UI copy with that behavior. The calculation should use record-level cost provenance and include only the Claude API-equivalent cost, rather than classifying an entire provider with one estimate flag. Please rebase onto current main. Support for additional providers can be added separately later.
c8d7c71 to
f0420a3
Compare
|
Reworked per your review and rebased onto current
|
Summary
Adds an optional Claude subscription leverage row for #200, scoped to Claude only as requested in review. Rebuilt from current
main.When the default Claude login is Max / Pro / Team and the user enters a monthly plan price in Settings, the popover shows one line under this week / this month:
Claude plan $100.00/mo · API-equiv $610.00 · 6.1×How the numerator is computed (record-level provenance):
UsageStore.claudeMonthAPIEquivalentCostreads the Claude snapshot's monthusageCost. It is looked up by id, the same way the existingclaudeActiveBlocklookup works.LocalUsageReader.Bucket:costUSD(fromcost-state) counts as.source..estimate..unavailable: it adds nothing to the amount and marks the total partial..sourceand.estimateClaude amounts are API-rate figures, so every known amount counts as API-equivalent.costIsEstimateflag any more. Other providers (Gemini/Codex estimates, Grok/OpenCode/Hermes bills) never enter the numerator. The combined month header still sums every provider, unlabeled.Gate: all of the following must hold, or the row is hidden:
LimitStatus.isFlatRateSubscription(max/pro/team, any case).$> 0.The menu bar and all cost rows are unchanged: bare
$, no "API-equiv" caption anywhere except the leverage row (#224).Support for other providers is intentionally out of scope and can be added later with their own plan inputs.
Type of change
UI changes
Claude plan $X/mo · API-equiv $Y · Z×. Its tooltip explains the source, estimate, or partial coverage.0= off). It drafts locally and commits on submit, blur, or leaving Settings (same pattern as #187), so UserDefaults isn't written on every keystroke. Negative, NaN, or infinite values load and save as0.$12.3.Validation
./scripts/test-gate.sh: 1395 tests, 0 failures (17 skipped); logic-core line coverage 93.39% (≥ 75%).UsageStoreTests:testLeverageUsesOnlyClaudeMonthCost: Claude $610 + Gemini estimate $200 + Grok bill $50, plan $100. Header = $860, leverage = 6.1×.testOtherProvidersNeverFeedLeverage.testLeverageKeepsRecordLevelCoverage: mixed source/estimate/unavailable gives the partial hint.testLeverageGates: price unset or 0, Free, no plan, no credential, unpriced-only month, non-costing snapshot.testLeverageOpensForProAndTeam.testLeverageHiddenWithSeveralClaudeAccounts.testMonthlyPlanPricePersistsAndSanitizes.testLeverageStaysOutOfTheMenuBar.ModelDecodingTests:testIsFlatRateSubscription,testMultiplierFormat,testLeverageUiShape(no store binding; draft andonDisappearcommit).LocalizationInterpolationTests: leverage placeholders survive in all 7 languages.llvm-cov --show-regionsshows no^0regions in the newUsageStorecode.defect-log.mdUI entry covers the record-level vs. provider-level provenance and the multi-account gate.provider-extension.mdnotes that the leverage lookup is an explicit provider-specific branch, likeclaudeActiveBlock.Checklist
swift buildandswift testpass locallyRelated