huskies: merge 946

This commit is contained in:
dave
2026-05-13 07:54:50 +00:00
parent 4a0fbcaa95
commit a7840ea4b0
49 changed files with 378 additions and 314 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
//!
//! Story 865 stripped YAML front matter from the content store; this module
//! no longer parses or writes YAML. What remains:
//! - `types` — `QaMode` enum.
//! - `types` — `QaMode` and `ItemType` enums.
//! - `parser` — `parse_unchecked_todos`, `resolve_qa_mode`, `is_story_frozen_in_store`.
//! - `deps` — dependency satisfaction checks (CRDT-backed).
@@ -11,4 +11,4 @@ mod parser;
mod types;
pub use parser::{is_story_frozen_in_store, parse_unchecked_todos, resolve_qa_mode};
pub use types::QaMode;
pub use types::{ItemType, QaMode};
+1 -3
View File
@@ -23,9 +23,7 @@ pub fn parse_unchecked_todos(contents: &str) -> Vec<String> {
/// 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)
.and_then(|view| view.qa_mode())
.unwrap_or(default)
}
+47 -2
View File
@@ -1,4 +1,4 @@
//! Core data types for story metadata.
//! Core data types for story metadata: [`QaMode`] and [`ItemType`] enums.
/// QA mode for a story: determines how the pipeline handles post-coder review.
///
@@ -6,7 +6,7 @@
/// If gates pass, advance straight to merge.
/// - `Agent` — spin up a QA agent (Claude session) to review code and run gates.
/// - `Human` — hold in QA for human approval after server gates pass.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum QaMode {
Server,
Agent,
@@ -39,3 +39,48 @@ impl std::fmt::Display for QaMode {
f.write_str(self.as_str())
}
}
/// The type of a pipeline work item.
///
/// Stored as a typed register in the CRDT (`"story"`, `"bug"`, `"spike"`,
/// `"refactor"`, `"epic"`). `None` in the view means "infer from the
/// story_id slug prefix".
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ItemType {
Story,
Bug,
Spike,
Refactor,
Epic,
}
impl ItemType {
/// Parse a string into an `ItemType`. Returns `None` for unrecognised values.
pub fn from_str(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"story" => Some(Self::Story),
"bug" => Some(Self::Bug),
"spike" => Some(Self::Spike),
"refactor" => Some(Self::Refactor),
"epic" => Some(Self::Epic),
_ => None,
}
}
/// Return the lowercase string representation of this item type.
pub fn as_str(&self) -> &'static str {
match self {
Self::Story => "story",
Self::Bug => "bug",
Self::Spike => "spike",
Self::Refactor => "refactor",
Self::Epic => "epic",
}
}
}
impl std::fmt::Display for ItemType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}