huskies: merge 946
This commit is contained in:
@@ -292,9 +292,12 @@ pub fn evict_item(story_id: &str) -> Result<(), String> {
|
||||
///
|
||||
/// Projects the loose CRDT `stage` register into a typed
|
||||
/// [`crate::pipeline_state::Stage`]. Items with an unknown or missing stage
|
||||
/// string are filtered out (`None`), so every `WorkItem` that escapes the
|
||||
/// read path carries a valid typed stage.
|
||||
/// string, or with no name set, are filtered out (`None`) — a nameless item
|
||||
/// is treated as malformed and never surfaces to callers.
|
||||
pub(super) fn extract_item_view(item: &PipelineItemCrdt) -> Option<PipelineItemView> {
|
||||
use super::types::{Claim, EpicId};
|
||||
use crate::io::story_metadata::{ItemType, QaMode};
|
||||
|
||||
let story_id = match item.story_id.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => s,
|
||||
_ => return None,
|
||||
@@ -303,48 +306,58 @@ pub(super) fn extract_item_view(item: &PipelineItemCrdt) -> Option<PipelineItemV
|
||||
JsonValue::String(s) if !s.is_empty() => s,
|
||||
_ => return None,
|
||||
};
|
||||
// AC 5: nameless item = malformed; filter it out.
|
||||
let name = match item.name.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
JsonValue::String(s) if !s.is_empty() => s,
|
||||
_ => return None,
|
||||
};
|
||||
let agent = match item.agent.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
};
|
||||
let retry_count = match item.retry_count.view() {
|
||||
JsonValue::Number(n) => Some(n as i64),
|
||||
_ => None,
|
||||
JsonValue::Number(n) if n >= 0.0 => n as u32,
|
||||
_ => 0u32,
|
||||
};
|
||||
let depends_on = match item.depends_on.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => serde_json::from_str::<Vec<u32>>(&s).ok(),
|
||||
_ => None,
|
||||
JsonValue::String(s) if !s.is_empty() => {
|
||||
serde_json::from_str::<Vec<u32>>(&s).unwrap_or_default()
|
||||
}
|
||||
_ => Vec::new(),
|
||||
};
|
||||
|
||||
let claimed_by = match item.claimed_by.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
};
|
||||
let claimed_at = match item.claimed_at.view() {
|
||||
JsonValue::Number(n) if n > 0.0 => Some(n),
|
||||
let claimed_at_secs = match item.claimed_at.view() {
|
||||
JsonValue::Number(n) if n > 0.0 => Some(n as u64),
|
||||
_ => None,
|
||||
};
|
||||
let merged_at = match item.merged_at.view() {
|
||||
let claim = match (claimed_by, claimed_at_secs) {
|
||||
(Some(node), Some(at)) => Some(Claim { node, at }),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// `merged_at` is read only to project into `Stage::Done`; it is not
|
||||
// stored on `WorkItem` (callers access it via `Stage::Done { merged_at }`).
|
||||
let merged_at_float = match item.merged_at.view() {
|
||||
JsonValue::Number(n) if n > 0.0 => Some(n),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let qa_mode = match item.qa_mode.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
JsonValue::String(s) if !s.is_empty() => QaMode::from_str(&s),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let item_type = match item.item_type.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
JsonValue::String(s) if !s.is_empty() => ItemType::from_str(&s),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let epic = match item.epic.view() {
|
||||
JsonValue::String(s) if !s.is_empty() => Some(s),
|
||||
JsonValue::String(s) if !s.is_empty() => EpicId::from_crdt_str(&s),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -353,7 +366,8 @@ pub(super) fn extract_item_view(item: &PipelineItemCrdt) -> Option<PipelineItemV
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let stage = project_stage_for_view(&stage_str, &story_id, merged_at, resume_to.as_deref())?;
|
||||
let stage =
|
||||
project_stage_for_view(&stage_str, &story_id, merged_at_float, resume_to.as_deref())?;
|
||||
|
||||
Some(PipelineItemView {
|
||||
story_id,
|
||||
@@ -362,9 +376,7 @@ pub(super) fn extract_item_view(item: &PipelineItemCrdt) -> Option<PipelineItemV
|
||||
agent,
|
||||
retry_count,
|
||||
depends_on,
|
||||
claimed_by,
|
||||
claimed_at,
|
||||
merged_at,
|
||||
claim,
|
||||
qa_mode,
|
||||
item_type,
|
||||
epic,
|
||||
@@ -571,10 +583,10 @@ mod tests {
|
||||
let view = extract_item_view(&crdt.doc.items[0]).unwrap();
|
||||
assert_eq!(view.story_id, "40_story_view");
|
||||
assert!(matches!(view.stage, crate::pipeline_state::Stage::Qa));
|
||||
assert_eq!(view.name.as_deref(), Some("View Test"));
|
||||
assert_eq!(view.name, "View Test");
|
||||
assert_eq!(view.agent.as_deref(), Some("coder-1"));
|
||||
assert_eq!(view.retry_count, Some(2));
|
||||
assert_eq!(view.depends_on, Some(vec![10, 20]));
|
||||
assert_eq!(view.retry_count, 2u32);
|
||||
assert_eq!(view.depends_on, vec![10u32, 20u32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user