huskies: merge 490_story_crdt_state_layer_backed_by_sqlite
CRDT state layer backed by SQLite for pipeline state. Integrates the BFT JSON CRDT crate with SQLite persistence via sqlx. Ops are persisted and replayed on startup. Node identity via Ed25519 keypair. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+25
-17
@@ -87,17 +87,13 @@ pub async fn init(db_path: &Path) -> Result<(), sqlx::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Shadow-write a pipeline item move to SQLite.
|
||||
/// Write a pipeline item state to both the CRDT layer and the legacy SQLite
|
||||
/// shadow table.
|
||||
///
|
||||
/// Reads front matter from `file_path` (the post-move location) to extract
|
||||
/// metadata. The write is fire-and-forget — errors are logged but never
|
||||
/// propagate to the caller. If the database has not been initialised this is a
|
||||
/// complete no-op.
|
||||
/// metadata. The CRDT layer is the primary write path; the legacy shadow
|
||||
/// table is kept for backwards compatibility. Both writes are fire-and-forget.
|
||||
pub fn shadow_write(story_id: &str, stage: &str, file_path: &Path) {
|
||||
let Some(db) = PIPELINE_DB.get() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (name, agent, retry_count, blocked, depends_on) =
|
||||
match std::fs::read_to_string(file_path) {
|
||||
Ok(contents) => match parse_front_matter(&contents) {
|
||||
@@ -113,18 +109,30 @@ pub fn shadow_write(story_id: &str, stage: &str, file_path: &Path) {
|
||||
Err(_) => (None, None, None, None, None),
|
||||
};
|
||||
|
||||
let msg = PipelineWriteMsg {
|
||||
story_id: story_id.to_string(),
|
||||
stage: stage.to_string(),
|
||||
name,
|
||||
agent,
|
||||
// Primary: write through CRDT ops (persisted to SQLite crdt_ops table).
|
||||
crate::crdt_state::write_item(
|
||||
story_id,
|
||||
stage,
|
||||
name.as_deref(),
|
||||
agent.as_deref(),
|
||||
retry_count,
|
||||
blocked,
|
||||
depends_on,
|
||||
};
|
||||
depends_on.as_deref(),
|
||||
);
|
||||
|
||||
// Ignore send errors: the background task may have exited (e.g. in tests).
|
||||
let _ = db.tx.send(msg);
|
||||
// Legacy: fire-and-forget to the pipeline_items shadow table.
|
||||
if let Some(db) = PIPELINE_DB.get() {
|
||||
let msg = PipelineWriteMsg {
|
||||
story_id: story_id.to_string(),
|
||||
stage: stage.to_string(),
|
||||
name,
|
||||
agent,
|
||||
retry_count,
|
||||
blocked,
|
||||
depends_on,
|
||||
};
|
||||
let _ = db.tx.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user