diff --git a/server/src/db/yaml_legacy.rs b/server/src/db/yaml_legacy.rs index a9588645..3fccfd89 100644 --- a/server/src/db/yaml_legacy.rs +++ b/server/src/db/yaml_legacy.rs @@ -12,6 +12,23 @@ use serde::Deserialize; use std::fs; use std::path::Path; +/// Identity wrapper that flags a yaml_legacy callsite blocked on adding a +/// CRDT register (story 929 residue). Every wrap is a grep-findable marker — +/// `grep -rn yaml_residue` enumerates every remaining gap — so it stays +/// visible in every code review. +/// +/// When the CRDT register lands and the caller is migrated, delete the wrap. +/// Once every wrap is gone, delete this function and `db::yaml_legacy` +/// entirely (929 stage 10). +/// +/// Filed sub-stories enumerate each gap: +/// - 932: `review_hold` flag (write-side in qa_tools, read-side in +/// auto_assign). +/// - 933: epic mechanism — `item_type` and `epic` link fields. +pub fn yaml_residue(v: T) -> T { + v +} + /// Front-matter fields used by the legacy `parse_front_matter` API. Mirrors /// the original `io::story_metadata::FrontMatter`. #[derive(Debug, Default, Deserialize)] diff --git a/server/src/http/mcp/qa_tools.rs b/server/src/http/mcp/qa_tools.rs index e69cd709..beec1fc0 100644 --- a/server/src/http/mcp/qa_tools.rs +++ b/server/src/http/mcp/qa_tools.rs @@ -54,12 +54,16 @@ pub(super) async fn tool_approve_qa(args: &Value, ctx: &AppContext) -> Result Result Result 0 - { + let rc = view.retry_count(); + if rc > 0 { front_matter.insert("retry_count".to_string(), json!(rc)); } - if let Some(mf) = &meta.merge_failure { - front_matter.insert("merge_failure".to_string(), json!(mf)); - } - if let Some(rh) = meta.review_hold - && rh - { - front_matter.insert("review_hold".to_string(), json!(rh)); - } - if let Some(deps) = &meta.depends_on - && !deps.is_empty() - { + let deps = view.depends_on(); + if !deps.is_empty() { front_matter.insert("depends_on".to_string(), json!(deps)); } - } - - // --- CRDT view fields (claimed_by, claimed_at, is_deleted) --- - // read_item uses the visible index, so is_deleted is always false here; - // we include it only when true (which cannot happen for stories that - // pass the read_typed / 2_current check above, but the code is present - // for completeness and future-proofing). - if let Some(view) = crate::crdt_state::read_item(story_id) { if let Some(cb) = view.claimed_by() && !cb.is_empty() { @@ -227,6 +209,22 @@ pub(super) async fn tool_status(args: &Value, ctx: &AppContext) -> Result = parse_ac_items(&contents) .into_iter() diff --git a/server/src/http/mcp/story_tools/epic.rs b/server/src/http/mcp/story_tools/epic.rs index 3843dcf0..a76b68fb 100644 --- a/server/src/http/mcp/story_tools/epic.rs +++ b/server/src/http/mcp/story_tools/epic.rs @@ -4,7 +4,10 @@ //! and refactors. They are not pipeline-driven but provide authoritative context //! injected into agent prompts for all member work items. -use crate::db::yaml_legacy::parse_front_matter; +// Epic mechanism (item_type, epic link) has no CRDT register yet — story 933. +// parse_front_matter calls here are wrapped in `yaml_residue` so they're +// grep-findable until 933 lands. +use crate::db::yaml_legacy::{parse_front_matter, yaml_residue}; use crate::http::context::AppContext; use crate::http::workflow::create_epic_file; use serde_json::{Value, json}; @@ -62,7 +65,7 @@ pub(crate) fn tool_list_epics(_ctx: &AppContext) -> Result { Some(c) => c, None => continue, }; - let meta = match parse_front_matter(&content) { + let meta = match yaml_residue(parse_front_matter(&content)) { Ok(m) => m, Err(_) => continue, }; @@ -113,7 +116,7 @@ pub(crate) fn tool_show_epic(args: &Value, _ctx: &AppContext) -> Result Result c, None => continue, }; - let member_meta = match parse_front_matter(&member_content) { + let member_meta = match yaml_residue(parse_front_matter(&member_content)) { Ok(m) => m, Err(_) => continue, };