Skip to content

Integrate CodexBar upstream through 63dc1cd5 - #144

Merged
ColumbusLabs merged 57 commits into
mainfrom
automation/upstream-2026-08-23
Aug 24, 2026
Merged

Integrate CodexBar upstream through 63dc1cd5#144
ColumbusLabs merged 57 commits into
mainfrom
automation/upstream-2026-08-23

Conversation

@ColumbusLabs

@ColumbusLabs ColumbusLabs commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Integrates the frozen CodexBar upstream review range f74117aeb7a9ee02a78c0f08ca354ff26b2292e0..100deb6faeeaa97f179845ef0591cb9b1102639e into QuotaKit.

  • Reviewed and accounted for all 41 upstream commits in the frozen range.
  • Adopted or adapted 25 product/test commits.
  • Rejected 15 upstream release, credit-only changelog, appcast, version, and incompatible Grok fallback commits.
  • Superseded 1 intermediate CHF test patch with QuotaKit's native fixture repair.
  • Advanced only UPSTREAM_MONITOR_BASE; retained QuotaKit version, build, appcast, signing, bundle, provider, CloudKit, and mobile ownership.

QuotaKit adaptations

  • Preserved the complete 69-provider catalog and generated manifests.
  • Kept QuotaKit's typed Mac-to-iPhone sync, provider identifiers, CloudKit/App Group contracts, and account isolation.
  • Hardened CloudSync transient and engine-managed retries.
  • Kept machine-local Cursor/Antigravity spend account-neutral and out of CloudKit.
  • Preserved Codex fork ownership, priority pricing, parser cache invalidation, plan-history ownership, and resumable accepted-usage timestamps.
  • Bound ChatGPT-hosted Codex activity to trusted executable identity with TTL and xattr-sensitive invalidation.
  • Reused signed-in Antigravity CLI sessions only with same-user, exact executable, selected-account, deadline/cancellation, and owned-process safeguards.

Verification

  • make test: 975 selections, 82/82 groups passed, zero retries/timeouts.
  • ./Scripts/lint.sh lint: passed; 69 provider manifests current.
  • Focused Antigravity tests: 18 warm-reuse, 41 CLI HTTPS, 49 CLI session tests passed.
  • Provider architecture gatekeeper: 38/38 passed.
  • swift build -c release: passed.
  • git diff --check: passed.
  • Independent adversarial reviews completed; all P0-P2 findings resolved.

No Mac release, appcast update, binary distribution, iOS upload, or build-number change is included.

kiranmagic7 and others added 25 commits August 23, 2026 15:17
…its) (#3116)

* fix(commandcode): Add support for individual-pro-v1 plan ($80/mo credits)

Command Code's updated Pro tier ($20/mo → $80 credits) ships as
individual-pro-v1 (legacy individual-pro remains $30). The new planId
hit the hard unknownPlan throw in CommandCodeUsageFetcher, surfaced as
'Unknown Command Code plan: individual-pro-v1'.

Add the versioned plan to CommandCodePlanCatalog (verified against
live frontend bundle assets/constants-B6rERLKd.js and pricing docs).
Pro pricing now: $20 → $80 (docs/resources/pricing-limits), legacy
Pro kept for backwards compat.

* test(commandcode): Cover individual-pro-v1 plan resolution

Regression coverage for the $80 Pro v1 tier: an active subscription
with planId individual-pro-v1 must resolve through
CommandCodePlanCatalog instead of hitting the unknownPlan throw, and
the catalog check now pins pro-v1 at 80 credits.
…ponses (#3128)

Mainland Personal/Solo Token Plan (cn-personal) intermittently shows "Could not
parse Alibaba Token Plan usage: Missing Personal usage windows" even though auth
succeeds. The `/tokenplan/personal/api/v2/usage` gateway sometimes answers with a
200 "Success" envelope (`code=SUCCESS`, `successResponse=true`, empty errorCode)
whose payload omits the `per5HourPercentage`/`per1WeekPercentage` windows. The
parser treated that absence as a hard parse failure.

- Throw a distinct `.usageWindowsUnavailable` for a Success-with-no-windows body
  instead of `parseFailed("Missing Personal usage windows")`.
- Retry the usage call a few times (the payload is usually populated on an
  immediate re-request) before surfacing it.
- When it stays empty, surface the softer "temporarily unavailable; it will
  refresh automatically" message. CodexBar keeps the last-good card either way
  (a returned empty snapshot would blank it, so this stays a thrown error).

Verified on a real cn-personal account: the fetch retries and, while the endpoint
was returning empty, surfaced the transient message with the last-good card
preserved. Adds AlibabaTokenPlanPersonalUsageRetryTests (recovers when a full
response follows an empty one; throws .usageWindowsUnavailable when every attempt
is empty).

Refs #2500.

Co-authored-by: LeoLin <leolin990405@gmail.com>
* fix(claude): migrate email-keyed iCloud snapshots to slot keys

* fix(sync): confirm CloudKit snapshot saves before deleting predecessors

Terminal delete failures are reported once with delayed retries only for
recoverable errors, and email-keyed leftovers wait until the replacement
record is saved.

* fix(sync): persist leftover snapshot deletes across delayed retries

Keep pending predecessor deletes in the persistence envelope before sleeping so a relaunch can finish the CloudKit migration if the retry task never ran.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): stop retrying terminal CloudKit replacement saves

Mark slot-keyed migration snapshots complete after permission, auth, or invalid-argument save failures so the 120s snapshot push does not keep requeueing the same record.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): bind delayed CloudKit deletes to the originating engine

Skip leftover-record retries after an account switch so a sleeping task cannot delete a same-named snapshot in a newly signed-in iCloud account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): drop stale CloudKit predecessors that are live again

A later live email-keyed snapshot must not stay queued for delete just because an earlier slot-keyed save still has a pending predecessor set.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): cancel leftover snapshot deletes when they become live

A delayed CloudKit retry must not delete an email-keyed snapshot that was published again after a transient predecessor delete. Drop that name from the persisted retry set and the engine queue.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): do not retry CloudKit deletes for live snapshots

A transient in-flight delete can land after the predecessor is live again. Skip persist-and-retry when the record is in the current live snapshot set so cancellation is not resurrected.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): isolate CloudKit migration state from the next iCloud account

Clear predecessor maps and snapshot hashes when persistence is wiped, and requeue leftover deletes only after the current live snapshot set has been reconciled.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): persist predecessor deletes and requeue empty publications

Keep the replacement-to-predecessor map in the persistence envelope across relaunch, and still requeue leftover snapshot deletes when the next publication is empty.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): wait for every shared-mailbox replacement before deleting

Two Claude Swap slots can share one email-keyed predecessor. Delete that leftover only after no unsaved replacement still points at it.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): retry lost CloudKit responses and keep shared leftovers

Treat serverResponseLost as a recoverable retry, and confirm saved replacements before abandoning failed siblings so a shared email-keyed record is not deleted early.

* fix(sync): queue predecessor deletes for unchanged slot payloads

When a slot snapshot is already published, newly obsolete email-keyed leftovers still need to be recorded and deleted instead of being skipped by the payload-hash shortcut.

* fix(sync): confirm slot saves and ignore remote cache as live

Predecessor deletes now wait for a confirmed replacement hash, and delete retries treat only local pending/confirmed snapshots as live so a fetched leftover cannot cancel its own removal.

* fix(sync): do not treat terminal save failures as confirmed

Skip retrying an unchanged terminal replacement without recording it in lastSnapshotHashes, so an unconfirmed slot cannot retire an email-keyed leftover.

* fix(sync): record confirmed save hashes and skip all terminal snapshot saves

Confirmed CloudKit saves now keep the in-flight payload hash, and terminal failures skip retrying that hash even when the snapshot has no predecessor.

* fix(sync): requeue in-flight snapshot updates and clear save markers on stop

A newer payload that arrives during an unconfirmed save stays pending and is flushed after that save completes, and toggling iCloud off no longer leaves in-flight hashes that skip every later publication.

* fix(sync): retry unavailable iCloud accounts and drop in-flight hashes on conflict

accountTemporarilyUnavailable is treated as a transient CloudKit error, and a server-winning conflict no longer leaves pendingSaveHashes blocking later snapshot publications.

* fix(sync): do not requeue fetched snapshots over in-flight local saves

Fetched CloudKit snapshots no longer overwrite an in-flight local payload, and pending local updates win when merging unpublished fleet cache entries.

* fix(sync): drop retained snapshots when iCloud sync stops

Pending snapshot payloads from before disable are discarded so re-enabling sync cannot upload or delete against a stale account set.

* fix(sync): limit email-keyed snapshot cleanup to Claude Swap

Predecessor deletes must not run for other providers that move from
email to a durable account ID. Drop the unreleased changelog line.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): defer restored predecessor deletes until live snapshots reconcile

CKSyncEngine can confirm an in-flight slot save on relaunch before local snapshots publish. Wait until that set is applied so a leftover email-keyed record that became live again is not deleted.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* perf(spend): parallelize loads and memoize model build

- Parallelize independent provider refreshes in makeRequest via
  TaskGroup (was sequential 400ms-6s additive).
- Parallelize Codex multi-account loads in SpendDashboardSource.load
  via ThrowingTaskGroup (was sequential 2s×N).
- Memoize SpendDashboardModel: cache CurrencyExchange conversion per
  currency pair, hoist bounds once per build, and reuse static
  utcCalendar for Mistral/OpenRouter bucket (was new calendar per
  entry, 2920× per build).

Evidence:
- SpendDashboardController.swift:237 parallel baselines
- SpendDashboardController.swift:433 parallel codex
- SpendDashboardModel.swift:300 conversionCache + bounds hoist
- SpendDashboardModel.swift:1069 utcCalendar reuse

Before: 全部 3-10s empty → 2-3s; build 40ms → 8ms.
After: TaskGroup wall-time = slowest provider, model build cached.

* fix(spend): restore Codex account order after parallel load

Task group completion order was appended directly to inputs, but providerRows uses input offset as tie-breaker for equal/unknown totals, so out-of-order completions reordered Codex · #1/#2 rows. Carry request index and sort results before appending, with compact formatting to keep file_length under warning.

Fixes ClawSweeper P2 for #3105.

* test(spend): add out-of-order Codex concurrent order regression

Verifies that parallel Codex loads restore configured request order even when second account's snapshot completes first. Equal totals make completion order visible via providerRows tie-breaker, so without sorting the rows would reorder.

Covers ClawSweeper P2 for #3105 and serves as needs-proof evidence.

* test: update gatekeeper anchors after rebase to 54.0

* fix(spend): repair parallel load CI - file_length and escaping captures

* fix(spend): debounce frequent refresh and throttle date window rebuilds

- 250ms debounce for withObservationTracking and token publication bursts
- 30s throttle for refreshDateWindow same-day revisits
- display-only fast path to avoid Codex scan for filter/currency changes
- update gatekeeper anchors for line shifts

* Improve Antigravity retrieval: retired Flash alias and offline fallback

- Map retired Flash wire ids (3.6/3.5/3-flash-agent) to 3.7-flash via canonicalModelID (opencodex RETIRED_FLASH_TIERS lesson), humanize via canonical, dedup collapsed windows by lowest remaining
- Add AntigravityOfflineStore counting ~/.gemini/antigravity-cli/conversations/*.db (GEMINI_CLI_HOME override) with tokscale cache fallback, and AntigravityOfflineFetchStrategy as terminal offline probe in auto/cli pipelines
- Cover with AntigravityModelLabelTests retired alias cases and AntigravityOfflineStoreTests (db/cache/count)

* fix(gate): add missing provider-specific markers and sync anchors

- add // Provider-specific by design for OpenCodex enrichment and token publication sync
- sync gate anchors after debounce/throttle line shifts

* fix(lint): wrap long provider-specific comment

* Fix provider architecture gatekeeper for Antigravity offline and retired alias

- Move CLI home marker to before gemini literal and update SpendDashboard marker to avoid flagging its own reason
- Add marker before family() and update suppressed anchors to 748/751/754/757
- Allowlist offline gemini, family cluster, and UsageStore codex constructs

* test: include offline strategy in antigravity pipeline expectations

* fix(gate): sync remaining anchors and add missing markers

* chore: trigger CI

* fix(spend): make debounce instant for testing

* fix(gate): update anchors after merge with main

* fix(lint): break long delay line

* fix(gate): drop stale codex anchor absorbed by sourceRevisions cluster
* Persist Codex priority-turn scan cursor across relaunches

After every relaunch, CodexBar's first Codex refresh re-scans the whole codex
CLI trace DB. Profiling (release CodexBarCLI, real ~/.codex, sample(1)) pinned
it on CostUsageScanner.codexPriorityTurns: three leading-wildcard
`feedback_log_body LIKE '%...%'` predicates over `logs_2.sqlite` (1.4 GB /
130k rows on the reference machine) — a full body-column scan. With a cold OS
page cache that is ~2 minutes of I/O-bound wall time (~20 s CPU); with a warm
page cache it is ~2.5-3 s of CPU on every relaunch. The function already scans
incrementally (`rowid > lastRowID`) through a process-global memo, but that
memo was never persisted, and app refreshes always inspect priority turns
(`bypassScannerDebounce` → `refreshMinIntervalSeconds = 0`), so every process
launch paid the cold scan again.

Persist the memo cursor (lastRowID, sqlite file identity, coverage epoch,
accumulated turns) in the codex cost cache metadata next to the existing
StoredPriorityState, and seed the memo from it before the cold path runs.
All existing invalidation rules still apply to a seeded cursor (file identity
change, rowid regression, window expanded earlier than coverage), and
`forceRescan` drops the memo instead of seeding it.

Two steady-state guards: the cursor is excluded from the identical-content
save comparison (its lastRowID advances on nearly every refresh) and is
written as a metadata-only update on the skip path, so the cheap no-op save
stays cheap; and the cursor decodes leniently so a malformed cursor can never
take `turnKeys` down with it (which would trigger cache-wide reprocessing).

CodexParserHash is regenerated because hashed scanner sources changed; the
previous hash (2d17f4981b78d07f) is added to compatiblePredecessorParserHashes
since parsing and the persisted row shape are unchanged, so existing
cost-usage.sqlite stores are adopted on upgrade instead of rebuilt (an old
priority payload without a cursor simply yields one cold trace-DB scan).

Measured (isolated cache root, same real data, same machine): the first
refresh after a relaunch drops from ~5.4-5.9 s / ~5.0-5.5 s CPU (main) to
~2.9-3.3 s / ~2.6-3.1 s CPU (this change); token and cost totals are identical
at every step; the within-interval cached fast path is unchanged (~0.8 s).

Tests: 9 new cases in CostUsageScannerCodexPriorityCursorTests covering
relaunch reuse with incremental-only scanning, inode change, window
expansion, old payload compatibility, live-memo-wins seeding, stale-cursor
re-accumulation idempotency, skip-path cursor persistence, malformed cursor
decode, and force rescan; plus a predecessor-adoption case in
CostUsageStoreTests for a cursorless payload.

Implemented by grok-4.6 (xhigh) via implementation-loop; reviewed hunk by
hunk plus an independent deep review; one iterate round.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: add changelog entry for #3130

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Validate the persisted priority cursor with a content anchor

Review feedback on #3130: the persisted cursor's `fileIdentity` is only the
sqlite inode. If `logs_2.sqlite` is deleted and recreated between launches
and the filesystem reuses the inode, and the replacement already has
`maxRowID >= lastRowID`, the inode check accepts the stale cursor and the
`rowid > lastRowID` query skips every replacement row up to lastRowID while
stale priority classifications are retained. In-process that window was
short; with persistence it is arbitrarily long.

Add a content anchor to both the in-memory memo and the persisted cursor:
the rowid the accumulation ended on plus the SHA-256 of that row's
`"<ts>\n<feedback_log_body>"`. Capture it with one primary-key lookup after
each successful accumulation (if the lookup fails the turns are still
returned but nothing is memoized or persisted), and validate it before
resuming: a missing row or a digest mismatch forces a full rescan. The inode
check stays as a cheap pre-check. A missing anchor row can also be Codex
pruning old rows in place; the conservative full rescan is intended there.
SHA-256 uses the repo's CryptoKit/swift-crypto pattern so the Linux CLI
still builds.

Tests: replaced database with a reused inode (anchor mismatch -> full
rescan; matching anchor -> incremental control), deleted anchor row ->
full rescan, payload without anchor fields -> nil cursor / cold scan; the
relaunch test now also asserts the anchor survives and advances.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(codex): show Business monthly credit on stacked cards

Stacked account fetches skipped the spend-controls credits path, so
Enterprise/Business cards showed Limits not available instead of used vs cap.

* docs: credit #3112 changelog entry

* fix(codex): keep cached monthly limits after spend-controls failures

Transient enrichment errors were persisted as missing credits, so stacked Business cards fell back to “Limits not available.” Restore the unreleased changelog heading as well.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): clear published credits when the monthly cap is gone

Successful spend-controls absence skipped publication and left the old cap on the selected account. Retarget gatekeeper fingerprints after that cluster split.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): keep monthly-only usage out of reset-credit rescue

A transient spend-controls failure still produced a success with no windows, and OAuth reset-credit rescue converted that into noRateLimitsFound before the cached monthly cap could be preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): treat unmappable monthly limits as enrichment failures

A nested spend-controls limit that is present but not numeric is no longer treated as confirmed absence, so a cached Business cap is preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): honor disabled caps and unmappable monthly usage

Inactive enforcement still confirms absence even if limit JSON is malformed, and a non-numeric current_month_usage is treated as enrichment failure instead of zero used.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): let an absent monthly cap win over malformed usage

Malformed current_month_usage only counts as enrichment failure when an active numeric limit actually needs that used amount.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): hide monthly credit when optional credits are off

Override-derived monthly lanes now follow Show credits + extra usage, so stacked Business cards no longer keep a credit meter the user asked to hide.

* fix(codex): include monthly credits in compact account planning

Inactive compact rows now see per-account monthly caps so an exhausted Business limit cannot hide behind a window-less usage snapshot.

* fix(codex): preserve only the monthly cap after enrichment failure

When spend-controls fails and usage confirmed there is no generic credit balance, keep the cached monthly limit without republishing stale remaining/events.

* fix(codex): fail monthly enrichment when account id or enforcement is unknown

A gated spend-controls fetch without an account id, or a non-string enforcement_mode, is now inconclusive so a cached Business cap is not cleared or published as active.

* fix(codex): hide menu-bar monthly credit when optional credits are off

Menu-bar projections now omit the optional monthly cap when the credits toggle is off, and a mappable nonpositive limit confirms cap removal even if enforcement is unreadable.

* fix(codex): reject non-finite monthly credit values

NaN and Infinity usage or limit strings are treated as mapping failures so they cannot zero out cached usage or persist invalid credit snapshots.

* fix(codex): keep monthly cap through standalone credits refresh

When spend-controls enrichment fails, the follow-up credits refresh now merges the prior monthly limit instead of publishing a generic-only snapshot.

* fix(codex): clear generic credits when monthly enrichment fails

A standalone credits refresh that confirms the generic balance is gone now publishes nil instead of throwing, so stale credits are not restored while a monthly cap is still preserved when one exists.

* fix(codex): retarget snapshot-store architecture suppressions

The monthly-cap helper shifted the Codex identity anchors, so the provider-architecture allowlist now points at the new lines.

* fix(codex): fetch monthly credits when plan type is unknown

Spend-control accounts with a missing or unmapped plan type now query the monthly endpoint, so a cached Business cap is not treated as confirmed removal.

* fix(codex): hydrate cached monthly credits and clear stale generic balance

Offline startup left the menu-bar projection without the disk-cached cap, and enrichment failure kept a generic balance when the monthly cap was already absent.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): persist standalone credits onto account snapshots

Usage refresh stored the selected account snapshot before the credits pass, so a later cap add or removal never reached disk and offline hydration replayed the stale value.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): persist credits using workspace identity

Same-email workspace accounts made the snapshot write a no-op; match the published cap with the scoped refresh identity so only the selected workspace row is stored.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: retrigger CI

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* Fix menu bar layout editor drag-and-drop

Layout editor chips were Buttons with .draggable attached. On macOS the
button's gesture recognizer claims the mouse-down, so no drag session ever
starts: reordering and the trash drop zone were unreachable by mouse and the
Delete key was the only way to remove a token. Moving .draggable onto the
button label does not help, because the button still owns the gesture.

Replace the chips with a plain draggable view that keeps click selection,
keyboard activation, and accessibility, and make the trash zone a click
target for the selected token as well.

* Fix Codex CLI approval policy (#3118)

* docs: credit #3118 changelog entry

* fix(commandcode): Add support for individual-pro-v1 plan ($80/mo credits) (#3116)

* fix(commandcode): Add support for individual-pro-v1 plan ($80/mo credits)

Command Code's updated Pro tier ($20/mo → $80 credits) ships as
individual-pro-v1 (legacy individual-pro remains $30). The new planId
hit the hard unknownPlan throw in CommandCodeUsageFetcher, surfaced as
'Unknown Command Code plan: individual-pro-v1'.

Add the versioned plan to CommandCodePlanCatalog (verified against
live frontend bundle assets/constants-B6rERLKd.js and pricing docs).
Pro pricing now: $20 → $80 (docs/resources/pricing-limits), legacy
Pro kept for backwards compat.

* test(commandcode): Cover individual-pro-v1 plan resolution

Regression coverage for the $80 Pro v1 tier: an active subscription
with planId individual-pro-v1 must resolve through
CommandCodePlanCatalog instead of hitting the unknownPlan throw, and
the catalog check now pins pro-v1 at 80 credits.

* fix(alibaba): tolerate the Personal usage gateway's empty-Success responses (#3128)

Mainland Personal/Solo Token Plan (cn-personal) intermittently shows "Could not
parse Alibaba Token Plan usage: Missing Personal usage windows" even though auth
succeeds. The `/tokenplan/personal/api/v2/usage` gateway sometimes answers with a
200 "Success" envelope (`code=SUCCESS`, `successResponse=true`, empty errorCode)
whose payload omits the `per5HourPercentage`/`per1WeekPercentage` windows. The
parser treated that absence as a hard parse failure.

- Throw a distinct `.usageWindowsUnavailable` for a Success-with-no-windows body
  instead of `parseFailed("Missing Personal usage windows")`.
- Retry the usage call a few times (the payload is usually populated on an
  immediate re-request) before surfacing it.
- When it stays empty, surface the softer "temporarily unavailable; it will
  refresh automatically" message. CodexBar keeps the last-good card either way
  (a returned empty snapshot would blank it, so this stays a thrown error).

Verified on a real cn-personal account: the fetch retries and, while the endpoint
was returning empty, surfaced the transient message with the last-good card
preserved. Adds AlibabaTokenPlanPersonalUsageRetryTests (recovers when a full
response follows an empty one; throws .usageWindowsUnavailable when every attempt
is empty).

Refs #2500.

Co-authored-by: LeoLin <leolin990405@gmail.com>

* docs: credit #3116 and #3128 changelog entries

* fix(claude): migrate email-keyed iCloud snapshots to slot keys (#3111)

* fix(claude): migrate email-keyed iCloud snapshots to slot keys

* fix(sync): confirm CloudKit snapshot saves before deleting predecessors

Terminal delete failures are reported once with delayed retries only for
recoverable errors, and email-keyed leftovers wait until the replacement
record is saved.

* fix(sync): persist leftover snapshot deletes across delayed retries

Keep pending predecessor deletes in the persistence envelope before sleeping so a relaunch can finish the CloudKit migration if the retry task never ran.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): stop retrying terminal CloudKit replacement saves

Mark slot-keyed migration snapshots complete after permission, auth, or invalid-argument save failures so the 120s snapshot push does not keep requeueing the same record.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): bind delayed CloudKit deletes to the originating engine

Skip leftover-record retries after an account switch so a sleeping task cannot delete a same-named snapshot in a newly signed-in iCloud account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): drop stale CloudKit predecessors that are live again

A later live email-keyed snapshot must not stay queued for delete just because an earlier slot-keyed save still has a pending predecessor set.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): cancel leftover snapshot deletes when they become live

A delayed CloudKit retry must not delete an email-keyed snapshot that was published again after a transient predecessor delete. Drop that name from the persisted retry set and the engine queue.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): do not retry CloudKit deletes for live snapshots

A transient in-flight delete can land after the predecessor is live again. Skip persist-and-retry when the record is in the current live snapshot set so cancellation is not resurrected.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): isolate CloudKit migration state from the next iCloud account

Clear predecessor maps and snapshot hashes when persistence is wiped, and requeue leftover deletes only after the current live snapshot set has been reconciled.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): persist predecessor deletes and requeue empty publications

Keep the replacement-to-predecessor map in the persistence envelope across relaunch, and still requeue leftover snapshot deletes when the next publication is empty.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): wait for every shared-mailbox replacement before deleting

Two Claude Swap slots can share one email-keyed predecessor. Delete that leftover only after no unsaved replacement still points at it.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): retry lost CloudKit responses and keep shared leftovers

Treat serverResponseLost as a recoverable retry, and confirm saved replacements before abandoning failed siblings so a shared email-keyed record is not deleted early.

* fix(sync): queue predecessor deletes for unchanged slot payloads

When a slot snapshot is already published, newly obsolete email-keyed leftovers still need to be recorded and deleted instead of being skipped by the payload-hash shortcut.

* fix(sync): confirm slot saves and ignore remote cache as live

Predecessor deletes now wait for a confirmed replacement hash, and delete retries treat only local pending/confirmed snapshots as live so a fetched leftover cannot cancel its own removal.

* fix(sync): do not treat terminal save failures as confirmed

Skip retrying an unchanged terminal replacement without recording it in lastSnapshotHashes, so an unconfirmed slot cannot retire an email-keyed leftover.

* fix(sync): record confirmed save hashes and skip all terminal snapshot saves

Confirmed CloudKit saves now keep the in-flight payload hash, and terminal failures skip retrying that hash even when the snapshot has no predecessor.

* fix(sync): requeue in-flight snapshot updates and clear save markers on stop

A newer payload that arrives during an unconfirmed save stays pending and is flushed after that save completes, and toggling iCloud off no longer leaves in-flight hashes that skip every later publication.

* fix(sync): retry unavailable iCloud accounts and drop in-flight hashes on conflict

accountTemporarilyUnavailable is treated as a transient CloudKit error, and a server-winning conflict no longer leaves pendingSaveHashes blocking later snapshot publications.

* fix(sync): do not requeue fetched snapshots over in-flight local saves

Fetched CloudKit snapshots no longer overwrite an in-flight local payload, and pending local updates win when merging unpublished fleet cache entries.

* fix(sync): drop retained snapshots when iCloud sync stops

Pending snapshot payloads from before disable are discarded so re-enabling sync cannot upload or delete against a stale account set.

* fix(sync): limit email-keyed snapshot cleanup to Claude Swap

Predecessor deletes must not run for other providers that move from
email to a durable account ID. Drop the unreleased changelog line.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(sync): defer restored predecessor deletes until live snapshots reconcile

CKSyncEngine can confirm an in-flight slot save on relaunch before local snapshots publish. Wait until that set is applied so a leftover email-keyed record that became live again is not deleted.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codex): isolate profile-scoped token cost snapshots (#3132)

* docs: credit #3111 changelog entry

* perf(spend): parallelize loads and memoize model build (#3105)

* perf(spend): parallelize loads and memoize model build

- Parallelize independent provider refreshes in makeRequest via
  TaskGroup (was sequential 400ms-6s additive).
- Parallelize Codex multi-account loads in SpendDashboardSource.load
  via ThrowingTaskGroup (was sequential 2s×N).
- Memoize SpendDashboardModel: cache CurrencyExchange conversion per
  currency pair, hoist bounds once per build, and reuse static
  utcCalendar for Mistral/OpenRouter bucket (was new calendar per
  entry, 2920× per build).

Evidence:
- SpendDashboardController.swift:237 parallel baselines
- SpendDashboardController.swift:433 parallel codex
- SpendDashboardModel.swift:300 conversionCache + bounds hoist
- SpendDashboardModel.swift:1069 utcCalendar reuse

Before: 全部 3-10s empty → 2-3s; build 40ms → 8ms.
After: TaskGroup wall-time = slowest provider, model build cached.

* fix(spend): restore Codex account order after parallel load

Task group completion order was appended directly to inputs, but providerRows uses input offset as tie-breaker for equal/unknown totals, so out-of-order completions reordered Codex · #1/#2 rows. Carry request index and sort results before appending, with compact formatting to keep file_length under warning.

Fixes ClawSweeper P2 for #3105.

* test(spend): add out-of-order Codex concurrent order regression

Verifies that parallel Codex loads restore configured request order even when second account's snapshot completes first. Equal totals make completion order visible via providerRows tie-breaker, so without sorting the rows would reorder.

Covers ClawSweeper P2 for #3105 and serves as needs-proof evidence.

* test: update gatekeeper anchors after rebase to 54.0

* fix(spend): repair parallel load CI - file_length and escaping captures

* fix(spend): debounce frequent refresh and throttle date window rebuilds

- 250ms debounce for withObservationTracking and token publication bursts
- 30s throttle for refreshDateWindow same-day revisits
- display-only fast path to avoid Codex scan for filter/currency changes
- update gatekeeper anchors for line shifts

* Improve Antigravity retrieval: retired Flash alias and offline fallback

- Map retired Flash wire ids (3.6/3.5/3-flash-agent) to 3.7-flash via canonicalModelID (opencodex RETIRED_FLASH_TIERS lesson), humanize via canonical, dedup collapsed windows by lowest remaining
- Add AntigravityOfflineStore counting ~/.gemini/antigravity-cli/conversations/*.db (GEMINI_CLI_HOME override) with tokscale cache fallback, and AntigravityOfflineFetchStrategy as terminal offline probe in auto/cli pipelines
- Cover with AntigravityModelLabelTests retired alias cases and AntigravityOfflineStoreTests (db/cache/count)

* fix(gate): add missing provider-specific markers and sync anchors

- add // Provider-specific by design for OpenCodex enrichment and token publication sync
- sync gate anchors after debounce/throttle line shifts

* fix(lint): wrap long provider-specific comment

* Fix provider architecture gatekeeper for Antigravity offline and retired alias

- Move CLI home marker to before gemini literal and update SpendDashboard marker to avoid flagging its own reason
- Add marker before family() and update suppressed anchors to 748/751/754/757
- Allowlist offline gemini, family cluster, and UsageStore codex constructs

* test: include offline strategy in antigravity pipeline expectations

* fix(gate): sync remaining anchors and add missing markers

* chore: trigger CI

* fix(spend): make debounce instant for testing

* fix(gate): update anchors after merge with main

* fix(lint): break long delay line

* fix(gate): drop stale codex anchor absorbed by sourceRevisions cluster

* docs: credit #3105 changelog entry

* style: swiftformat pass on layout editor chips

---------

Co-authored-by: kiranmagic7 <kiranmagic@proton.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Sebastian Marines <18373185+sebastianmarines@users.noreply.github.com>
Co-authored-by: Zhongyue Lin <101193087+LeoLin990405@users.noreply.github.com>
Co-authored-by: LeoLin <leolin990405@gmail.com>
Co-authored-by: sf-jin-ku <jin.ku@sendbird.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>
* feat(cursor): show Grok Bot weekly included usage

Grok Bot is billed on the Cursor session, so surface it as a fourth
Cursor card bar instead of a separate provider.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cursor): keep stalled Grok Bot fetch from failing login

Cap the best-effort Sand request at 5s and do not fail Cursor login
after usage-summary has already succeeded.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
@ColumbusLabs
ColumbusLabs enabled auto-merge August 24, 2026 01:45
@ColumbusLabs
ColumbusLabs merged commit 4a4e0b4 into main Aug 24, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants