Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/terraphim_orchestrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ name = "compound_cancellation_test"
path = "tests/compound_cancellation_test.rs"
required-features = ["test-helpers"]

# Layer 2 startup sweep integration test (epic #1567 / issue #1570).
# Same test-helpers gate as Layer 1 -- the test re-uses the shared
# `scope::test_support::setup_git_repo` fixture so the sweep never
# runs against the live repository.
[[test]]
name = "sweep_on_startup_test"
path = "tests/sweep_on_startup_test.rs"
required-features = ["test-helpers"]


[[bin]]
name = "adf"
Expand Down
12 changes: 12 additions & 0 deletions crates/terraphim_orchestrator/src/compound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,18 @@ impl CompoundReviewWorkflow {
Self::new(swarm_config)
}

/// Borrow the inner [`WorktreeManager`].
///
/// Layer 2 (epic #1567, issue #1570) calls
/// `worktree_manager().sweep_stale(...)` from
/// `AgentOrchestrator::new` to reconcile stale `review-*` residue
/// left behind by SIGKILL / OOM before any tick thread runs.
/// Production code outside the startup sweep should prefer the
/// higher-level workflow methods.
pub fn worktree_manager(&self) -> &WorktreeManager {
&self.worktree_manager
}

/// Run a full compound review cycle.
///
/// 1. Get changed files between git_ref and base_ref
Expand Down
39 changes: 39 additions & 0 deletions crates/terraphim_orchestrator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,45 @@ impl AgentOrchestrator {
let scheduler = TimeScheduler::new(&config.agents, Some(&config.compound_review.schedule))?;
let compound_workflow =
CompoundReviewWorkflow::from_compound_config(config.compound_review.clone());

// Layer 2 startup sweep (epic #1567, issue #1570).
//
// Reconcile any worktree residue left by a previous instance
// before we accept ticks. Synchronous: must finish before the
// tick thread is spawned in `run()` so a fresh review cycle
// never races against half-killed `review-*` directories.
//
// `extra_roots` mirrors the per-agent worktree convention
// from `lib.rs:5393`. If you change that literal there, change
// it here too.
//
// `cfg(not(test))` gate: the in-lib `test_config()` (see
// `lib.rs:7926`) points `repo_path` at the live terraphim-ai
// checkout. Without this gate, the sweep's
// `git worktree prune --verbose` races against
// `test_orchestrator_compound_review_manual`'s concurrent
// `git worktree add` on that shared real repo's
// `.git/worktrees/` admin registry. The production wiring is
// exercised end-to-end by `tests/sweep_on_startup_test.rs`,
// which builds an isolated `TempDir` repo and asserts the
// sweep DOES run from `AgentOrchestrator::new`. Do not remove
// this gate without first migrating the in-lib `test_config()`
// to a TempDir-based `repo_path`.
#[cfg(not(test))]
{
let sweep_report = compound_workflow
.worktree_manager()
.sweep_stale(&[PathBuf::from("/tmp/adf-worktrees")]);
if sweep_report.swept_count + sweep_report.root_owned_skipped > 10 {
warn!(
swept_count = sweep_report.swept_count,
root_owned_skipped = sweep_report.root_owned_skipped,
failed_count = sweep_report.failed_count,
"large worktree backlog at startup -- prior crash storm likely"
);
}
}

let handoff_buffer = HandoffBuffer::new(config.handoff_buffer_ttl_secs.unwrap_or(86400));
let handoff_ledger = HandoffLedger::new(config.working_dir.join("handoff-ledger.jsonl"));

Expand Down
Loading
Loading