huskies: merge 1096 bug Shadow drift: set_agent writes CRDT agent register without updating pipeline_items.agent
This commit is contained in:
@@ -183,6 +183,7 @@ pub fn set_agent(story_id: &str, agent: Option<crate::config::AgentName>) -> boo
|
|||||||
let Some(state_mutex) = get_crdt() else {
|
let Some(state_mutex) = get_crdt() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
{
|
||||||
let Ok(mut state) = state_mutex.lock() else {
|
let Ok(mut state) = state_mutex.lock() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -193,6 +194,10 @@ pub fn set_agent(story_id: &str, agent: Option<crate::config::AgentName>) -> boo
|
|||||||
apply_and_persist(&mut state, |s| {
|
apply_and_persist(&mut state, |s| {
|
||||||
s.crdt.doc.items[idx].agent.set(value.clone())
|
s.crdt.doc.items[idx].agent.set(value.clone())
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
// Sync the updated agent to the SQLite shadow table. Must be called after
|
||||||
|
// releasing the CRDT mutex so read_item can re-acquire it without deadlock.
|
||||||
|
crate::db::ops::sync_item_agent(story_id);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,43 @@ pub fn move_item_stage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shadow-write the updated agent field for an existing pipeline item.
|
||||||
|
///
|
||||||
|
/// Called by [`crate::crdt_state::set_agent`] after the CRDT register is updated
|
||||||
|
/// so `pipeline_items.agent` stays in sync. Reads the full current metadata from
|
||||||
|
/// the CRDT (stage, name, depends_on, retry_count) to avoid overwriting other
|
||||||
|
/// columns with stale values — only the `agent` column carries the new data.
|
||||||
|
pub fn sync_item_agent(story_id: &str) {
|
||||||
|
let Some(db) = PIPELINE_DB.get() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(view) = crate::crdt_state::read_item(story_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let stage = view.stage().dir_name().to_string();
|
||||||
|
let name = Some(view.name().to_string());
|
||||||
|
let agent = view.agent().map(|a| a.as_str().to_string());
|
||||||
|
let depends_on = {
|
||||||
|
let d = view.depends_on();
|
||||||
|
if d.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
serde_json::to_string(d).ok()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let retry_count = Some(i64::from(view.retry_count()));
|
||||||
|
let msg = PipelineWriteMsg {
|
||||||
|
story_id: story_id.to_string(),
|
||||||
|
stage,
|
||||||
|
name,
|
||||||
|
agent,
|
||||||
|
retry_count,
|
||||||
|
depends_on,
|
||||||
|
content: None,
|
||||||
|
};
|
||||||
|
let _ = db.tx.send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
/// Delete a story from the shadow table (fire-and-forget).
|
/// Delete a story from the shadow table (fire-and-forget).
|
||||||
pub fn delete_item(story_id: &str) {
|
pub fn delete_item(story_id: &str) {
|
||||||
delete_content(ContentKey::Story(story_id));
|
delete_content(ContentKey::Story(story_id));
|
||||||
|
|||||||
Reference in New Issue
Block a user