Persist Daybreak preferences in thread metadata (#42854)

## Why

Clients need a per-thread Daybreak toggle that survives restarts and can be
restored on resume without changing the access program of an active or future
turn.

## What changed

- Add experimental `daybreakEnabled` support to `thread/metadata/update` and
  expose the saved value on thread responses.
- Store the preference in SQLite, including for threads without a first turn,
  and preserve it through reads, resumes, reconciliation, and restarts.
- Copy the preference when forking a thread while keeping subsequent updates
  independent.
- Keep `daybreakEnabled` separate from the per-turn `cyberAccessProgram` field;
  app-server does not derive one from the other.

## Testing

- Cover persistence across restarts, cold reads, reconciliation, and forks.
- Verify metadata updates do not alter the access program of active or later
  turns.

GitOrigin-RevId: bcf987a9fcd7b0ac8a88b1c8f0df06b33ed8ad6e
This commit is contained in:
faizan-oai
2026-09-04 21:17:25 +00:00
committed by copyberry
parent 4636819a35
commit 3921a30d6b
47 changed files with 555 additions and 52 deletions
@@ -283,6 +283,9 @@ pub struct Thread {
pub git_info: Option<GitInfo>,
/// Optional user-facing thread title.
pub name: Option<String>,
/// Saved Daybreak choice, independent of turn execution. Null if unset.
#[experimental("thread.daybreakEnabled")]
pub daybreak_enabled: Option<bool>,
/// Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read`
/// (when `includeTurns` is true) responses.
/// For all other responses and notifications returning a Thread,
@@ -330,6 +333,7 @@ struct ThreadCompatibility {
agent_role: Option<String>,
git_info: Option<GitInfo>,
name: Option<String>,
daybreak_enabled: Option<bool>,
turns: Vec<Turn>,
}
@@ -370,6 +374,7 @@ impl<'de> Deserialize<'de> for Thread {
agent_role: thread.agent_role,
git_info: thread.git_info,
name: thread.name,
daybreak_enabled: thread.daybreak_enabled,
turns: thread.turns,
})
}