feat(932): add review_hold CRDT register + migrate callers off yaml_legacy
review_hold is now a typed bool register on PipelineItemCrdt alongside blocked / mergemaster_attempted. Exposed via the typed setter `crdt_state::set_review_hold(story_id, value)` and the `WorkItem::review_hold()` accessor. Replaces the legacy `review_hold: true` YAML front-matter field. Migrated callers: - http/mcp/qa_tools.rs::tool_approve_qa — clear via set_review_hold(false) - agents/lifecycle.rs::reject_story_from_qa — clear via set_review_hold(false) - agents/pool/pipeline/advance/helpers.rs::write_review_hold_to_store — set via set_review_hold(true), no more content rewrite - agents/pool/auto_assign/reconcile.rs (two callsites) — set via set_review_hold(true) instead of FS YAML write - agents/pool/auto_assign/story_checks.rs::has_review_hold — reads the typed register instead of conflating with Stage::Frozen (real bug fix: the legacy implementation returned `stage.is_frozen()`, which made the auto-assigner treat *every* held-for-review item as frozen even when it wasn't actually parked at the freeze stage). Dead yaml_legacy helpers removed: - write_review_hold(path), write_review_hold_in_content(content) - clear_front_matter_field(path) — last caller was the qa_tools wrap The yaml_residue marker doc now only mentions 933; the 932 line is gone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -212,27 +212,36 @@ pub fn move_story_to_qa(story_id: &str) -> Result<(), String> {
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Move a story from `work/3_qa/` back to `work/2_current/`, clearing `review_hold` and writing notes.
|
||||
/// Move a story from `work/3_qa/` back to `work/2_current/`, clearing
|
||||
/// `review_hold` (story 932: CRDT register) and appending rejection notes.
|
||||
pub fn reject_story_from_qa(story_id: &str, notes: &str) -> Result<(), String> {
|
||||
let notes_owned = notes.to_string();
|
||||
let transform: Box<dyn Fn(&str) -> String> = Box::new(move |content: &str| {
|
||||
let mut result = clear_front_matter_field_in_content(content, "review_hold");
|
||||
if !notes_owned.is_empty() {
|
||||
result =
|
||||
crate::db::yaml_legacy::write_rejection_notes_to_content(&result, ¬es_owned);
|
||||
}
|
||||
result
|
||||
});
|
||||
crate::crdt_state::set_review_hold(story_id, false);
|
||||
|
||||
apply_transition(
|
||||
story_id,
|
||||
PipelineEvent::GatesFailed {
|
||||
reason: notes.to_string(),
|
||||
},
|
||||
Some(&*transform),
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
if notes.is_empty() {
|
||||
apply_transition(
|
||||
story_id,
|
||||
PipelineEvent::GatesFailed {
|
||||
reason: notes.to_string(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
} else {
|
||||
let notes_owned = notes.to_string();
|
||||
let transform = move |content: &str| -> String {
|
||||
crate::db::yaml_legacy::write_rejection_notes_to_content(content, ¬es_owned)
|
||||
};
|
||||
apply_transition(
|
||||
story_id,
|
||||
PipelineEvent::GatesFailed {
|
||||
reason: notes.to_string(),
|
||||
},
|
||||
Some(&transform),
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Transition a story to the `Blocked` stage via the state machine.
|
||||
|
||||
Reference in New Issue
Block a user