Skip to content

feat: Phase 4 parallel file-disjoint workers (#37)#57

Merged
caoergou merged 2 commits into
mainfrom
claude/issue-37-stsc4e
Jul 7, 2026
Merged

feat: Phase 4 parallel file-disjoint workers (#37)#57
caoergou merged 2 commits into
mainfrom
claude/issue-37-stsc4e

Conversation

@caoergou

@caoergou caoergou commented Jul 6, 2026

Copy link
Copy Markdown
Owner

The final phase of the #37 roadmap: run multiple specs concurrently, safely, by scheduling on file-disjointness rather than lock coordination — and only now that Phase 1 stall detection exists to bound the cost of missing progress. Builds on merged Phases 1–3.

File-disjoint scheduling (spec_queue.py)

Specs declare a ## Files scope. get_parallel_batch(specs_dir, N) greedily selects a set of ready specs whose scopes don't overlap (glob- and directory-prefix aware), up to N workers. A spec with no declared scope runs alone — correctness over parallelism. Ready specs are already dependency-independent, so scheduling only has to reason about file scope.

Shared verification gate (verification.py)

The deterministic gate — acceptance criteria + backpressure via subprocess, plus the tamper-guard hash — is extracted into one module that both the sequential engine and the parallel orchestrator call. There is exactly one definition of "verified"; the engine now delegates to it (no behavior change, existing tests green).

Parallel orchestrator (parallel.py) + owloop run --workers N

Each worker runs one target spec in its own git worktree on its own branch: implement → shared gate → commit. The orchestrator then merges each passed branch into the base branch — because the batch is file-disjoint, those merges never conflict. A round with zero progress counts toward a stall (StopReason.STALLED) so a parallel run can't spin forever. A fresh adapter is created per worker (adapters hold per-run streaming state). --workers 1 (default) leaves the sequential engine untouched.

Docs & specs

Spec template + generator now teach the ## Files scope and disjoint decomposition; CLAUDE.md documents the file-disjoint principle and the shared gate.

Tests & checks

  • tests/test_parallel.py — real worktrees + merges, overlap→sequential, stall, preflight.
  • file-disjoint scheduling tests in tests/test_spec_queue.py.
  • Full suite 307 passed; ruff + mypy clean.

This closes out the last phase of #37. Parallelism deliberately relies on decomposition (the ## Files contract), never lock coordination.

caoergou added 2 commits July 6, 2026 17:15
Completes the final phase of the loop-engineering roadmap: run multiple specs
concurrently, safely, by scheduling on file-disjointness rather than lock
coordination — and only now that Phase 1 stall detection exists to bound the
cost of missing progress.

File-disjoint scheduling (spec_queue.py) — specs declare a `## Files` scope;
get_parallel_batch() greedily selects a set of ready specs whose scopes don't
overlap (glob + directory-prefix aware), up to N workers. A spec with no
declared scope runs alone — correctness over parallelism. Ready specs are
already dependency-independent, so scheduling only reasons about file scope.

Shared verification gate (verification.py) — the deterministic gate (acceptance
criteria + backpressure via subprocess, plus the tamper-guard hash) is extracted
into one module that both the sequential engine and the parallel orchestrator
call. There is exactly one definition of "verified"; the engine now delegates to
it (no behavior change).

Parallel orchestrator (parallel.py) + owloop run --workers N — each worker runs
one target spec in its own git worktree on its own branch: implement -> shared
gate -> commit. The orchestrator merges each passed branch into the base branch;
because the batch is file-disjoint those merges never conflict. A round with
zero progress counts toward a stall (StopReason.STALLED) so a parallel run can't
spin forever. Fresh adapter per worker (adapters hold per-run streaming state).
Default --workers 1 keeps the existing sequential engine untouched.

Spec template + generator now teach the `## Files` scope and disjoint
decomposition; CLAUDE.md documents the file-disjoint principle and the shared
gate. Tests: test_parallel.py (real worktrees + merges, stall, preflight) and
file-disjoint scheduling tests in test_spec_queue.py. Full suite 307 passed;
ruff + mypy clean.
# Conflicts:
#	CLAUDE.md
#	src/owloop/engine.py
@caoergou caoergou merged commit 3bb6bae into main Jul 7, 2026
5 of 6 checks passed
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