Skip to content

feat(loop): periodic health sweep — self-heal stale drives + orphaned worktrees#11

Merged
mabry1985 merged 1 commit into
mainfrom
feat/health-sweep
Jun 13, 2026
Merged

feat(loop): periodic health sweep — self-heal stale drives + orphaned worktrees#11
mabry1985 merged 1 commit into
mainfrom
feat/health-sweep

Conversation

@mabry1985

Copy link
Copy Markdown
Member

What

The second P1 concurrency-correctness port. A long-running loop accumulates two kinds of cruft nothing reclaimed: features stuck in_progress after a drive died without finishing (holding a board slot forever), and feat-<id> worktrees left behind by a missed reap. A periodic sweep (health_sweep_interval_s, default 300s; 0 disables) self-heals both:

  • stale in_progress (not in self._inflight_files → no live drive) → reconciled the same way boot recovery does (adopt an open PR → in_review, else reset → ready). Boot recovery and the sweep now share _reconcile_orphan.
  • orphaned worktrees — a feat-<id> dir whose feature is gone or already done → reaped. (in_review keeps its worktree for a CI-fail re-dispatch; a live drive's worktree is left alone.)

worktree.list_feature_worktrees enumerates the feat-<id> dirs under worktrees_root.

Tests

+6 (110 total), all green: list_feature_worktrees (dirs only / absent dir); _sweep reconciles a driveless in_progress (and skips a driven one) and reaps done/missing worktrees (keeps in_review); _maybe_sweep rate-limit + disabled. ruff clean.

P1 batch

🤖 Generated with Claude Code

… worktrees

A long-running loop accumulates two kinds of cruft that nothing reclaimed: features
stuck in_progress after a drive died without finishing (holding a board slot), and
feat-<id> worktrees left behind by a missed reap. A periodic sweep
(health_sweep_interval_s, default 300s; 0 disables) now self-heals both:

- in_progress features with no live drive (not in self._inflight_files) → reconciled
  the same way boot recovery does (adopt an open PR → in_review, else reset → ready).
  Boot recovery and the sweep now share _reconcile_orphan.
- feat-<id> worktrees whose feature is gone or already done → reaped (in_review keeps
  its worktree for a CI-fail re-dispatch; a live drive's worktree is left alone).

worktree.list_feature_worktrees enumerates the feat-<id> dirs under worktrees_root.

Second of the P1 concurrency-correctness ports.

Tests: +6 (110 total) — list_feature_worktrees (dirs only, absent dir); _sweep
reconciles a driveless in_progress (skips a driven one) and reaps done/missing
worktrees (keeps in_review); _maybe_sweep rate-limit + disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@protoquinn

protoquinn Bot commented Jun 13, 2026

Copy link
Copy Markdown

👀 Quinn is reviewing — verdict (PASS / WARN / FAIL) + findings to follow.

@mabry1985
mabry1985 merged commit 8f09248 into main Jun 13, 2026
1 check passed
@mabry1985
mabry1985 deleted the feat/health-sweep branch June 13, 2026 06:24
mabry1985 added a commit that referenced this pull request Jun 13, 2026
…w) (#12)

By default a dependent waits for every blocks-dependency to MERGE (done) — `br ready`
excludes a feature with any open blocker, so this falls out for free and stays the
safe default (dep_gate: merge). The new opt-in dep_gate: review relaxes it: a
NON-foundation blocker releases its dependents once it reaches in_review (build on
code that's in review, not yet merged — more parallelism). Foundation features
(foundation=True) ALWAYS gate dependents on merge.

- store.ready_queue(relaxed=False): the relaxed branch adds dep-blocked ready
  features whose every still-open blocker is a non-foundation feature at in_review,
  resolved in Python from `br list` labels (board_state + foundation) + `br show`
  deps (`_open_blockers`), since `br ready` only knows "blocker closed".
- create_feature(foundation=…) + the `foundation` label + _project exposure; the
  board_create_feature tool + the decompose skill gain the flag (the skill already
  marked milestones foundation in frontmatter — now it's wired to the gate).
- loop: dep_gate config → relaxed_gate → ready_queue(relaxed=…).

Verified against br 0.1.23: `br list --json` carries labels; `br show` deps carry
status; `br ready` waits for blockers to close. Default behaviour is unchanged.

Completes the P1 concurrency-correctness batch (hot-file guard #10, health sweep #11,
this).

Tests: +6 (116 total) — _project foundation, create_feature labels foundation,
_open_blockers filtering, ready_queue(relaxed) releases only non-foundation in_review
blockers, dep_gate config, _spawn_ready passes the gate through.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant