huskies: merge 556_bug_stale_filesystem_shadows_in_1_backlog_cause_auto_assign_to_promote_archived_stories
This commit is contained in:
@@ -30,6 +30,9 @@ pub(super) fn scan_stage_items(project_root: &Path, stage_dir: &str) -> Vec<Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also include filesystem items (backwards compat / migration fallback).
|
// Also include filesystem items (backwards compat / migration fallback).
|
||||||
|
// Skip any story the CRDT already tracks — its authoritative stage wins.
|
||||||
|
// Stale .md files in pipeline dirs (e.g. 1_backlog/) must not shadow an
|
||||||
|
// archived or otherwise-moved story in the CRDT.
|
||||||
let dir = project_root.join(".huskies").join("work").join(stage_dir);
|
let dir = project_root.join(".huskies").join("work").join(stage_dir);
|
||||||
if dir.is_dir()
|
if dir.is_dir()
|
||||||
&& let Ok(entries) = std::fs::read_dir(&dir)
|
&& let Ok(entries) = std::fs::read_dir(&dir)
|
||||||
@@ -39,6 +42,14 @@ pub(super) fn scan_stage_items(project_root: &Path, stage_dir: &str) -> Vec<Stri
|
|||||||
if path.extension().and_then(|e| e.to_str()) == Some("md")
|
if path.extension().and_then(|e| e.to_str()) == Some("md")
|
||||||
&& let Some(stem) = path.file_stem().and_then(|s| s.to_str())
|
&& let Some(stem) = path.file_stem().and_then(|s| s.to_str())
|
||||||
{
|
{
|
||||||
|
// If the CRDT knows about this story (any stage), trust the CRDT.
|
||||||
|
if crate::pipeline_state::read_typed(stem)
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
items.insert(stem.to_string());
|
items.insert(stem.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +178,39 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Bug 556: stale filesystem shadow must not override CRDT stage ──────────
|
||||||
|
//
|
||||||
|
// A story file left in 1_backlog/ on disk but tracked as 6_archived in the
|
||||||
|
// CRDT must NOT appear when scanning 1_backlog. Without the fix, the
|
||||||
|
// filesystem fallback would add it, causing promote_ready_backlog_stories to
|
||||||
|
// attempt to promote an archived story.
|
||||||
|
#[test]
|
||||||
|
fn scan_stage_items_skips_filesystem_item_known_to_crdt_at_different_stage() {
|
||||||
|
crate::db::ensure_content_store();
|
||||||
|
// Write the story into the CRDT as 6_archived.
|
||||||
|
crate::db::write_item_with_content(
|
||||||
|
"9970_story_archived",
|
||||||
|
"6_archived",
|
||||||
|
"---\nname: Archived\n---\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Also place a stale .md file in a temp 1_backlog/ dir.
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let backlog = tmp.path().join(".huskies/work/1_backlog");
|
||||||
|
std::fs::create_dir_all(&backlog).unwrap();
|
||||||
|
std::fs::write(
|
||||||
|
backlog.join("9970_story_archived.md"),
|
||||||
|
"---\nname: Archived\n---\n",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let items = scan_stage_items(tmp.path(), "1_backlog");
|
||||||
|
assert!(
|
||||||
|
!items.contains(&"9970_story_archived".to_string()),
|
||||||
|
"archived CRDT story must not appear in 1_backlog scan via stale filesystem shadow"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn scan_stage_items_returns_empty_for_missing_dir() {
|
fn scan_stage_items_returns_empty_for_missing_dir() {
|
||||||
// Use a unique stage name that no other test writes to, so
|
// Use a unique stage name that no other test writes to, so
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ fn read_coverage_report(path: &std::path::Path) -> String {
|
|||||||
let report: CoverageReport = match serde_json::from_str(&content) {
|
let report: CoverageReport = match serde_json::from_str(&content) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return format!("**Coverage (cached)**\n\nFailed to parse `.coverage_report.json`: {e}");
|
return format!(
|
||||||
|
"**Coverage (cached)**\n\nFailed to parse `.coverage_report.json`: {e}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user