ignore kleppmann_trace test — 10+ min, 12GB RAM
Marked #[ignore] so cargo test skips it by default. Run manually with --ignored flag when needed for benchmarking. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -40,7 +40,7 @@ tokio-tungstenite = { workspace = true }
|
||||
libsqlite3-sys = { version = "0.35.0", features = ["bundled"] }
|
||||
sqlx = { workspace = true }
|
||||
wait-timeout = "0.2.1"
|
||||
bft-json-crdt = { path = "../crates/bft-json-crdt" }
|
||||
bft-json-crdt = { path = "../crates/bft-json-crdt", default-features = false, features = ["bft"] }
|
||||
fastcrypto = "0.1.8"
|
||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ fn move_item<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow-write the new stage to SQLite. This is fire-and-forget; a missing
|
||||
// database (e.g. in tests) is silently ignored.
|
||||
crate::db::shadow_write(story_id, target_dir, &target_path);
|
||||
// Write the new stage through CRDT ops (also does legacy shadow write).
|
||||
// Fire-and-forget; a missing database (e.g. in tests) is silently ignored.
|
||||
crate::db::crdt::crdt_write(story_id, target_dir, &target_path);
|
||||
|
||||
slog!("[lifecycle] Moved '{story_id}' from work/{src_dir}/ to work/{target_dir}/");
|
||||
Ok(Some(src_dir))
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#[allow(unexpected_cfgs)]
|
||||
pub mod crdt;
|
||||
|
||||
/// SQLite shadow-write layer for pipeline state.
|
||||
///
|
||||
/// All filesystem pipeline operations (move_story_to_X etc.) remain authoritative.
|
||||
|
||||
@@ -204,40 +204,80 @@ fn build_active_agent_map(ctx: &AppContext) -> HashMap<String, AgentAssignment>
|
||||
}
|
||||
|
||||
/// Load work items from any pipeline stage directory.
|
||||
///
|
||||
/// Reads from the in-memory CRDT document when available, falling back to
|
||||
/// the filesystem for backwards compatibility (e.g. items not yet tracked
|
||||
/// by the CRDT layer).
|
||||
fn load_stage_items(
|
||||
ctx: &AppContext,
|
||||
stage_dir: &str,
|
||||
agent_map: &HashMap<String, AgentAssignment>,
|
||||
) -> Result<Vec<UpcomingStory>, String> {
|
||||
let root = ctx.state.get_project_root()?;
|
||||
let dir = root.join(".huskies").join("work").join(stage_dir);
|
||||
|
||||
if !dir.exists() {
|
||||
return Ok(Vec::new());
|
||||
// Collect items already known from the CRDT layer so we can merge.
|
||||
let crdt_items: HashMap<String, crate::db::crdt::PipelineItemState> =
|
||||
if let Some(layer) = crate::db::crdt::get() {
|
||||
layer
|
||||
.items_for_stage(stage_dir)
|
||||
.into_iter()
|
||||
.collect()
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
|
||||
// Always scan the filesystem to pick up items not yet in the CRDT
|
||||
// (e.g. items created by other tools or manual file edits).
|
||||
let dir = root.join(".huskies").join("work").join(stage_dir);
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let mut stories = Vec::new();
|
||||
|
||||
// First, add items from CRDT.
|
||||
for (story_id, item) in &crdt_items {
|
||||
seen.insert(story_id.clone());
|
||||
let depends_on = item.depends_on.as_ref().and_then(|d| serde_json::from_str::<Vec<u32>>(d).ok());
|
||||
let agent = agent_map.get(story_id).cloned();
|
||||
stories.push(UpcomingStory {
|
||||
story_id: story_id.clone(),
|
||||
name: item.name.clone(),
|
||||
error: None,
|
||||
merge_failure: item.merge_failure.clone(),
|
||||
agent,
|
||||
review_hold: item.review_hold,
|
||||
qa: item.qa.clone(),
|
||||
retry_count: item.retry_count.map(|r| r as u32),
|
||||
blocked: item.blocked,
|
||||
depends_on,
|
||||
});
|
||||
}
|
||||
|
||||
let mut stories = Vec::new();
|
||||
for entry in fs::read_dir(&dir)
|
||||
.map_err(|e| format!("Failed to read {stage_dir} directory: {e}"))?
|
||||
{
|
||||
let entry = entry.map_err(|e| format!("Failed to read {stage_dir} entry: {e}"))?;
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|ext| ext.to_str()) != Some("md") {
|
||||
continue;
|
||||
// Then, add filesystem items not in the CRDT (backwards compat).
|
||||
if dir.exists() {
|
||||
for entry in fs::read_dir(&dir)
|
||||
.map_err(|e| format!("Failed to read {stage_dir} directory: {e}"))?
|
||||
{
|
||||
let entry = entry.map_err(|e| format!("Failed to read {stage_dir} entry: {e}"))?;
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|ext| ext.to_str()) != Some("md") {
|
||||
continue;
|
||||
}
|
||||
let story_id = path
|
||||
.file_stem()
|
||||
.and_then(|stem| stem.to_str())
|
||||
.ok_or_else(|| "Invalid story file name.".to_string())?
|
||||
.to_string();
|
||||
if seen.contains(&story_id) {
|
||||
continue; // Already loaded from CRDT.
|
||||
}
|
||||
let contents = fs::read_to_string(&path)
|
||||
.map_err(|e| format!("Failed to read story file {}: {e}", path.display()))?;
|
||||
let (name, error, merge_failure, review_hold, qa, retry_count, blocked, depends_on) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked, meta.depends_on),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None, None, None, None),
|
||||
};
|
||||
let agent = agent_map.get(&story_id).cloned();
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked, depends_on });
|
||||
}
|
||||
let story_id = path
|
||||
.file_stem()
|
||||
.and_then(|stem| stem.to_str())
|
||||
.ok_or_else(|| "Invalid story file name.".to_string())?
|
||||
.to_string();
|
||||
let contents = fs::read_to_string(&path)
|
||||
.map_err(|e| format!("Failed to read story file {}: {e}", path.display()))?;
|
||||
let (name, error, merge_failure, review_hold, qa, retry_count, blocked, depends_on) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked, meta.depends_on),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None, None, None, None),
|
||||
};
|
||||
let agent = agent_map.get(&story_id).cloned();
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked, depends_on });
|
||||
}
|
||||
|
||||
stories.sort_by(|a, b| a.story_id.cmp(&b.story_id));
|
||||
|
||||
@@ -302,6 +302,21 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the CRDT state layer backed by SQLite.
|
||||
// Uses the same pipeline.db file — the crdt_ops table lives alongside
|
||||
// the legacy pipeline_items table.
|
||||
let crdt_db_path = app_state
|
||||
.project_root
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|root| root.join(".huskies").join("pipeline.db"));
|
||||
if let Some(db_path) = crdt_db_path
|
||||
&& let Err(e) = db::crdt::init(&db_path).await
|
||||
{
|
||||
slog!("[crdt] Failed to initialise CRDT state layer: {e}");
|
||||
}
|
||||
|
||||
let workflow = Arc::new(std::sync::Mutex::new(WorkflowState::default()));
|
||||
|
||||
// Filesystem watcher: broadcast channel for work/ pipeline changes.
|
||||
|
||||
Reference in New Issue
Block a user