Persist thread section moves before the first turn (#39523)

## Why

New non-ephemeral threads have no persisted rollout or preview until their first
turn, so moving them into a section could leave them absent from section-filtered
thread lists.

## What changed

- Materialize and flush a non-ephemeral thread before applying an explicit
  section move.
- Include explicitly sectioned threads with empty previews in section-filtered
  queries, and update the partial indexes to cover them.

## Testing

- Add an app-server test that moves a newly started thread into and out of the
  pinned section before its first turn.
- Cover empty-preview threads in recency and section-position query tests.

GitOrigin-RevId: aa3c4daf9890f06c08b93cd60f146099cbc6cfb2
This commit is contained in:
joeytrasatti-openai authored and copyberry committed 2026-08-19 17:57:40 +00:00
1 parent ffad922340
commit 1b450c7912
5 files changed
+119 -15

No files matched your search

+10 -7
View File
@@ -835,19 +835,22 @@ impl ThreadManager {
}
}
/// Moves a persisted thread to, within, or out of a server-ordered section.
/// Moves a thread to, within, or out of a server-ordered section.
pub async fn move_thread_to_section(
&self,
thread_id: ThreadId,
section: Option<&str>,
before_thread_id: Option<ThreadId>,
) -> CodexResult<()> {
if let Ok(thread) = self.get_thread(thread_id).await
&& thread.config_snapshot().await.ephemeral
{
return Err(CodexErr::InvalidRequest(format!(
"ephemeral thread does not support section moves: {thread_id}"
)));
if let Ok(thread) = self.get_thread(thread_id).await {
if thread.config_snapshot().await.ephemeral {
return Err(CodexErr::InvalidRequest(format!(
"ephemeral thread does not support section moves: {thread_id}"
)));
}
// Explicit placement must work before the first turn materializes the thread.
thread.ensure_rollout_materialized().await;
thread.flush_rollout().await?;
}
self.state