Commit 050d496
feat(orchestrator): startup worktree sweep for SIGKILL residue Refs #1570 (Gitea) (#875)
Layer 2 of the worktree lifecycle defence in depth from epic
terraphim/terraphim-ai#1567. Between Layer 1 (WorktreeGuard::Drop
on the happy/cancelled path) and Layer 3 (root-privileged
ExecStartPre), this sweep reconciles residue left behind when the
previous orchestrator process died via SIGKILL, OOM, or a
panic-across-runtime where Drop never ran.
Changes
-------
* scope.rs:
- New `pub fn WorktreeManager::sweep_stale(&self, extra_roots:
&[PathBuf]) -> SweepReport`. Synchronous on purpose so it can
run inline in `AgentOrchestrator::new` before any tick thread
is spawned.
- Walks `worktree_base` for `WORKTREE_REVIEW_PREFIX`-prefixed
children, walks every direct child of each `extra_roots` entry
(no prefix filter -- the per-agent root convention has no
prefix), tries `git worktree remove --force` and falls back to
`std::fs::remove_dir_all`. EACCES/EPERM increments
`root_owned_skipped` rather than `failed_count` (Layer 3
territory). Then runs `git worktree prune --verbose` and emits
a single structured `info!` line with every report field plus
a synthetic `backlog_count = swept_count + root_owned_skipped`
for Quickwit alerting.
- New `pub struct SweepReport` carrying `swept_count`,
`failed_count`, `root_owned_skipped`, `prune_succeeded`,
`duration_ms`.
- Seven new unit tests covering empty/missing base, review
prefix removal, non-review preservation, prune execution,
extra-roots no-prefix-filter, and the Linux-only root-owned
contract test (runtime gated by `getuid() == 0`; documents the
contract even when it cannot run).
* compound.rs:
- New `pub fn CompoundReviewWorkflow::worktree_manager(&self)
-> &WorktreeManager` trivial accessor for the field needed by
the Layer 2 wiring.
* lib.rs:
- `AgentOrchestrator::new` now calls
`compound_workflow.worktree_manager().sweep_stale(&[
PathBuf::from("/tmp/adf-worktrees") ])` immediately after the
compound workflow is constructed, before `Ok(Self { ... })`.
The /tmp/adf-worktrees literal mirrors lib.rs:5393 (the
per-agent worktree root from `create_agent_worktree`).
- Logs a `warn!` when the residue backlog at startup exceeds 10,
which the research doc flagged as the prior-crash-storm
threshold.
* tests/sweep_on_startup_test.rs (NEW):
- Three integration tests around an isolated TempDir git repo
via `scope::test_support::setup_git_repo`. Verifies that
`AgentOrchestrator::new` does sweep `review-*` residue,
preserves non-review siblings, and that extra_roots children
are removed regardless of prefix.
* Cargo.toml:
- Declares the new integration test with
`required-features = ["test-helpers"]`, mirroring the Layer 1
`compound_cancellation_test` entry.
Deviations from the brief
-------------------------
1. Struct name: the brief says `Orchestrator::new`; the actual
symbol is `AgentOrchestrator::new` (lib.rs:661). Insertion site
is between `compound_workflow` construction at :687 and the
`Ok(Self { ... })` block at :786.
2. `#[cfg(not(test))]` gate on the sweep call. The in-lib
`test_config()` (lib.rs:7926) points `repo_path` at the live
terraphim-ai checkout. Without the gate, the sweep's
`git worktree prune --verbose` ran against that real repo and
raced against `test_orchestrator_compound_review_manual`'s
concurrent `git worktree add` on the same shared
`.git/worktrees/` admin registry. Production wiring is fully
exercised by `tests/sweep_on_startup_test.rs` (a separate
crate, so `cfg(test)` is not set on the lib's own code path
when it links the integration test). The gate is documented
inline with a pointer to the integration test.
3. SweepReport is placed at module scope in scope.rs (as the
brief preferred), not wrapped in `WorktreeManager`.
4. The Linux/root-only contract test is included as the brief
requested. It uses a raw `extern "C" getuid()` FFI to avoid
pulling in `nix` or `libc` solely for a single gated test.
Verification
------------
* `cargo test -p terraphim_orchestrator --features test-helpers
--test sweep_on_startup_test -- --nocapture`: 3 passed.
* `cargo test -p terraphim_orchestrator --features test-helpers`:
691 lib tests + all integration tests pass, including Layer 1
`compound_cancellation_test`.
* `cargo clippy -p terraphim_orchestrator --lib --tests
--features test-helpers -- -D warnings`: clean.
* `cargo fmt`: clean.
Branched from task/1569-worktree-guard (Layer 1) which provides
the `WORKTREE_REVIEW_PREFIX` constant referenced by the sweep.
Co-authored-by: Alex <alex@example.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 95e2b15 commit 050d496
5 files changed
Lines changed: 702 additions & 0 deletions
File tree
- crates/terraphim_orchestrator
- src
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
104 | 113 | | |
105 | 114 | | |
106 | 115 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
250 | 250 | | |
251 | 251 | | |
252 | 252 | | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
253 | 265 | | |
254 | 266 | | |
255 | 267 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
693 | 693 | | |
694 | 694 | | |
695 | 695 | | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
696 | 735 | | |
697 | 736 | | |
698 | 737 | | |
| |||
0 commit comments