mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
ensure thread.history_mode is immutable (#30261)
## Description This PR makes `thread.history_mode` immutable after the thread's canonical first `SessionMeta` has been written. Later same-thread `SessionMeta` lines are compatibility metadata writes, not a new thread definition. Without this, an older binary could append a `SessionMeta` that omits `history_mode`; when a newer binary replays it, serde defaults that missing field to `legacy` and SQLite could downgrade a paginated thread. ## Why `history_mode` is the persisted thread storage contract. Paginated-thread fail-closed behavior and SQLite memory filtering depend on it staying aligned with canonical rollout metadata, especially when multiple Codex binary versions can touch the same local rollout. ## What changed - Stop generic rollout metadata replay from overwriting `history_mode` from later `SessionMeta` items. - Remove `history_mode` from `ThreadMetadataPatch`, so mutable metadata sync and app-server metadata updates cannot rewrite it. - When local metadata sync has to recreate a missing SQLite row, recover `history_mode` from the rollout's canonical first `SessionMeta` instead of from a mutable patch. - Keep the in-memory thread store using the created thread's canonical `history_mode` instead of metadata patches. - Fill the one remaining core test `CreateThreadParams` initializer with the new `history_mode` field; Bazel CI caught this after the parent history-mode PR landed. ## Validation - `just fmt` - `just test -p codex-thread-store` - `just test -p codex-state session_meta_does_not_set_model_or_reasoning_effort`
This commit is contained in:
1 parent
cf36c688b3
commit
812cd2bb57
7 files changed
+226
-66
No files matched your search
@@ -218,17 +218,22 @@ mod tests {
|
||||
})
|
||||
.await
|
||||
.expect("register rollout path");
|
||||
store
|
||||
.update_thread_metadata(UpdateThreadMetadataParams {
|
||||
thread_id,
|
||||
patch: ThreadMetadataPatch {
|
||||
history_mode: Some(ThreadHistoryMode::Paginated),
|
||||
..Default::default()
|
||||
},
|
||||
include_archived: false,
|
||||
})
|
||||
.await
|
||||
.expect("seed paginated metadata");
|
||||
{
|
||||
let mut state = store.state.lock().await;
|
||||
state
|
||||
.created_threads
|
||||
.get_mut(&thread_id)
|
||||
.expect("created thread")
|
||||
.history_mode = ThreadHistoryMode::Paginated;
|
||||
let Some(RolloutItem::SessionMeta(meta_line)) = state
|
||||
.histories
|
||||
.get_mut(&thread_id)
|
||||
.and_then(|history| history.first_mut())
|
||||
else {
|
||||
panic!("canonical session meta");
|
||||
};
|
||||
meta_line.meta.history_mode = ThreadHistoryMode::Paginated;
|
||||
}
|
||||
|
||||
let thread = store
|
||||
.read_thread(ReadThreadParams {
|
||||
@@ -784,9 +789,7 @@ fn stored_thread_from_state(
|
||||
source: metadata
|
||||
.and_then(|metadata| metadata.source.clone())
|
||||
.unwrap_or_else(|| created.source.clone()),
|
||||
history_mode: metadata
|
||||
.and_then(|metadata| metadata.history_mode)
|
||||
.unwrap_or(created.history_mode),
|
||||
history_mode: created.history_mode,
|
||||
thread_source: metadata
|
||||
.and_then(|metadata| metadata.thread_source.clone())
|
||||
.unwrap_or_else(|| created.thread_source.clone()),
|
||||
@@ -811,15 +814,9 @@ fn history_mode_from_state(
|
||||
thread_id: ThreadId,
|
||||
) -> ThreadHistoryMode {
|
||||
state
|
||||
.metadata_updates
|
||||
.created_threads
|
||||
.get(&thread_id)
|
||||
.and_then(|metadata| metadata.history_mode)
|
||||
.or_else(|| {
|
||||
state
|
||||
.created_threads
|
||||
.get(&thread_id)
|
||||
.map(|thread| thread.history_mode)
|
||||
})
|
||||
.map(|thread| thread.history_mode)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user