fix: validate_story_dirs reads filesystem shadows instead of global CRDT singleton (bug 525)

The post-520 migration changed validate_story_dirs to read from
pipeline_state::read_all_typed() (the process-global CRDT singleton),
ignoring its root: &Path argument. This broke test isolation — tests
creating a tempdir saw dozens of results from ambient CRDT state,
causing non-deterministic failures that blocked every mergemaster gate.

Remove the CRDT singleton block and rely on the filesystem shadow scan
that already uses the root argument correctly. 1845/1845 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Timmy
2026-04-10 10:52:42 +01:00
parent d1b845fd2e
commit 9633ab35a6
+4 -46
View File
@@ -344,47 +344,10 @@ pub fn validate_story_dirs(
) -> Result<Vec<StoryValidationResult>, String> {
let mut results = Vec::new();
// Validate from typed projection + content store.
{
let typed_items = crate::pipeline_state::read_all_typed();
for item in typed_items {
use crate::pipeline_state::Stage;
if !matches!(item.stage, Stage::Backlog | Stage::Coding) {
continue;
}
let sid = item.story_id.0.clone();
if let Some(content) = crate::db::read_content(&sid) {
match parse_front_matter(&content) {
Ok(meta) => {
let mut errors = Vec::new();
if meta.name.is_none() {
errors.push("Missing 'name' field".to_string());
}
if errors.is_empty() {
results.push(StoryValidationResult {
story_id: sid,
valid: true,
error: None,
});
} else {
results.push(StoryValidationResult {
story_id: sid,
valid: false,
error: Some(errors.join("; ")),
});
}
}
Err(e) => results.push(StoryValidationResult {
story_id: sid,
valid: false,
error: Some(e.to_string()),
}),
}
}
}
}
// Filesystem fallback: also check work/ directories.
// Validate from filesystem shadows under the given root.
// NOTE: We intentionally read the filesystem here (not the global CRDT
// singleton) so that tests can pass an isolated tempdir and get
// deterministic results. See bug 525.
let dirs_to_validate = vec![
root.join(".huskies").join("work").join("2_current"),
root.join(".huskies").join("work").join("1_backlog"),
@@ -409,11 +372,6 @@ pub fn validate_story_dirs(
.unwrap_or_default()
.to_string();
// Skip if already validated from CRDT.
if results.iter().any(|r| r.story_id == story_id) {
continue;
}
let contents = std::fs::read_to_string(&path)
.map_err(|e| format!("Failed to read {}: {e}", path.display()))?;
match parse_front_matter(&contents) {