huskies: merge 520_story_typed_pipeline_state_machine_in_rust_foundation_replaces_stringly_typed_crdt_views_with_strict_enums_subsumes_436
This commit is contained in:
@@ -33,15 +33,17 @@ fn move_item<'a>(
|
||||
fields_to_clear: &[&str],
|
||||
) -> Result<Option<&'a str>, String> {
|
||||
// Check if the item is already in the target stage or a done stage.
|
||||
if let Some(item) = crate::crdt_state::read_item(story_id) {
|
||||
if item.stage == target_dir
|
||||
|| extra_done_dirs.iter().any(|d| item.stage == *d)
|
||||
// Use the typed projection for compile-safe stage comparison.
|
||||
if let Ok(Some(typed_item)) = crate::pipeline_state::read_typed(story_id) {
|
||||
let current_dir = typed_item.stage.dir_name();
|
||||
if current_dir == target_dir
|
||||
|| extra_done_dirs.contains(¤t_dir)
|
||||
{
|
||||
return Ok(None); // Idempotent: already there.
|
||||
}
|
||||
|
||||
// Verify it's in one of the expected source stages.
|
||||
let src_dir = sources.iter().find(|&&s| item.stage == s).copied();
|
||||
let src_dir = sources.iter().find(|&&s| current_dir == s).copied();
|
||||
if src_dir.is_none() && !missing_ok {
|
||||
let locs = sources
|
||||
.iter()
|
||||
|
||||
@@ -22,12 +22,10 @@ pub(super) fn scan_stage_items(project_root: &Path, stage_dir: &str) -> Vec<Stri
|
||||
use std::collections::BTreeSet;
|
||||
let mut items = BTreeSet::new();
|
||||
|
||||
// Include CRDT items — the primary source of truth for pipeline state.
|
||||
if let Some(all) = crate::crdt_state::read_all_items() {
|
||||
for item in &all {
|
||||
if item.stage == stage_dir {
|
||||
items.insert(item.story_id.clone());
|
||||
}
|
||||
// Include CRDT items via the typed projection — the primary source of truth.
|
||||
for item in crate::pipeline_state::read_all_typed() {
|
||||
if item.stage.dir_name() == stage_dir {
|
||||
items.insert(item.story_id.0.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ pub(super) fn has_unmet_dependencies(
|
||||
return true;
|
||||
}
|
||||
// If the CRDT had the item and returned empty deps, it means all are met.
|
||||
if crate::crdt_state::read_item(story_id).is_some() {
|
||||
if crate::pipeline_state::read_typed(story_id).ok().flatten().is_some() {
|
||||
return false;
|
||||
}
|
||||
// Fallback: filesystem check (CRDT not initialised or item not yet in CRDT).
|
||||
@@ -96,7 +96,7 @@ pub(super) fn check_archived_dependencies(
|
||||
story_id: &str,
|
||||
) -> Vec<u32> {
|
||||
// Prefer CRDT-based check when the item is known to CRDT.
|
||||
if crate::crdt_state::read_item(story_id).is_some() {
|
||||
if crate::pipeline_state::read_typed(story_id).ok().flatten().is_some() {
|
||||
return crate::crdt_state::check_archived_deps_crdt(story_id);
|
||||
}
|
||||
// Fallback: filesystem.
|
||||
|
||||
@@ -395,8 +395,10 @@ fn write_review_hold_to_store(story_id: &str) {
|
||||
let updated = crate::io::story_metadata::write_review_hold_in_content(&contents);
|
||||
crate::db::write_content(story_id, &updated);
|
||||
// Also persist to SQLite via shadow write.
|
||||
let stage = crate::crdt_state::read_item(story_id)
|
||||
.map(|i| i.stage)
|
||||
let stage = crate::pipeline_state::read_typed(story_id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|i| i.stage.dir_name().to_string())
|
||||
.unwrap_or_else(|| "3_qa".to_string());
|
||||
crate::db::write_item_with_content(story_id, &stage, &updated);
|
||||
} else {
|
||||
@@ -419,8 +421,10 @@ fn should_block_story(story_id: &str, max_retries: u32, stage_label: &str) -> Op
|
||||
if let Some(contents) = crate::db::read_content(story_id) {
|
||||
let (updated, new_count) = increment_retry_count_in_content(&contents);
|
||||
crate::db::write_content(story_id, &updated);
|
||||
let stage = crate::crdt_state::read_item(story_id)
|
||||
.map(|i| i.stage)
|
||||
let stage = crate::pipeline_state::read_typed(story_id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|i| i.stage.dir_name().to_string())
|
||||
.unwrap_or_else(|| "2_current".to_string());
|
||||
crate::db::write_item_with_content(story_id, &stage, &updated);
|
||||
|
||||
|
||||
@@ -23,18 +23,15 @@ impl AgentPool {
|
||||
/// Return the active pipeline stage directory name for `story_id`, or `None` if the
|
||||
/// story is not in any active stage (`2_current/`, `3_qa/`, `4_merge/`).
|
||||
pub(super) fn find_active_story_stage(project_root: &Path, story_id: &str) -> Option<&'static str> {
|
||||
const STAGES: [&str; 3] = ["2_current", "3_qa", "4_merge"];
|
||||
|
||||
// Try CRDT first — primary source of truth.
|
||||
if let Some(item) = crate::crdt_state::read_item(story_id) {
|
||||
for stage in &STAGES {
|
||||
if item.stage == *stage {
|
||||
return Some(stage);
|
||||
}
|
||||
}
|
||||
// Try typed CRDT projection first — primary source of truth.
|
||||
if let Ok(Some(item)) = crate::pipeline_state::read_typed(story_id)
|
||||
&& item.stage.is_active()
|
||||
{
|
||||
return Some(item.stage.dir_name());
|
||||
}
|
||||
|
||||
// Also check filesystem (backwards compat / tests).
|
||||
const STAGES: [&str; 3] = ["2_current", "3_qa", "4_merge"];
|
||||
for stage in &STAGES {
|
||||
let path = project_root
|
||||
.join(".huskies")
|
||||
|
||||
Reference in New Issue
Block a user