Ensure side-chat policy reaches the first model request (#60067)

## Why

An inherited turn can suppress a fork's configured developer instructions, leaving the first side-chat request without its developer policy.

## What changed

- Move shared side-conversation instructions and the history boundary into `codex-context-fragments`.
- Inject the developer policy before the user-role boundary when creating a TUI side-chat fork, while retaining the configured instructions.
- Distinguish attached and temporary policies, applying the worktree restriction only to temporary side chats.
- Add guidance to set up recurring monitors in the main chat or a new chat because temporary side chats cannot run scheduled updates.

## Testing

Add a TUI integration test that checks the first side-chat model request contains the policy and boundary. Add a core request-history snapshot covering an attached side chat that preserves inherited context, policy, and its prior answer after resuming from disk.

GitOrigin-RevId: 889cb317dc3327457cd9ef0879ec9f77dbfaeeba
This commit is contained in:
Felipe Coury
2026-11-07 05:59:44 +00:00
committed by copyberry
parent 1c414e0d65
commit 0ed34eb9ce
10 changed files with 589 additions and 74 deletions
+5 -2
View File
@@ -142,6 +142,7 @@ use codex_app_server_protocol::TurnSteerParams;
use codex_app_server_protocol::TurnSteerResponse;
use codex_app_server_protocol::UserInput;
use codex_config::ConfigLayerSource;
use codex_context_fragments::SideConversationPolicy;
use codex_otel::TelemetryAuthMode;
use codex_protocol::ThreadId;
use codex_protocol::approvals::GuardianAssessmentEvent;
@@ -1215,7 +1216,6 @@ impl AppServerSession {
config: Config,
parent: ThreadId,
profile: Option<PermissionProfileSelection>,
boundary: ResponseItem,
) -> impl Future<Output = Result<SidebarFork>> + Send + use<> {
let mut view = self
.request_view()
@@ -1228,7 +1228,10 @@ impl AppServerSession {
.fork_side_thread(&settings, config, parent, profile.as_ref())
.await?;
let boundary = view
.thread_inject_items(thread.session.thread_id, vec![boundary])
.thread_inject_items(
thread.session.thread_id,
SideConversationPolicy::Temporary.fork_items(),
)
.await
.map(|_| ())
.map_err(|err| err.to_string());