wip(929): stage 1 — migrate chat/commands/* off yaml_legacy
Each chat command that previously read parse_front_matter for story metadata (name, agent, depends_on, blocked, retry_count, merge_failure, qa_mode) now reads from the typed CRDT API: - WorkItem (via crdt_state::read_item) for pipeline-item registers. - MergeJobView (via crdt_state::read_merge_job) for the merge failure detail text, which has its own LWW-map CRDT entry. Files migrated: depends.rs, freeze.rs, move_story.rs, overview.rs, status/render.rs, triage.rs, unblock.rs, unreleased.rs. unblock.rs: also removes the legacy front-matter cleanup branch that fired when the typed Blocked→Coding transition failed. Post-929 there is no YAML on disk to clean; the fallback now just resets retry_count in the CRDT. triage.rs: drops the YAML-only `review_hold` and `coverage_baseline` fields from the dump. These have no CRDT register and were never load-bearing on the triage output; if needed later, add a CRDT register and surface it back. Tests: - The three status/render merge-failure rendering tests now seed a MergeJob CRDT entry via write_merge_job instead of writing YAML. - The unblock test that asserted YAML cleanup on disk is now an assertion on the CRDT registers (blocked=false, retry_count=0). Also re-seeded in `2_blocked` stage so the typed Blocked → Coding transition actually fires (not the fallback path). All 2855 tests pass; fmt clean; clippy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
//! and returns a confirmation.
|
||||
|
||||
use super::CommandContext;
|
||||
use crate::db::yaml_legacy::clear_front_matter_field_in_content;
|
||||
use std::path::Path;
|
||||
|
||||
/// Handle the `unblock` command.
|
||||
@@ -80,37 +79,14 @@ fn unblock_by_story_id(story_id: &str) -> String {
|
||||
// the CRDT.
|
||||
if let Err(e) = crate::agents::lifecycle::transition_to_unblocked(story_id) {
|
||||
// If the typed transition fails (e.g. a legacy Archived item with no
|
||||
// valid `Unblock` transition out of its current stage), fall back to
|
||||
// a direct CRDT/content cleanup. The legacy front-matter cleanup is
|
||||
// gated on content actually still containing YAML, so post-865
|
||||
// CRDT-only stories don't hit a parse error.
|
||||
// valid `Unblock` transition out of its current stage), at least
|
||||
// reset retry_count directly in the CRDT so the agent doesn't stay
|
||||
// tagged with a stale fail counter. Post-929 there's no FS shadow
|
||||
// to clean up alongside.
|
||||
crate::slog_warn!(
|
||||
"[unblock] State-machine transition failed for '{story_id}': {e}. \
|
||||
Falling back to direct CRDT cleanup."
|
||||
Falling back to direct CRDT retry_count reset."
|
||||
);
|
||||
|
||||
if let Some(content) = crate::db::read_content(story_id) {
|
||||
// Only run legacy front-matter cleanup if the stored content still
|
||||
// begins with a `---` YAML block. Post-865 content has been
|
||||
// stripped and would no-op here anyway.
|
||||
if content.trim_start().starts_with("---") {
|
||||
let mut updated = content;
|
||||
updated = clear_front_matter_field_in_content(&updated, "blocked");
|
||||
updated = clear_front_matter_field_in_content(&updated, "merge_failure");
|
||||
updated = clear_front_matter_field_in_content(&updated, "retry_count");
|
||||
crate::db::write_content(story_id, &updated);
|
||||
let stage = typed_item
|
||||
.as_ref()
|
||||
.map(|i| i.stage.dir_name().to_string())
|
||||
.unwrap_or_else(|| "2_current".to_string());
|
||||
crate::db::write_item_with_content(
|
||||
story_id,
|
||||
&stage,
|
||||
&updated,
|
||||
crate::db::ItemMeta::from_yaml(&updated),
|
||||
);
|
||||
}
|
||||
}
|
||||
crate::crdt_state::set_retry_count(story_id, 0);
|
||||
}
|
||||
|
||||
@@ -221,14 +197,15 @@ mod tests {
|
||||
// global content store.
|
||||
write_story_file(
|
||||
tmp.path(),
|
||||
"2_current",
|
||||
"2_blocked",
|
||||
"9903_story_stuck.md",
|
||||
"---\nname: Stuck Story\nblocked: true\nretry_count: 5\n---\n# Story\n",
|
||||
);
|
||||
// Seed the story in the CRDT with retry_count=5 so set_retry_count can reset it.
|
||||
// Seed the story in the CRDT in 2_blocked stage so the typed
|
||||
// Blocked → Coding transition fires and clears `blocked` properly.
|
||||
crate::crdt_state::write_item(
|
||||
"9903_story_stuck",
|
||||
"2_current",
|
||||
"2_blocked",
|
||||
Some("Stuck Story"),
|
||||
None,
|
||||
Some(5),
|
||||
@@ -249,25 +226,9 @@ mod tests {
|
||||
"should include story_id in response: {output}"
|
||||
);
|
||||
|
||||
// The unblock command writes back via the content store; blocked field should be gone.
|
||||
let contents = crate::db::read_content("9903_story_stuck")
|
||||
.or_else(|| {
|
||||
std::fs::read_to_string(
|
||||
tmp.path()
|
||||
.join(".huskies/work/2_current/9903_story_stuck.md"),
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.expect("story content should be readable after unblock");
|
||||
assert!(
|
||||
!contents.contains("blocked:"),
|
||||
"blocked field should be removed: {contents}"
|
||||
);
|
||||
// retry_count is now in the CRDT, not in front-matter.
|
||||
assert!(
|
||||
!contents.contains("retry_count:"),
|
||||
"retry_count should be cleared from front-matter after unblock: {contents}"
|
||||
);
|
||||
// Post-929: the CRDT is the sole source of truth; we no longer clean
|
||||
// YAML front matter from on-disk content. Verify the CRDT registers
|
||||
// were updated correctly.
|
||||
let item = crate::crdt_state::read_item("9903_story_stuck")
|
||||
.expect("story should be in CRDT after unblock");
|
||||
assert_eq!(
|
||||
@@ -275,6 +236,10 @@ mod tests {
|
||||
0,
|
||||
"retry_count should be reset to 0 in CRDT after unblock"
|
||||
);
|
||||
assert!(
|
||||
!item.blocked(),
|
||||
"blocked flag should be cleared in CRDT after unblock"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user