wip(929): stage 10 sweep — production callsites move to CRDT, yaml_legacy shrinks
After 932 (review_hold register) and 933 (item_type + epic registers), the
remaining production yaml_legacy callers all had typed CRDT equivalents.
Migrated:
- agents/lifecycle.rs:
- transition_to_merge_failure writes to MergeJob.error CRDT entry instead
of YAML body. The legacy `merge_failure: "..."` front-matter write is gone.
- reject_story_from_qa inlines the QA-rejection notes append; no longer
needs yaml_legacy::write_rejection_notes_to_content.
- fields_to_clear_transform helper deleted along with all five callers —
blocked/retry_count/merge_failure are typed CRDT fields now, so clearing
the equivalent YAML keys is redundant.
- http/workflow/pipeline.rs:
- load_pipeline_state reads merge_failure from MergeJob.error (mirrors
status_tools.rs).
- validate_story_dirs checks the typed CRDT `name` register instead of
parsing YAML front matter.
- http/mcp/status_tools.rs: review_hold reads the typed CRDT register
(yaml_residue wrap was the last one in this file).
- http/mcp/story_tools/criteria.rs: story_name reads from CRDT.
- service/agents/mod.rs::get_work_item_content: name/agent come from CRDT.
- service/notifications/io/mod.rs::read_story_name: same.
- http/workflow/bug_ops/{bug,refactor}.rs: name-fallback paths drop YAML
parsing in favour of the CRDT-derived item.name.
Dead helpers removed from db/yaml_legacy.rs:
yaml_residue, write_merge_failure_in_content, write_rejection_notes_to_content,
clear_front_matter_field_in_content, write_review_hold_in_content,
clear_front_matter_field, write_review_hold (the last four shipped in 932).
Remaining surface: FrontMatter / StoryMetadata structs, parse_front_matter,
set_front_matter_field — kept for `coverage_baseline` writes via
test_results.rs and the generic update_story front_matter escape hatch.
Test fixtures rewritten to seed the CRDT register instead of relying on
YAML parsing during write_item_with_content:
- has_review_hold_returns_* tests
- item_type_from_id_uses_crdt_register_for_numeric_ids
- tool_list_epics_shows_member_rollup
- get_work_item_content (both copies — http/agents + service/agents)
- validate_story_dirs_missing_name_in_crdt
- server_side_merge_*_sets_merge_failure (assert MergeJob.error, not YAML)
cargo fmt --check, clippy --all-targets -- -D warnings, and the
2856-test suite all pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,21 +10,6 @@
|
||||
use crate::io::story_metadata::QaMode;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// 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:
|
||||
/// - 933: epic mechanism — `item_type` and `epic` link fields.
|
||||
pub fn yaml_residue<T>(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)]
|
||||
@@ -155,47 +140,6 @@ pub(crate) fn set_front_matter_field(contents: &str, key: &str, value: &str) ->
|
||||
result
|
||||
}
|
||||
|
||||
/// Remove a `key: value` line from the YAML front matter of a markdown string.
|
||||
pub(crate) fn clear_front_matter_field_in_content(contents: &str, key: &str) -> String {
|
||||
let mut lines: Vec<String> = contents.lines().map(String::from).collect();
|
||||
if lines.is_empty() || lines[0].trim() != "---" {
|
||||
return contents.to_string();
|
||||
}
|
||||
let close_idx = match lines[1..].iter().position(|l| l.trim() == "---") {
|
||||
Some(i) => i + 1,
|
||||
None => return contents.to_string(),
|
||||
};
|
||||
let key_prefix = format!("{key}:");
|
||||
if let Some(idx) = lines[1..close_idx]
|
||||
.iter()
|
||||
.position(|l| l.trim_start().starts_with(&key_prefix))
|
||||
.map(|i| i + 1)
|
||||
{
|
||||
lines.remove(idx);
|
||||
} else {
|
||||
return contents.to_string();
|
||||
}
|
||||
let mut result = lines.join("\n");
|
||||
if contents.ends_with('\n') {
|
||||
result.push('\n');
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Append rejection notes to a markdown body.
|
||||
pub(crate) fn write_rejection_notes_to_content(contents: &str, notes: &str) -> String {
|
||||
format!("{contents}\n\n## QA Rejection Notes\n\n{notes}\n")
|
||||
}
|
||||
|
||||
/// Write or update `merge_failure` in story content.
|
||||
pub(crate) fn write_merge_failure_in_content(contents: &str, reason: &str) -> String {
|
||||
let escaped = reason
|
||||
.replace('"', "\\\"")
|
||||
.replace('\n', " ")
|
||||
.replace('\r', "");
|
||||
set_front_matter_field(contents, "merge_failure", &format!("\"{escaped}\""))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -219,13 +163,4 @@ mod tests {
|
||||
let out = set_front_matter_field("---\nname: X\n---\n# B\n", "agent", "coder-1");
|
||||
assert!(out.contains("agent: coder-1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clear_front_matter_field_removes_key() {
|
||||
let out = clear_front_matter_field_in_content(
|
||||
"---\nname: X\nblocked: true\n---\n# B\n",
|
||||
"blocked",
|
||||
);
|
||||
assert!(!out.contains("blocked"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user