diff --git a/server/src/db/ops.rs b/server/src/db/ops.rs index 3f282945..6eb2aea0 100644 --- a/server/src/db/ops.rs +++ b/server/src/db/ops.rs @@ -132,24 +132,10 @@ pub fn move_item_stage( _ => None, }; - let (name, agent, _ignored_retry_count, blocked, depends_on) = content - .as_deref() - .or(current_content.as_deref()) - .and_then(|c| parse_front_matter(c).ok()) - .map(|meta| { - ( - meta.name, - meta.agent, - meta.retry_count.map(|r| r as i64), - meta.blocked, - meta.depends_on - .as_ref() - .and_then(|d| serde_json::to_string(d).ok()), - ) - }) - .unwrap_or((None, None, None, None, None)); - - // CRDT stage transition. + // Story 929: metadata (name/agent/blocked/depends_on) is owned by the + // CRDT typed registers — no need to re-derive it from the content body's + // YAML front matter on every stage transition. Pass `None` for those + // fields so write_item leaves the existing registers untouched. let merged_at_ts = if crate::pipeline_state::Stage::from_dir(new_stage) .is_some_and(|s| matches!(s, crate::pipeline_state::Stage::Done { .. })) { @@ -160,11 +146,11 @@ pub fn move_item_stage( crate::crdt_state::write_item( story_id, new_stage, - name.as_deref(), - agent.as_deref(), None, - blocked, - depends_on.as_deref(), + None, + None, + None, + None, None, None, merged_at_ts, @@ -176,15 +162,24 @@ pub fn move_item_stage( // transitions. crate::crdt_state::set_retry_count(story_id, 0); - // Shadow table — always reset retry_count to 0 on stage transition. - let retry_count: Option = Some(0); + // Shadow table — read current metadata from the CRDT so the SQLite + // mirror stays in sync. Always reset retry_count to 0 on stage transition. if let Some(db) = PIPELINE_DB.get() { + let view = crate::crdt_state::read_item(story_id); + let name = view.as_ref().and_then(|v| v.name().map(str::to_string)); + let agent = view.as_ref().and_then(|v| v.agent().map(str::to_string)); + let blocked = view.as_ref().map(|v| v.blocked()); + let depends_on = view + .as_ref() + .map(|v| v.depends_on()) + .filter(|d| !d.is_empty()) + .and_then(|d| serde_json::to_string(d).ok()); let msg = PipelineWriteMsg { story_id: story_id.to_string(), stage: new_stage.to_string(), name, agent, - retry_count, + retry_count: Some(0), blocked, depends_on, content,