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:
@@ -344,47 +344,10 @@ pub fn validate_story_dirs(
|
|||||||
) -> Result<Vec<StoryValidationResult>, String> {
|
) -> Result<Vec<StoryValidationResult>, String> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
// Validate from typed projection + content store.
|
// Validate from filesystem shadows under the given root.
|
||||||
{
|
// NOTE: We intentionally read the filesystem here (not the global CRDT
|
||||||
let typed_items = crate::pipeline_state::read_all_typed();
|
// singleton) so that tests can pass an isolated tempdir and get
|
||||||
for item in typed_items {
|
// deterministic results. See bug 525.
|
||||||
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.
|
|
||||||
let dirs_to_validate = vec![
|
let dirs_to_validate = vec![
|
||||||
root.join(".huskies").join("work").join("2_current"),
|
root.join(".huskies").join("work").join("2_current"),
|
||||||
root.join(".huskies").join("work").join("1_backlog"),
|
root.join(".huskies").join("work").join("1_backlog"),
|
||||||
@@ -409,11 +372,6 @@ pub fn validate_story_dirs(
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string();
|
.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)
|
let contents = std::fs::read_to_string(&path)
|
||||||
.map_err(|e| format!("Failed to read {}: {e}", path.display()))?;
|
.map_err(|e| format!("Failed to read {}: {e}", path.display()))?;
|
||||||
match parse_front_matter(&contents) {
|
match parse_front_matter(&contents) {
|
||||||
|
|||||||
Reference in New Issue
Block a user