Skip to content

[DEV-79] Enable bounded parallel execution across repositories in workspace mode - #47

Closed
danii1 wants to merge 8 commits into
mainfrom
feature/dev-79-attempt-3
Closed

[DEV-79] Enable bounded parallel execution across repositories in workspace mode#47
danii1 wants to merge 8 commits into
mainfrom
feature/dev-79-attempt-3

Conversation

@danii1

@danii1 danii1 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Task: DEV-79

Summary: Enable bounded parallel execution across repositories in workspace mode

Implementation Details

No usable partial work exists (branches/stashes are for other tasks). Starting fresh from current HEAD. Let me explore the workspace architecture.
Exploration complete. Now checking the dashboard-ui test setup before implementing.

Step 1: Config — [workspace].parallel_across_repos and max_concurrency

Now the validation logic in parseWorkspaceConfig:

Step 2: The bounded workspace scheduler

The parked-item model has a slot-accounting flaw; rewriting with a cleaner readyAt-based defer model:

Step 3: SQLite concurrency hardening (WAL + busy_timeout)

Step 4: Workspace state — routing skips WAL + fleet activity store

Now append the FleetActivityStore to state.ts:
Now update the state.ts module docstring and add the batch-execute hook in the polling acquirer:

Step 5: Polling acquirer — batch execution hook + dedupe removal

Now add removeProcessed to WebhookQueue:

Step 6: Core integration — executor, acquirer batching, event handlers

Now the acquirer factory with the batch strategy:
Now the executor itself:
Now wire runWorkspaceWorker:
Add the onChange hook to the scheduler:
Now update fleet-events.ts to route review/mention runs through the scheduler:

Step 7: Worker shutdown — onShutdown hook + second-signal force exit

Step 8: Dashboard API — fleet activity + fleet-aware worker lock

Now add readonly support to FleetActivityStore:
Now update handleWorkerStatus:
Let me verify compilation before continuing with UI/docs:

Step 9: Dashboard UI — fleet status strip

Step 10: workspace init template comments

All 791 existing tests pass. Now the test suite — first, scheduler unit tests:
Three issues found: (1) my pump dispatches by lane-insertion order, which breaks global FIFO in serial mode; (2)+(3) test bugs (unhandled rejections). Rewriting the scheduler core with a global FIFO dispatch order:
Now fix the two buggy tests (unhandled rejections):
Test run hangs. Let me isolate which test with a manual environment:
The contended-item fix is clear (deferred head must block its lane). But the drain test result is surprising — let me reproduce minimally:
The scheduler itself works correctly. Let me inspect what the test file actually looks like now:
Test file looks right and the repro contradicts it. Let me instrument the actual test to find the divergence:
The queued item actually RAN in test context. Let me instrument timing to understand:
Let me verify this bizarre behavior in isolation:
Found it: in bun 1.3.2, attaching expect(pendingPromise).rejects.* blocks the test until settlement — a runner quirk. Rewriting those assertions with manual outcome capture instead:
Now fix the FIFO bug in pump() — a deferred head must block its lane's followers:
Scheduler tests pass. Now config validation tests:
Two issues: my repo-count clamp fights explicit configs (remove it — the lane model bounds naturally), and a test misplaced the TOML key:
Now the fleet integration tests — appending to workspace-worker.test.ts:
Test helper bug — runs were recorded after the gate instead of at start:
Two test-design deadlocks (never-released gates / draining before releasing the in-flight gate):
Now add fleet-activity store tests and the SQLite concurrency test:
Stale detection logic is inverted — EPERM means alive; any other error means gone:
Now extend the dashboard API tests:
latest() orders rows alphabetically by repo — fix the test expectation:
Now the dashboard-ui test for the fleet chips:
All green. Now documentation:
Now the changelog:
Now the full test suite across the repo, plus lint and format:
Warnings are pre-existing style categories (repo runs with 0 errors). Let me verify I didn't inflate the baseline:
8 new warnings vs baseline — all stylistic promise-plugin warnings matching existing patterns (0 errors). Now a final review of the complete diff:
The diff looks correct. Let me verify the remaining diffs:
Everything checks out. Final full verification — build, typecheck all packages, lint, format check, full test suite:
DEV-79 is implemented on feature/dev-79-attempt-3 (no prior partial work existed — branches/stashes were for other tasks). All checks pass: 831 tests (40 new), build, typecheck, lint (0 errors), format.

What was built

Config (workspace/config.ts) — [workspace].parallel_across_repos (bool, default false) and [workspace].max_concurrency (positive integer; rejects booleans/fractions/zero/negatives/strings; safe default 4 via DEFAULT_MAX_CONCURRENCY). effectiveMaxConcurrency() yields 1 in serial mode and naturally bounds caps larger than the fleet.

Scheduler (workspace/scheduler.ts, new) — one shared bounded scheduler with a global concurrency limit and keyed per-repo FIFO lanes. Dispatch follows global submission order, so serial mode reproduces the exact historical ordering while parallel mode overlaps independent repos up to the cap. Lock contention throws RepoBusyError: the item returns to its lane head and retries after an injectable delay without consuming a global slot or resolving the submission — dedupe stays intact. drain() cancels never-started work (running onCancel rollbacks) and awaits in-flight runs so per-repo locks always release.

Integration (workspace-worker.ts, fleet-events.ts, task-polling-acquirer.ts) — routing happens before scheduling; polling ticks dispatch whole ready batches via a new executeBatch hook, and PR review/mention/relay runs join the same lanes. The executor keeps legacy behavior when no scheduler is passed.

Shutdown (worker.ts) — new awaited onShutdown hook plus second-signal force exit. Fleet mode drains (queued tasks get their dedupe marks rolled back via WebhookQueue.removeProcessed), closes SQLite handles, then releases locks.

SQLite — WAL + busy_timeout + NORMAL sync applied to every store connection sharing queue.db.

ObservabilityFleetActivityStore persists per-repo idle/queued/running snapshots with PID-based stale detection after crashes; GET /api/worker serves them (null on older DBs), the dashboard header renders live per-repo chips, and the fleet daemon's lock is now actually found (plainDir layout fix).

Docsworkspaces.md (new "Parallel execution" + shutdown/status sections), dashboard API table, workspace init template comments, CLI startup banner, changelog entries under [Unreleased].


This PR was automatically created by @devintern/code

@danii1

danii1 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ devintern attempted to resolve this branch's merge conflicts with main but could not finish safely (agent left unresolved conflicts; merge aborted). The merge was aborted; manual resolution needed.

1 similar comment
@danii1

danii1 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ devintern attempted to resolve this branch's merge conflicts with main but could not finish safely (agent left unresolved conflicts; merge aborted). The merge was aborted; manual resolution needed.

# Conflicts:
#	docs/code/workspaces.md
#	packages/code/src/lib/webhook-queue.ts
#	packages/code/src/lib/workspace/config.ts
#	packages/code/src/lib/workspace/state.ts
#	packages/code/src/lib/workspace/workspace-worker.ts
#	packages/code/tests/workspace-worker.test.ts
@danii1

danii1 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

@danii1 danii1 added the blocked label Aug 25, 2026
# Conflicts:
#	packages/code/CHANGELOG.md
#	packages/code/src/lib/task-polling-acquirer.ts
@danii1

danii1 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

@danii1

danii1 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

@danii1

danii1 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

# Conflicts:
#	docs/code/workspaces.md
#	packages/code/CHANGELOG.md
#	packages/code/src/lib/workspace/config.ts
#	packages/code/src/lib/workspace/init.ts
#	packages/code/src/lib/workspace/workspace-worker.ts
#	packages/code/src/worker.ts
#	packages/code/tests/workspace-config.test.ts
@danii1

danii1 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

🔀 This branch had merge conflicts with main; devintern resolved them and pushed the merge. Please double-check the resolution.

danii1 added 2 commits August 27, 2026 16:35
# Conflicts:
#	packages/code/CHANGELOG.md
#	packages/code/src/lib/task-polling-acquirer.ts
#	packages/code/src/lib/workspace/workspace-worker.ts
# Conflicts:
#	packages/code/CHANGELOG.md
#	packages/code/src/lib/workspace/workspace-worker.ts
#	packages/code/src/worker.ts
@danii1

danii1 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ devintern resolved this branch's merge conflicts with main but could not publish the merge to this PR (push rejected: Failed to push branch: error: failed to push some refs to 'https://github.com/getdevintern/devintern'). No changes landed on the PR; manual action needed.

@danii1 danii1 added devintern-authored Pull request written by DevIntern working its own backlog and removed blocked labels Aug 29, 2026
@danii1

danii1 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #126, which preserves the reusable SQLite and graceful-shutdown foundations while leaving scheduler and sandbox architecture for the microVM execution roadmap.

@danii1 danii1 closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devintern-authored Pull request written by DevIntern working its own backlog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant