Skip to content

feat(loop): hot-file overlap guard + review-queue WIP limit#10

Merged
mabry1985 merged 1 commit into
mainfrom
feat/spawn-gates
Jun 13, 2026
Merged

feat(loop): hot-file overlap guard + review-queue WIP limit#10
mabry1985 merged 1 commit into
mainfrom
feat/spawn-gates

Conversation

@mabry1985

Copy link
Copy Markdown
Member

What

The first P1 concurrency-correctness port — directly hardens the max_concurrent>1 parallel drives from #6. Two back-pressure gates in _spawn_ready:

  • Hot-file guard — skip a ready candidate whose files_to_modify overlap an in-flight build's files. Two parallel coders editing the same file are a guaranteed merge conflict. _spawn_ready now peeks ready_queue() (priority order) and claims a specific non-conflicting feature via the new store.claim(fid) instead of always taking the top; each drive's files are tracked in self._inflight_files and released by its done-callback (so a deferred candidate can claim next).
  • Review-queue WIP limit (max_pending_reviews, default 5) — pause claiming new work while that many PRs already await review, so the loop can't pile up PRs faster than they merge (flooding CI / reviewers). 0 = unlimited.

store.claim(fid) atomically claims a chosen ready feature (vs claim_next_ready's top-of-queue), returning None if it changed state or lost the br --claim race.

Tests

+6 (104 total), all green: store.claim (specific / not-ready / claim-race); _spawn_ready caps at max_concurrent, defers a file-conflicting candidate, respects the review WIP limit, and releases files when a drive finishes. ruff clean.

P1 batch

  • ✅ hot-file guard + review WIP (this)
  • ⏳ periodic health sweep
  • ⏳ foundation merge-gate (review-vs-done)

🤖 Generated with Claude Code

Now that max_concurrent>1 runs features in parallel, two new back-pressure gates in
_spawn_ready keep concurrency correct:

- Hot-file guard: skip a ready candidate whose files_to_modify overlap an in-flight
  build's files — two parallel coders editing the same file are a guaranteed merge
  conflict. _spawn_ready now peeks the ready_queue (priority order) and claims a
  specific non-conflicting feature via the new store.claim(fid) instead of always
  taking the top; the files each drive holds are tracked in self._inflight_files and
  released by the drive's done-callback (so a deferred candidate can claim next).
- Review-queue WIP limit (max_pending_reviews, default 5): pause claiming new work
  while that many PRs already await review, so the loop can't pile up PRs faster than
  they merge (flooding CI / reviewers). 0 = unlimited.

store.claim(fid) atomically claims a chosen ready feature (vs claim_next_ready's
top-of-queue), returning None if it changed state or lost the `br --claim` race.

First of the P1 concurrency-correctness ports.

Tests: +6 (104 total) — store.claim (specific / not-ready / claim-race); _spawn_ready
caps at max_concurrent, defers a file-conflicting candidate, respects the review WIP
limit, and releases files when a drive finishes.

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 cd0577a into main Jun 13, 2026
1 check passed
@mabry1985
mabry1985 deleted the feat/spawn-gates branch June 13, 2026 06:19

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #10 | feat(loop): hot-file overlap guard + review-queue WIP limit

VERDICT: WARN ⏳ (CI queued — non-terminal)


CI Status

  • test: queued

Diff Review

  • loop.py: _spawn_ready rewritten with hot-file guard (skip file-overlapping candidates via busy set + store.claim(fid)) and review-queue WIP limit (max_pending_reviews, default 5)
  • store.py: new claim(fid) — atomic specific-feature claim via br --claim, returns None on race/state change
  • protoagent.plugin.yaml: config docs for both new gates
  • tests/test_loop.py: _ClaimStore refactored to ready_queue()/claim()/list_features() API; new helpers _ready() and _hold_drives() for test ergonomics

Observations

  • LOW: busy set computed once per _spawn_ready call; drives finishing mid-iteration don't update it until next call — conservative but safe (may defer a candidate unnecessarily, never allows a conflict)
  • GAP: ready_queue() and list_features() used in _spawn_ready but not visible in the store.py diff — unverified they exist on the production BoardStore. Tests mock via _ClaimStore so wouldn't catch a missing method. Likely pre-existing but worth confirming.
  • GAP: clawpatch structural review skipped — repo not in project registry. Cross-file analysis (call chain from _spawn_ready → store → br CLI) couldn't run.
  • Clean: no unresolved CodeRabbit threads, tests claim +6 all green, ruff clean

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jun 13, 2026

Copy link
Copy Markdown

Submitted COMMENT review on protoLabsAI/projectBoard-plugin#10.

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