wip(929): stage 3 — migrate http/mcp/* off yaml_legacy + introduce yaml_residue marker

Three MCP files touched:

- status_tools.rs (story-status JSON dump): every field with a CRDT
  equivalent now reads from WorkItem (name, agent, blocked, qa_mode,
  retry_count, depends_on, claimed_by, claimed_at) or MergeJob.error
  (merge_failure detail). One field — review_hold — has no CRDT register
  yet (sub-story 932) and is wrapped in `yaml_residue(parse_front_matter(...))`
  so the gap is visible at every code-search.

- qa_tools.rs:
  • tool_approve_qa wraps the legacy `clear_front_matter_field("review_hold")`
    write in `yaml_residue(...)` pending sub-story 932.
  • tool_reject_qa now reads the agent name from the CRDT WorkItem instead
    of parsing front matter on disk.

- story_tools/epic.rs: the entire epic feature (item_type, epic link)
  has no CRDT analog — sub-story 933. Every parse_front_matter call here
  is wrapped in `yaml_residue(...)`.

Also: new identity wrapper `db::yaml_legacy::yaml_residue<T>(v: T) -> T`
that marks a yaml_legacy callsite blocked on a CRDT-register gap. Pure
identity at runtime; the distinctive name makes the residue grep-findable
(`grep -rn yaml_residue`). Sub-stories 932 and 933 enumerate the gaps.

Filed:
- 932: Add CRDT register for review_hold
- 933: Add CRDT registers for the epic mechanism

All 2854 tests pass; fmt + clippy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Timmy
2026-05-12 18:54:32 +01:00
parent 9eb5116f7e
commit b8945654bf
4 changed files with 61 additions and 47 deletions
+7 -4
View File
@@ -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<String, String> {
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<String,
let content = crate::db::read_content(epic_id)
.ok_or_else(|| format!("Epic '{epic_id}' not found in content store"))?;
let meta = parse_front_matter(&content)
let meta = yaml_residue(parse_front_matter(&content))
.map_err(|e| format!("Failed to parse epic front matter: {e}"))?;
if meta.item_type.as_deref() != Some("epic") {
@@ -132,7 +135,7 @@ pub(crate) fn tool_show_epic(args: &Value, _ctx: &AppContext) -> Result<String,
Some(c) => 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,
};