Files
codex/codex-rs/memories/write/src/guard_tests.rs
T
stefanstokic-oai 4df8027a97 Honor workspace spend controls in rate-limit handling (#33187)
## Why

Sparse and out-of-order rate-limit updates can omit account metadata or let an
older full read overwrite a newer workspace hard stop. Credit availability also
does not always include a displayable balance.

## What changed

- Propagate the backend's `spendControlReached` state through rate-limit
  snapshots and the app-server protocol, preserving it across sparse updates.
- Keep workspace hard-stop classifications for error routing and ignore stale
  full-read results after a newer hard-stop notification.
- Base TUI warnings and model-switch prompts on credit availability and hard-stop
  state, and show `Credits: Available` when a finite balance is hidden.

## Testing

Added coverage for spend-control mapping, snapshot merging, out-of-order reads,
workspace error routing, warning and prompt behavior, and credit status display.

GitOrigin-RevId: 18b09d493d5a620a7c079fb721ec50b38dd5b04c
2026-07-14 22:43:26 +00:00

81 lines
2.2 KiB
Rust

use super::*;
use codex_protocol::protocol::RateLimitReachedType;
fn snapshot(
primary_used_percent: Option<f64>,
secondary_used_percent: Option<f64>,
) -> RateLimitSnapshot {
RateLimitSnapshot {
limit_id: Some(crate::guard_limits::CODEX_LIMIT_ID.to_string()),
limit_name: None,
primary: primary_used_percent.map(window),
secondary: secondary_used_percent.map(window),
credits: None,
individual_limit: None,
spend_control_reached: None,
plan_type: None,
rate_limit_reached_type: None,
}
}
fn window(used_percent: f64) -> RateLimitWindow {
RateLimitWindow {
used_percent,
window_minutes: None,
resets_at: None,
}
}
#[test]
fn startup_check_uses_configured_remaining_threshold() {
let snapshot = snapshot(
/*primary_used_percent*/ Some(89.9),
/*secondary_used_percent*/ Some(50.0),
);
assert!(snapshot_allows_startup(
&snapshot, /*min_remaining_percent*/ 10
));
assert!(!snapshot_allows_startup(
&snapshot, /*min_remaining_percent*/ 11
));
}
#[test]
fn startup_check_skips_when_primary_or_secondary_is_too_low() {
assert!(!snapshot_allows_startup(
&snapshot(
/*primary_used_percent*/ Some(75.1),
/*secondary_used_percent*/ Some(10.0),
),
/*min_remaining_percent*/ 25,
));
assert!(!snapshot_allows_startup(
&snapshot(
/*primary_used_percent*/ Some(10.0),
/*secondary_used_percent*/ Some(75.1),
),
/*min_remaining_percent*/ 25,
));
assert!(snapshot_allows_startup(
&snapshot(
/*primary_used_percent*/ Some(74.9),
/*secondary_used_percent*/ Some(74.9),
),
/*min_remaining_percent*/ 25,
));
}
#[test]
fn startup_check_skips_when_limit_is_reached() {
let mut snapshot = snapshot(
/*primary_used_percent*/ Some(10.0),
/*secondary_used_percent*/ Some(10.0),
);
snapshot.rate_limit_reached_type = Some(RateLimitReachedType::RateLimitReached);
assert!(!snapshot_allows_startup(
&snapshot, /*min_remaining_percent*/ 25,
));
}