Files
codex/codex-rs/protocol/src/security_risk.rs
T
jif 2a452d7dc1 Keep the latest Guardian risk score during concurrent sampling (#38580)
## Why

Concurrent Guardian samples can finish out of order, allowing an older sample to
replace the thread's newer in-memory security risk score.

## What changed

- Record when each `SecurityRiskScore` sample starts while preserving compatibility
  with records that have no timestamp.
- Add `ExtensionData::insert_if` so checking and replacing a typed attachment happen
  under the same lock.
- Update Guardian V2 to replace the thread's risk score only when the completed sample
  is newer than the stored one.

## Testing

- Verify concurrent conditional inserts retain the newest value.
- Verify Guardian-generated risk scores include a sampling timestamp.

GitOrigin-RevId: 6543a4e5497da4c623331050789e91613f931c4b
2026-08-14 13:44:51 +00:00

20 lines
748 B
Rust

use chrono::DateTime;
use chrono::Utc;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
/// A durable, thread-owned snapshot of security risk classifier scores.
///
/// These records belong to rollout history only and must not enter model-visible
/// conversation context or user-visible thread item projections.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SecurityRiskScore {
pub scores: BTreeMap<String, f64>,
/// When sampling started, if this snapshot was written by a timestamp-aware client.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[schemars(with = "Option<String>")]
pub sampled_at: Option<DateTime<Utc>>,
}