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:
@@ -174,47 +174,29 @@ pub(super) async fn tool_status(args: &Value, ctx: &AppContext) -> Result<String
|
||||
let contents = crate::db::read_content(story_id)
|
||||
.ok_or_else(|| format!("Story '{story_id}' has no content in the content store."))?;
|
||||
|
||||
// --- Front matter ---
|
||||
// --- Metadata (story 929: CRDT-first, yaml_residue marks gaps) ---
|
||||
let mut front_matter = serde_json::Map::new();
|
||||
if let Ok(meta) = crate::db::yaml_legacy::parse_front_matter(&contents) {
|
||||
if let Some(name) = &meta.name {
|
||||
if let Some(view) = crate::crdt_state::read_item(story_id) {
|
||||
if let Some(name) = view.name() {
|
||||
front_matter.insert("name".to_string(), json!(name));
|
||||
}
|
||||
if let Some(agent) = &meta.agent {
|
||||
if let Some(agent) = view.agent() {
|
||||
front_matter.insert("agent".to_string(), json!(agent));
|
||||
}
|
||||
if let Some(true) = meta.blocked {
|
||||
if view.blocked() {
|
||||
front_matter.insert("blocked".to_string(), json!(true));
|
||||
}
|
||||
if let Some(qa) = &meta.qa {
|
||||
front_matter.insert("qa".to_string(), json!(qa.as_str()));
|
||||
if let Some(qa) = view.qa_mode() {
|
||||
front_matter.insert("qa".to_string(), json!(qa));
|
||||
}
|
||||
if let Some(rc) = meta.retry_count
|
||||
&& rc > 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<String
|
||||
}
|
||||
}
|
||||
|
||||
// Merge-failure detail lives on the MergeJob CRDT entry, not on WorkItem.
|
||||
if let Some(job) = crate::crdt_state::read_merge_job(story_id)
|
||||
&& let Some(mf) = job.error
|
||||
{
|
||||
front_matter.insert("merge_failure".to_string(), json!(mf));
|
||||
}
|
||||
|
||||
// review_hold has no CRDT register yet — see story 932. Wrap the
|
||||
// yaml_legacy read in `yaml_residue(...)` so it's grep-findable.
|
||||
if let Ok(meta) =
|
||||
crate::db::yaml_legacy::yaml_residue(crate::db::yaml_legacy::parse_front_matter(&contents))
|
||||
&& let Some(true) = meta.review_hold
|
||||
{
|
||||
front_matter.insert("review_hold".to_string(), json!(true));
|
||||
}
|
||||
|
||||
// --- AC checklist ---
|
||||
let ac_items: Vec<Value> = parse_ac_items(&contents)
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user