//! Pure-content helpers and CRDT-backed metadata lookups. //! //! Story 865 stripped YAML front matter from stored content and the codebase //! at large; the only remaining functions here read the CRDT or operate on //! the markdown body directly. use super::types::QaMode; /// Parse unchecked todo items (`- [ ] ...`) from a markdown string. pub fn parse_unchecked_todos(contents: &str) -> Vec { contents .lines() .filter_map(|line| { let trimmed = line.trim(); trimmed.strip_prefix("- [ ] ").map(|text| text.to_string()) }) .collect() } /// Resolve the effective QA mode for a story by ID via the CRDT. /// /// Returns `default` when the story has no entry or its `qa_mode` register is /// unset. Spikes are **not** handled here — callers override to `Human` for /// spikes themselves. pub fn resolve_qa_mode(story_id: &str, default: QaMode) -> QaMode { crate::crdt_state::read_item(story_id) .and_then(|view| view.qa_mode().map(str::to_string)) .as_deref() .and_then(QaMode::from_str) .unwrap_or(default) } /// Return `true` if the story is in the `Frozen` pipeline stage. /// /// Checks the typed CRDT stage via `read_typed`. Used by the pipeline advance /// code to suppress stage transitions for frozen stories. pub fn is_story_frozen_in_store(story_id: &str) -> bool { crate::pipeline_state::read_typed(story_id) .ok() .flatten() .map(|item| item.stage.is_frozen()) .unwrap_or(false) } #[cfg(test)] mod tests { use super::*; #[test] fn parse_unchecked_todos_mixed() { let input = "## AC\n- [ ] First thing\n- [x] Done thing\n- [ ] Second thing\n"; assert_eq!( parse_unchecked_todos(input), vec!["First thing", "Second thing"] ); } #[test] fn parse_unchecked_todos_all_checked() { let input = "- [x] Done\n- [x] Also done\n"; assert!(parse_unchecked_todos(input).is_empty()); } #[test] fn parse_unchecked_todos_no_checkboxes() { let input = "# Story\nSome text\n- A bullet\n"; assert!(parse_unchecked_todos(input).is_empty()); } #[test] fn parse_unchecked_todos_leading_whitespace() { let input = " - [ ] Indented item\n"; assert_eq!(parse_unchecked_todos(input), vec!["Indented item"]); } #[test] fn resolve_qa_mode_falls_back_to_default_when_crdt_empty() { crate::crdt_state::init_for_test(); assert_eq!( resolve_qa_mode("9999_no_such_story", QaMode::Server), QaMode::Server ); } }