fix(tui,core): scope auth-profile usage invalidation to the relogged profile#410
Conversation
8355a6e to
a6e18e5
Compare
…profile Recovered from a stale worktree (task/2f47aa47-pr211-repair). The rest of that branch duplicated PR #211, which already landed on main; only these two behavior fixes were never merged. - chatwidget/usage_limit_reset: relogin previously invalidated usage state only when the mutated profile was still the selected one, so a same-name relogin (or a relogin whose selection changed mid-flight) left stale exhausted-reset/heartbeat-suppression entries for that profile and the usage heartbeat stayed suppressed until the old reset time. Invalidation is now scoped: AllProfiles for account-level updates, Profile(name) for a credential mutation. The per-profile snapshot / heartbeat-requested / heartbeat-failed / exhausted-reset entries for the profiles in scope are always dropped; the global usage-limit reset state (generation, reset credits, in-flight and pending reset bookkeeping, limit-id snapshot caches) is reset only when the scope covers the currently selected profile, so relogging an unrelated profile no longer clears the live selected-profile snapshot or cancels its in-flight reset. - core/auth_profile_usage: the Ordered auto-switch strategy returned the first Unknown candidate immediately, so an earlier unknown-health profile beat a later known-healthy one. It now defers to the existing first_unknown fallback, matching HighestAvailable. Adds three TUI tests and one core test covering the new behavior.
a6e18e5 to
c32f719
Compare
Rebased onto current
|
| tests run | failed | |
|---|---|---|
| branch | 6497 | 57 |
main baseline |
6493 | 57 |
The two failing sets are identical (comm diff empty in both directions): pre-existing environment failures in codex-core::all — suite::cli_stream::*, suite::rmcp_client::*, suite::code_mode::*, suite::hooks_mcp::*, suite::shell_snapshot::*, suite::request_permissions::*, suite::truncation::mcp_*. This PR adds zero new failures.
Merge-result gate
git merge-tree --write-tree origin/main HEAD → 990bd7fdf7d66c0d1fcd4bec2502901129a6bfb3, byte-identical to HEAD^{tree}. Because the branch is rebased directly onto current origin/main (b71a05ee9), the merge is a fast-forward and the merge result is exactly the tree that run 30145816927 tested — the branch numbers above are the merge-result numbers.
Origin
Recovered from a stale worktree (
wt_2f47aa47, branchtask/2f47aa47-pr211-repair, untouched ~200h) during worktree triage.That branch's 3 commits duplicated PR #211 "Repair TUI thread routing stack", which already merged to
mainon 2026-07-21 fromrepair/pr0-wave2-tui-routing-stack, and itsscripts/list-bazel-clippy-targets.shchange is now byte-identical tomain. The uncommitted working tree, however, contained two behavior fixes that were never merged anywhere. This PR rebases only those onto currentmain; everything already upstream or superseded was dropped.Changes
1.
codex-rs/tui/src/chatwidget/usage_limit_reset/state.rs- profile-scoped invalidationfinish_selected_auth_profile_credential_mutationonly invalidated usage state when the mutated profile was still the selected one:Two consequences:
auth_profile_usage_exhausted_reset_at_by_profile/ heartbeat-suppression entries in place, so the usage heartbeat stayed suppressed for the old (now invalid) reset time even though the credentials changed.Invalidation is now scoped via a small
AuthProfileUsageInvalidationenum:AllProfiles- account-level update (existinginvalidate_rate_limit_reset_state_after_account_updatebehavior, plus it now also clears the per-profile caches).Profile(name)- a credential mutation: drops only that profile's snapshot / heartbeat-requested / heartbeat-failed / exhausted-reset entries, and clearsrate_limit_snapshots_by_limit_idonly when the relogged profile is the currently selected one (so an unrelated profile's relogin no longer nukes the live selected-profile snapshot).2.
codex-rs/core/src/auth_profile_usage.rs- Ordered strategy defers UnknownThe
Orderedauto-switch branch returned the firstUnknown-health candidate immediately, so an earlier unknown-health profile beat a later known-healthy one. It now feeds the existingfirst_unknownfallback (already used byHighestAvailableand already returned at the end of the function), so a known-healthy candidate wins andSelectedUnknownFallbackbehaves like the fallback its name implies.Tests
codex-tui:same_name_relogin_clears_exhausted_profile_heartbeat_suppression,relogin_invalidates_captured_profile_after_selection_changes,profile_relogin_invalidation_preserves_unrelated_profile_usage_statecodex-core:ordered_recommendation_prefers_healthy_over_earlier_unknownExplicitly dropped from the stale worktree
codex-rs/tui/src/app/app_server_events.rsmain;mainsolved the pre-primary leak differently (note_agent_metrics_from_notification+is_tracked_thread)codex-rs/tui/src/app/thread_routing.rscodex-rs/tui/src/app/tests.rsmainalready hasenqueue_primary_thread_session_*/pre_primary_untracked_request_stays_resolvable_on_addressed_threadcodex-rs/core/src/usage_profile_health.rs/*used_percent*/labels), no behaviorFull pre-image is archived at
~/.hasna/repos/recovery/wt_2f47aa47/.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.