fix(commandcode): Add support for individual-goat plan ($70/mo credits) - #2706
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed August 6, 2026, 8:33 AM ET / 12:33 UTC. ClawSweeper reviewWhat this changesThe PR adds CommandCode’s Merge readiness⛔ Blocked until real behavior proof from a real setup is added - 5 items remain Keep open: the GOAT catalog addition is focused and the earlier widget-packaging concern is resolved, but the PR changes the established bare-token fallback without compatibility proof and has no after-fix live CommandCode evidence. Priority: P2 Review scores
Verification
How this fits togetherCodexBar sends a CommandCode session cookie to its billing endpoints, maps the returned plan ID to a credit allowance, and renders the resulting usage. The package script separately builds and embeds the macOS widget extension in the app bundle. flowchart LR
A[Browser or manual cookie] --> B[Cookie header handling]
B --> C[CommandCode billing endpoints]
C --> D[Subscription plan ID]
D --> E[Plan credit catalog]
E --> F[Usage display]
G[Package script] --> H[App bundle and widget]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep the legacy bare-token fallback, add the new named-cookie variants, and attach a redacted live CommandCode trace that shows the new plan ID and resulting $70 credit total. Do we have a high-confidence way to reproduce the issue? No high-confidence live reproduction is provided. Source and existing tests establish the fallback change, but the PR does not show a real CommandCode response for the new cookie or plan. Is this the best way to solve the issue? No; adding the plan ID is appropriately narrow, but changing the legacy bare-token default is unnecessary for recognizing explicitly named new cookies and lacks compatibility proof. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 005a71f550cd. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
History |
|
Restored widget extension packaging in @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Keep __Secure-better-auth.session_token as the bare-token default until a renamed production cookie is proven live; accept the new commandcode_prod_ cookie names additively with regression coverage for both name families.
|
Landed. Verified before merge: GOAT plan confirmed real against commandcode.ai docs ($10/mo → $70 credits); unknown plans still fail soft. Maintainer fix pushed before merge ( |
* Port upstream 0.48.0: bound serve request heads * Test serve deadline-driven connection recovery * Port upstream 0.48.0: serve dashboard + snapshot contract * Port upstream 0.48.0: codexbar dashboard command * fix(dashboard): coordinator lost-wakeup/cancellation, daily totalCost wire, bare --output, camelCase schema F1: coordinator.rs registers the Building waiter's Notified while the lock is held (await_build helper), closing the notify_waiters lost-wakeup window; a BuildGuard resets a stranded Slot::Building to Empty + wakes waiters when a build is cancelled or panics. Adds deterministic lost-wakeup + cancel/panic regression tests with tokio::time::timeout bounds. Single-flight, TTL, late-result delivery, and errors-not-cached semantics preserved. F2: data.rs emits the upstream daily wire key 'totalCost' (was cost_usd); dashboard.html gates on 'daily.some(v => (v.totalCost || 0) > 0)' and every per-row read uses 'd.totalCost'. Adds wire/HTML agreement and positive/zero/ empty chart behavior tests. F3: dashboard.rs write_atomic treats an empty Path::parent as '.' so '--output bare-name.json' writes to the working directory. Test covers bare relative create, replacement, and no temporary leftover. F4: AccountPayload and StatusPayload serialize camelCase (updatedAt) to match pinned v1; golden assertions verify 'updatedAt' exists and 'updated_at' does not. * Port upstream 0.48.0: OpenCode Go per-model daily cost breakdown Extract each local assistant message's modelID from opencode.db (the real model behind the constant opencode-go Zen-proxy providerID) and group cost / request counts by (day, model) instead of just by day, so the shared Cost history chart shows a per-model breakdown for OpenCode Go the same way it already does for Codex/Claude. Rows with no modelID fall back to an 'unknown' bucket; whitespace-only ids collapse to 'unknown', whitespace-padded ids merge with the trimmed bucket (upstream steipete#2649). Provider-local: the SQL extraction, model normalization and (day, model) aggregation live in the OpenCode Go local reader. The shared cost surfaces are reused, not duplicated -- get_daily_cost_history gains an 'opencodego' arm and CostScanner gains scan_opencodego_with_cancel that maps the provider-local summary onto the existing CostSummary (total_cost_usd, by_model, sessions_count, period), so the chart's local-usage panel and daily cost history treat OpenCode Go like Codex/Claude without a bespoke chart surface. No Codex/Claude pricing policy is copied; no duplicate chart machinery. Tests: 11 focused regressions covering multiple models/days, same-model merge, step-finish model inheritance, unknown/whitespace-only/whitespace-padded model ids, zero-cost rows, malformed rows, history-window exclusion, local-day boundary keying, deterministic (day, model) ordering, summary aggregation, and Zen-wait independence of the pure aggregation. * Port upstream 0.48.0: parse CommandCode rolling windows + GOAT plan F12 (steipete#2630): parse windowLimits.fiveHour/weekly (root or nested in credits) into primary/secondary rate windows with number-or-string coercion and epoch-s/epoch-ms/ISO-8601 resetAt handling; monthly grant moves to tertiary and uses the plan catalog for its total. F13 (steipete#2706): add the individual-goat plan (0/mo) to the plan catalog, recognize the new commandcode_prod_.session_token cookie names ahead of the legacy better-auth family (bare tokens keep the legacy name), and narrow pasted headers to the session cookie per upstream CommandCodeCookieHeader.override. Regressions: both upstream window-limits fixtures copied verbatim; cookie priority/case-folding/family tests; plan catalog + login-method and monthly-window mapping tests. * Port upstream 0.48.0: derive OpenRouter key meter from server remaining F14 (steipete#2612): the key-limit meter and its left/used text now come from the server-reported current-period limit_remaining (clamped to [0, limit]: negative reads exhausted, above-limit reads 0%) instead of lifetime usage. Without a server remaining, fall back to the period usage matching the declared limit_reset window, then cumulative usage; keys without any usable quota source keep the meter hidden. Adds wire decoding for limit_remaining/limit_reset. * Port upstream 0.48.0: preserve ZoomMate browser cookie scope F16 (steipete#2627): browser-imported cookies keep their raw host scope instead of being merged into one header reused on host failover. Chromium/Firefox host keys carry the scope (leading '.' = parent-domain), so each destination host (ai.zoom.us / zoommate.zoom.us) now gets its own header via RFC 6265 domain matching: parent-domain sessions reach both API hosts, host-only cookies never leak onto sibling hosts, non-API hosts are never destinations. Upstream fixture issue-2507-cookie-scope.json copied verbatim; regression tests cover the per-host partition, suffix-attacker rejection, empty domains, and the hostOnly/domain matrix. * Port upstream 0.48.0: decode Copilot AI credits counter A15 (steipete#2593/steipete#2613): quota snapshots now decode credits_used (number or string) for token-billed seats. The absolute counter stays off the rate-window path — it surfaces as an informational extra window (ai-credits), matching the existing snapshot/bridge/diagnostics pipeline without inventing a fake quota denominator. Upstream carriesCreditsCounter parity: zero-entitlement placeholder snapshots still yield their counter, so a business seat with no renderable quota window no longer blanks out — its snapshot becomes an informational credits row (preferred premium-, then chat-classified entries) instead of the previous hard error. Seats without any counter keep the existing token-billing error. * Port upstream 0.48.0: classify Claude OAuth refresh failures, terminal backoff F3 (steipete#2650): on Windows the credential file is readable, so the upstream touch-completes-but-unreadable state has no equivalent — the matching provably-unrecoverable-by-retry state is the refresh endpoint rejecting the stored refresh token (400/401/403). Those now classify as terminal: a 5-minute per-source backoff (upstream defaultCooldownInterval) instead of a doomed grant on every poll, and an honest re-login message without the useless retry tail. Transient failures (network, 429, 5xx) keep a short 20-second cooldown (upstream shortCooldownInterval) so recovery still lands quickly. Successful refresh clears state; a re-login via the shared credentials file is adopted past any backoff as before. Regressions: classification matrix, long/short backoff gating + purge, distinct terminal/cooldown user messages. * Port upstream 0.48.0: bounded Zen balance wait in OpenCode Go usage reads F15 (steipete#2583): the Zen balance now joins usage reads with an explicit policy bound measured from task creation — CLI usage/serve /usage reads (requires_optional_usage_completeness, new FetchContext field) join for the remainder of the 5 s optional-balance budget; background/UI/guard/ diagnose hooks keep the 250 ms grace, so a slow subscription fetch can never stack a second full wait. Local (SQLite) reads gain the same optional enrichment as web reads, matching the upstream local strategy. The balance fetch itself is the upstream chain: dashboard page parse first, dedicated billing server-fn (raw 1e-8 USD behind a customerID marker, RSC-fragment tolerant) as fallback, 25 ms start delay, bounded per-request, and abandoned-over-budget tasks are aborted instead of leaking. A zero-cost balance embedded in the usage page still wins without any extra request. A14 (per-model cost breakdown by day) intentionally NOT in this commit. * Port upstream 0.48.0: Claude OAuth refresh gate + serve/opencodego fixes (M1-M4) M1: from_http_status terminal iff (400|401) AND OAuth error == invalid_grant (case-insensitive). 403 and 400/401-without-invalid_grant are transient. M2: terminal gate indefinite until credential fingerprint changes or success clears; transient base 5min flat; eliminates repeated dead-grant retries. M3: serve /usage sets requires_optional_usage_completeness false (background poll grace); CLI usage remains true. M4: abort spawned Zen balance task on usage-page/parse error before early return. * Port upstream 0.48.0: Kimi/GLM/z.ai China routing (WS5) - Kimi Desktop monthly membership pool enrichment: read-only WAL-safe kimi-auth token reader for the Electron Chromium store (%APPDATA%/kimi- desktop), AES-256-GCM via existing browser cookie crypto; Code API + CLI snapshots merged with Monthly + Code 7-day membership windows (steipete#2622/A10). - Cookie Source Off disables Kimi Desktop + browser import (manual cookie headers keep working) (steipete#2623/A12). - Moonshot/Kimi Open Platform: MOONSHOT_REGION + region-bound CODEXBAR_MOONSHOT_API_KEY(_REGION) binding so CN/intl keys stay on their issuing hosts; provider renamed per upstream (steipete#2621/A11). - GLM Coding Plan: 5-hour TOKENS_LIMIT window is primary, weekly secondary, MCP rendered as a separate named window; plan name falls back to plan/plan_type/packageName/level (steipete#2621/A11). - z.ai region routing: BIGMODEL/ZHIPU(ZHIPUAI)/GLM env aliases and coding-relay key files only for BigModel CN; canonical cross-region endpoint overrides rejected before bearer auth (steipete#2623/A12). - Shared WAL-safe read-only SQLite helper (core::sqlite) replacing the OpenCode Go-local copy, reused by the Kimi Desktop reader (steipete#2544 pattern). * Port upstream 0.48.0: unify Pi-family (pi + OMP) agent sessions (WS6) - One dialect-aware scanner: live pi/OMP process detection (basename + bun-shim handling, helper filtering), session-jsonl correlation per CWD, PID-only rows when no transcript can be attributed, upstream OMP profile / PI_CONFIG_DIR / --session-dir / settings.json root resolution with the same fail-closed validation, upstream fixtures copied verbatim (steipete#2626/A13). - Wire shape: AgentSession gains optional dialect + sessionName; --json stays legacy Codex/Claude-only (v1) while --json-v2 emits the complete array; SSH session discovery negotiates --json-v2 with --json fallback. - Local scanner adopts the shared bounded directory budget; provider labels Pi/OMP in the sessions UI (bridge DTO + locale keys). - Remote plumbing (RemoteSessionFetcher) moved to agent_sessions/remote.rs and the Pi scanner split into pi_family/{mod,parser,roots} to keep every file under 1000 lines. * fix(dashboard): enable waiter notification under the decision guard (F1) Corrects the lost-wakeup fix in 87ff071: await_build re-acquired the slot mutex AFTER the decision guard was released, so a build completing in that gap could fire notify_waiters (and swap the slot) before the waiter ever registered — the waiter then slept forever on an already-fired Notify. Now the waiter constructs and enable()s an OwnedNotified (which owns the Arc<Notify>, Send+Sync) while still holding the SAME decision mutex that observed Slot::Building, carries the registered future out of the critical section, and awaits it only after the guard drops. The builder can update the slot and notify_waiters only while holding that same mutex, so registration is provably ordered before any wakeup attempt for this build. await_build helper removed. Regression: completion_in_decision_window_sets_waiter_notified drives the waiter with manual polls and forces build completion + notify_waiters into the exact decision->await window (slot manipulated directly; zero scheduler dependence). Existing racing/cancel/panic regressions and single-flight, TTL, late-result, and errors-not-cached behavior unchanged. Also repairs two FetchContext initializers in source.rs for the integrated requires_optional_usage_completeness field (E0063 at d2a63eb; false = FetchContext::default, no behavior change). Verified: cargo fmt --all --check clean; cargo clippy -p codexbar --all-targets -- -D warnings clean; 10/10 coordinator tests pass (2 threads). * Port upstream 0.48.0: Codex cost-scanner robustness (F1,F2,F18,F19) WS2 — Codex cost cache and scan robustness, ported from upstream 0.48.0. F1 (cache bounds): add CostUsageCacheBudget module with upstream's 256 MiB save / 320 MiB load / 25 000 entry caps. Load refuses to decode artifacts above MAX_LOAD_BYTES (cheaper to rebuild bounded). Save prunes out-of-window entries, then trims oldest in-window entries to fit the budget, protecting partially-parsed (growing) files so append-only resume keeps its catch-up progress. F2 (fork catch-up resume): validate the cached resume offset is a real line boundary (byte at offset-1 == newline) before resuming an append-only parse. A partial trailing-line write leaves the offset mid-line; resuming there corrupts the first record. When the check fails, fall back to a full re-parse from zero instead of the append-only merge. F18 (priced + unpriced Auto Review): codex-auto-review and the model-less sentinel are now deliberately unpriced routing rows — tokens counted, by_model row present with 0 cost, no fallback to gpt-4o rates. Add typed ModelPricingCompleteness (Complete | Partial{unpriced_models}) to CostSummary so the dashboard can label a partial breakdown. F19 (overshoot contract + predecessor keys): document the save/load overshoot contract — save may exceed MAX_FILE_BYTES up to MAX_LOAD_BYTES when protected entries cannot be trimmed further. Predecessor-key acceptance is N/A locally (local cache uses filename -v1 versioning, no producer-key field); documented as a documented divergence. * Port upstream 0.48.0: Codex windows/pricing (F5,F6,C4) WS3 — Codex duration classification and pricing, ported from upstream 0.48.0. F5 (duration classification 5h/weekly/30-day): centralize duration policy in RateWindowCadence (Session/Weekly/Monthly/Unknown) with from_minutes() and from_seconds(). Add MONTHLY_WINDOW_MINUTES (43 200) next to the existing SESSION/WEEKLY constants. Update codex_window_role to use RateWindowCadence so 30-day windows classify as Monthly instead of being swallowed into Weekly. C4 (Fast cost semantics + Terra/Luna refresh): add codex_api_fast_multiplier() (gpt-5.4/5.4-mini/5.6-sol/5.6-terra/5.6-luna → 2.0; gpt-5.5 → 2.5; else nil) and codex_fast_cost_usd() (standard cost × multiplier with long-context guard at 272 000 input). Wire into codex_costs::codex_cost_usd after canonical resolution fails but before legacy gpt-4o fallback, for fast/priority model IDs. Refresh Terra rates (2e-6/1.2e-5, long 4e-6/1.8e-5) and Luna rates (2e-7/1.2e-6, long 4e-7/1.8e-6). Fast detection is name-based locally (upstream uses a priority-trace SQLite DB scan — documented divergence). * Port upstream 0.48.0: complete WS2+WS3 follow-up (A16,F6,F8,F5) A16 (scan completeness JSON): add historyCoverageIsEstablished to CostSummary and surface it in the CLI cost JSON as historyCoverageIsEstablished (Bool?, null for non-Codex providers). Set from cache freshness + catch-up state so callers know when a re-scan is pending. Provider-native-only flag is N/A locally (no pi/OMP mirror sessions) — documented divergence. F6 (manual reset backfill): add codex_reset_backfill in Tauri providers.rs — backfills missing resets_at/reset_description on fresh Codex windows from the cached snapshot when the cached reset is still future (fresh used_percent untouched). Wired into refresh_provider before publishing so every surface (tray, CLI, frontend) sees the backfilled reset. Implemented through the existing provider refresh abstraction, not a generic trait hook. F8 (cached spend during refresh): add refreshing + stale_updated_at to UsageSpendRow (backward-compatible optional fields). When the Codex cache was pruned for budget (previous_report set), the spend row shows the stale timestamp and refreshing indicator so the UI can show old data while a re-scan rebuilds the artifact. Frontend UsageSpendTab renders the indicator and uses the UsageSpendRefreshing locale key. F5 (monthly cadence wiring): add Monthly to WindowRole (managed accounts) and wire monthly through the ambient provider (normalize_array_windows 4-tuple routes monthly to UsageSnapshot.tertiary). Add tertiary_label to bridge ProviderUsageSnapshot (duration-cadence label via RateWindowCadence). Frontend MenuCard.tsx uses tertiaryLabel with monthly localization (ProviderMonthly). Tray provider_status_label for Codex picks first non-informational lane (session → weekly → monthly). CLI usage.rs appends a monthly lane line with RateWindowCadence-based label. Test added for Monthly role classification. * Port upstream 0.48.0: fix fmt/clippy integration issues - Remove untracked package-lock.json (pnpm repo, npm artifacts incompatible) - cargo fmt --all: bridge.rs, providers.rs, usage_spend.rs, tray_bridge.rs - clippy: move constant-size budget assertion into const block (assertions_on_constants) - clippy: add TestCache type alias to simplify test helper return type (type_complexity) - clippy: collapse nested if-let in tray_bridge.rs codex_lane_headline_window using let-chains (let-chains stable since 2025 edition) * Port upstream 0.48.0: C4 centralize fast suffix stripping (audit fix) Extract codex_fast_base_model() that strips -fast/-priority suffixes. Both codex_api_fast_multiplier() and codex_fast_cost_usd() now use it so the original suffix does not leak into the Standard base lookup. Previously codex_fast_cost_usd passed the original model name to codex_cost_usd, which failed for suffixed IDs like gpt-5.5-fast. Tests added: - test_codex_fast_cost_usd_suffixed_models_resolve_to_base: gpt-5.5-fast -> base gpt-5.5 × 2.5, gpt-5.6-sol-priority -> base gpt-5.6-sol × 2.0 - test_codex_fast_base_model_unsuffixed: unsuffixed and unknown models resolve to themselves. * Port upstream 0.48.0: F8 clear previous_report after full scan (audit fix) A completed full scan rebuilds the cache for the current window, so any prior catch-up state is no longer pending. Clear previous_report before save_cache so the persisted artifact no longer signals stale/refreshing. Previously previous_report was set during save-time budget pruning but never cleared, causing a permanent Refreshing indicator. Test: previous_report_clears_after_successful_full_scan — first scan clears, inject previous_report to simulate trim, full scan clears it. * Port upstream 0.48.0: A16/F18 expose coverage+completeness in CLI JSON (audit fix) A16 historyCoverageIsEstablished and F18 modelPricingCompleteness were added to CostSummary in the prior follow-up but never wired into the CLI cost JSON or text output. Now: - JSON emits historyCoverageIsEstablished (bool for Codex, null otherwise) and modelPricingCompleteness ("complete" or {partial:{unpriced_models}}). - Text output labels partial pricing and partial coverage when present. - --provider-native-only flag added, maps to CostScanOptions::include_pi_sessions = false, excluding pi/OMP session mirrors. Documented divergence: no pi/OMP mirror sessions on this Windows build so the flag is accepted but has no observable effect locally. Tests: json_output_emits_a16_and_f18_fields, json_output_a16_null_for_non_codex, provider_native_only_flag_default_false. * Port upstream 0.48.0: F19 refuse oversized cache + fix trim double-subtraction (audit fix) F19: save_cache now checks the encoded JSON length against MAX_LOAD_BYTES before persisting. If the artifact still exceeds the load budget after pruning+trimming (e.g. a single protected entry alone exceeds the limit), the save is refused — no persist/refuse/rebuild loop. Extracted as CostUsageCacheBudget::should_refuse_persistence() pure helper for testability. Trim double-subtraction fix: trim_in_window_for_budget pre-subtracted droppable[0] from the initial estimate, then subtracted it again inside the loop — a double count. Now the initial estimate is the full estimated_cache_bytes and the loop subtracts each candidate once. Tests: - should_refuse_persistence_at_and_above_limit (boundary 1024/1025) - trim_estimate_no_double_subtraction_of_first_entry - trim_drops_until_target_reached_then_stops - save_cache_persists_small_codex_artifact (no false-positive) - save_cache_refuses_non_bounded_provider_oversize (Claude gate) * Port upstream 0.48.0: F2 boundary helper + scan-level negative regression (audit fix) F2 (upstream 0.48.0 steipete#2648): add boundary helper tests for all edge cases and a scan-level negative regression proving midline/truncated rewrite forces full parse (no resume from stale offset). Tests: - is_line_boundary_offset_zero_returns_true (offset 0) - is_line_boundary_offset_at_or_past_size_returns_true (EOF) - is_line_boundary_offset_exact_newline_returns_true (valid boundary) - is_line_boundary_offset_midline_returns_false (fall through) - is_line_boundary_offset_missing_file_returns_false (probe fail) - cost_scan_midline_rewrite_forces_full_parse_not_resume (scan-level) * Port upstream 0.48.0: F5 cadence/routing/headline regression tests (audit fix) F5 (upstream 0.48.0): boundary table for RateWindowCadence and routing regression for normalize_array_windows + tray headline preference. Tests: - cadence_boundary_session_exactly_300 (Session) - cadence_boundary_weekly_10080 (Weekly) - cadence_boundary_below_monthly_43199_is_weekly (boundary) - cadence_boundary_monthly_43200 (Monthly) - cadence_from_seconds_rounding (0/neg→Unknown, 18001s→301→Unknown) - cadence_label_keys (session/weekly/monthly/unknown) - f5_normalize_array_routes_session_weekly_monthly_to_lanes - f5_normalize_array_monthly_routes_to_tertiary_not_secondary - f5_normalize_array_empty_returns_placeholder_primary - f5_normalize_array_unknown_windows_fall_to_code_review - f5_headline_prefers_non_informational_primary (Tauri) - f5_headline_falls_back_to_secondary_when_primary_informational (Tauri) - f5_headline_falls_back_to_tertiary_when_primary_and_secondary_informational (Tauri) - f5_headline_returns_primary_when_all_informational (Tauri) * Port upstream 0.48.0: F6 reset-backfill regression tests (audit fix) F6 (upstream 0.48.0 UsageStore+CodexResetBackfill): regression tests for codex_reset_backfill covering future/stale/no-cached/non-codex/existing paths. Tests: - f6_backfills_future_cached_reset (future reset backfilled, used untouched) - f6_does_not_backfill_stale_cached_reset (past reset skipped) - f6_does_not_overwrite_existing_resets_at (fresh reset preserved) - f6_skips_non_codex_provider (Claude skip) - f6_skips_when_no_cached_snapshot (None cached) Divergence: upstream weekly-confirmation exemption N/A locally — local backfill is the observable analog (no weekly-confirmation guard exists). * Port upstream 0.48.0: fix clippy lint in audit-followup test code (audit fix) Fix 4 clippy -D warnings violations in the audit-followup test code: - collapsible_if in cli/cost.rs partial pricing label - field_assignment_outside_initializer in cli/cost.rs test - field_assignment_outside_initializer in jsonl_scanner.rs test - needless_borrows_for_generic_args in cost_scanner.rs test * Port upstream 0.48.0: F19 refusal removes preexisting destination artifact (audit fix) The prior F19 commit refused on oversized post-encode but left any existing destination cache file in place; a stale/oversized artifact could persist and trip the load-refusal path on the next scan, forcing an unnecessary full rebuild from a poisoned artifact. - save_cache now deletes the destination file on refusal (best-effort, mirroring the fs-delete idiom used elsewhere in core). - Extracted save_cache_with_limit(provider, cache, cache_root, max_load_bytes) as a private testable helper; save_cache delegates with the production MAX_LOAD_BYTES const. Production limit behavior is unchanged. Integration regressions (jsonl_scanner.rs): - save_cache_refusal_removes_preexisting_destination_artifact: precreate real destination via save_cache_with_limit(usize::MAX), trigger refusal with limit=1, assert destination gone, no tmp artifact with content, and load yields empty cache (no rebuild loop). - save_cache_at_exact_limit_is_accepted: encoded artifact at exactly the injected limit is persisted (boundary). - save_cache_one_over_limit_is_refused_and_removes_destination: one byte over limit is refused and destination removed. * fix: fan out dashboard build errors * fix: pin Windows globalization timezone module iana-time-zone resolves the Windows system zone through WinRT's Windows.Globalization Calendar class, but nothing keeps that DLL loaded. COM cleanup exercised by the notification sound/toast tests unloads it, leaving windows-core's process-static factory cache pointing into an abandoned mapping; the next get_timezone() call then access-violates (observed under LLDB; full lib suite crashed 3/3 single-threaded). Load Windows.Globalization.dll from System32 and pin it for the process lifetime before any get_timezone() call, gated behind a one-shot LazyLock so every caller waits for load+pin to settle. On pin failure return UTC without calling iana-time-zone (an AV is uncatchable). Route both project call sites (claude cli_reset, sub2api) through the new crate-internal helper. No lockfile change. * test: make globalization pin test host-independent The self-hosted PR runner is a stripped Windows image without registered WinRT types (ToastNotification not registered), where pinning Windows.Globalization.dll can fail by design; the helper then correctly falls back to UTC. Assert the environment-independent contract instead: the pin attempt settles exactly once and every caller observes the same decision.
Description
Adds support for CommandCode's new GOAT plan (
individual-goat, $10/month subscription providing $70/month in credits).Details
CommandCodePlanCatalog.swiftto registerindividual-goatwithmonthlyCreditsUSD: 70.CommandCodeUsageFetcherTests.swiftto assert catalog resolution forindividual-goat.References