feat(933): add item_type + epic CRDT registers + migrate epic mechanism
Replaces the YAML-only `type: epic` / `epic: <id>` front-matter fields with typed CRDT registers on PipelineItemCrdt. The epic-mechanism MCP tools (`tool_list_epics`, `tool_show_epic`), the epic-context injection in agent spawn, and the type-classifier helpers (`item_type_from_id`, `is_bug_item`, `is_refactor_item`) now all read from the CRDT. Schema: - PipelineItemCrdt: `item_type: LwwRegisterCrdt<String>` and `epic: LwwRegisterCrdt<String>` registers. - WorkItem: typed `item_type()` and `epic()` accessors returning `Option<&str>`. - crdt_state::set_item_type(story_id, Option<&str>) and crdt_state::set_epic(story_id, Option<&str>) typed setters. Write paths populate the new registers: - create_story_file / create_bug_file / create_spike_file / create_refactor_file / create_epic_file — each calls set_item_type after write_story_content. - tool_update_story intercepts `epic` and `type` fields and routes them to the typed setters (same pattern as qa / depends_on). Read paths migrated off yaml_legacy: - http/mcp/story_tools/epic.rs: tool_list_epics + tool_show_epic. - agents/lifecycle.rs::item_type_from_id (numeric-only IDs). - agents/pool/start/spawn.rs epic-context injection. - http/workflow/bug_ops/bug.rs::is_bug_item, refactor.rs::is_refactor_item. - http/workflow/pipeline.rs::load_pipeline_state — review_hold/qa/epic_id all come from the CRDT now; only merge_failure is still YAML (sweep in 929 stage 10). All `yaml_residue(...)` wraps for item_type / epic are removed; the remaining residue marker doc no longer references 933. cargo fmt --check, clippy --all-targets -- -D warnings, and the 2857-test suite all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,49 @@ pub fn set_depends_on(story_id: &str, deps: &[u32]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Set the `item_type` CRDT register for a pipeline item (sub-story 933).
|
||||
///
|
||||
/// `Some(t)` writes the type string (e.g. `"story"`, `"epic"`, `"bug"`).
|
||||
/// `None` clears the register to an empty string, which means "use the
|
||||
/// id-prefix heuristic" (see `item_type_from_id`).
|
||||
///
|
||||
/// Returns `true` if the item was found and the op was applied, `false` otherwise.
|
||||
pub fn set_item_type(story_id: &str, item_type: Option<&str>) -> bool {
|
||||
let Some(state_mutex) = get_crdt() else {
|
||||
return false;
|
||||
};
|
||||
let Ok(mut state) = state_mutex.lock() else {
|
||||
return false;
|
||||
};
|
||||
let Some(&idx) = state.index.get(story_id) else {
|
||||
return false;
|
||||
};
|
||||
let value = item_type.unwrap_or("").to_string();
|
||||
apply_and_persist(&mut state, |s| s.crdt.doc.items[idx].item_type.set(value));
|
||||
true
|
||||
}
|
||||
|
||||
/// Set the `epic` CRDT register for a pipeline item (sub-story 933).
|
||||
///
|
||||
/// `Some(epic_id)` links the item to its parent epic.
|
||||
/// `None` clears the register to an empty string (no epic membership).
|
||||
///
|
||||
/// Returns `true` if the item was found and the op was applied, `false` otherwise.
|
||||
pub fn set_epic(story_id: &str, epic_id: Option<&str>) -> bool {
|
||||
let Some(state_mutex) = get_crdt() else {
|
||||
return false;
|
||||
};
|
||||
let Ok(mut state) = state_mutex.lock() else {
|
||||
return false;
|
||||
};
|
||||
let Some(&idx) = state.index.get(story_id) else {
|
||||
return false;
|
||||
};
|
||||
let value = epic_id.unwrap_or("").to_string();
|
||||
apply_and_persist(&mut state, |s| s.crdt.doc.items[idx].epic.set(value));
|
||||
true
|
||||
}
|
||||
|
||||
/// Set the `review_hold` CRDT flag for a pipeline item (sub-story 932).
|
||||
///
|
||||
/// `true` marks the item as held for human review at a pipeline-stage boundary;
|
||||
@@ -250,6 +293,8 @@ pub fn write_item(
|
||||
"qa_mode": "",
|
||||
"mergemaster_attempted": false,
|
||||
"review_hold": false,
|
||||
"item_type": "",
|
||||
"epic": "",
|
||||
})
|
||||
.into();
|
||||
|
||||
@@ -278,6 +323,8 @@ pub fn write_item(
|
||||
item.qa_mode.advance_seq(floor);
|
||||
item.mergemaster_attempted.advance_seq(floor);
|
||||
item.review_hold.advance_seq(floor);
|
||||
item.item_type.advance_seq(floor);
|
||||
item.epic.advance_seq(floor);
|
||||
}
|
||||
|
||||
// Broadcast a CrdtEvent for the new item.
|
||||
|
||||
Reference in New Issue
Block a user