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 <noreply@anthropic.com>
This commit is contained in:
dave
2026-04-10 00:21:39 +00:00
parent 934bda5904
commit d1b845fd2e
+10 -2
View File
@@ -44,7 +44,15 @@ fn move_item<'a>(
// Verify it's in one of the expected source stages. // Verify it's in one of the expected source stages.
let src_dir = sources.iter().find(|&&s| current_dir == s).copied(); let src_dir = sources.iter().find(|&&s| current_dir == s).copied();
if src_dir.is_none() && !missing_ok { 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 let locs = sources
.iter() .iter()
.map(|s| format!("work/{s}/")) .map(|s| format!("work/{s}/"))
@@ -52,7 +60,7 @@ fn move_item<'a>(
.join(" or "); .join(" or ");
return Err(format!("Work item '{story_id}' not found in {locs}.")); return Err(format!("Work item '{story_id}' not found in {locs}."));
} }
let src_dir = src_dir.unwrap_or(sources[0]); };
// Optionally clear front-matter fields from the stored content. // Optionally clear front-matter fields from the stored content.
let transform: ContentTransform = if fields_to_clear.is_empty() { let transform: ContentTransform = if fields_to_clear.is_empty() {