From d1b845fd2e839912f5cabe24f4139dae155ed00f Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 10 Apr 2026 00:21:39 +0000 Subject: [PATCH] fix: move_item must not overwrite advanced CRDT stage when missing_ok=true (bug 524) When a story is found in the CRDT but not in the expected source stages, and missing_ok is true, return Ok(None) instead of proceeding with the move. This prevents promote_ready_backlog_stories from demoting a story that has already advanced to merge/done via a stale filesystem shadow in 1_backlog. Co-Authored-By: Claude Sonnet 4.6 --- server/src/agents/lifecycle.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/server/src/agents/lifecycle.rs b/server/src/agents/lifecycle.rs index d81bfab1..a911d44b 100644 --- a/server/src/agents/lifecycle.rs +++ b/server/src/agents/lifecycle.rs @@ -44,15 +44,23 @@ fn move_item<'a>( // Verify it's in one of the expected source stages. let src_dir = sources.iter().find(|&&s| current_dir == s).copied(); - if src_dir.is_none() && !missing_ok { - let locs = sources - .iter() - .map(|s| format!("work/{s}/")) - .collect::>() - .join(" or "); - return Err(format!("Work item '{story_id}' not found in {locs}.")); - } - let src_dir = src_dir.unwrap_or(sources[0]); + let src_dir = match src_dir { + Some(s) => s, + None if missing_ok => { + // Item is in CRDT but not in an expected source stage — do not + // overwrite its current stage. This prevents promote_ready_backlog_stories + // from demoting a story that has already advanced to merge/done (bug 524). + return Ok(None); + } + None => { + let locs = sources + .iter() + .map(|s| format!("work/{s}/")) + .collect::>() + .join(" or "); + return Err(format!("Work item '{story_id}' not found in {locs}.")); + } + }; // Optionally clear front-matter fields from the stored content. let transform: ContentTransform = if fields_to_clear.is_empty() {