fix(queue): require a selected project before loading work#3765
Merged
Conversation
The new dismissal override (a stored dismissal must not mask a missing
Queue project) force-opened the Onboarding dialog over every surface in
CI: the daemon-less e2e run (COVEN_CAVE_E2E=1) never has a selected
project, so all 15 pre-existing specs — which follow the documented
contract of setting cave:onboarding:dismissed=1 and mocking /api/* —
timed out behind the aria-modal overlay ('subtree intercepts pointer
events', 25m job timeout).
Stub the project step ok in the harness, mirroring the existing
COVEN_CAVE_E2E short-circuits (playwright.config.ts, mobile-access-
provision.ts). Real runs keep the readiness probe; onboarding-wizard
and familiar-work-queue specs mock this route wholesale, so project-
readiness coverage is unchanged.
Verified locally: route + gate unit tests ok; calendar-month-grid (a
previously pointer-blocked legacy spec), all 13 onboarding-wizard and
all 14 familiar-work-queue tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
With the dismissed short-circuit gone every boot fetches /api/onboarding/status for real; its cold compile + probes race the lazy code-rail chunk on pixel-5 and the sheet renders empty past the 5s expect (the exact E2E failure on this PR's last run). Mock the route like familiar-work-queue.spec.ts already does — specs are self-contained per the harness contract. Verified: code-rail-sheet green across pixel-5/iphone-13/desktop with --repeat-each=2 (was: deterministic pixel-5 fail at this tip). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Queue readiness previously accepted a canonical-path mismatch for a contained .beads directory (&&), while resolveSafeBeadsWorkspace treats any mismatch as unsafe (||) — so readiness could report ready where /api/beads answers 422 unsafe. Delegate the existing-directory verdict to resolveSafeBeadsWorkspace so both surfaces share one contract, and cover the swapped in-repo .beads symlink in the readiness test. Also canonicalize mkdtemp roots in the readiness and workspace tests so they pass on macOS, where os.tmpdir() sits behind the /var symlink. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
His fork branch for #3743 became unreachable, so the work re-lands through this internal branch; record the attribution it is due. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes the Queue surface explicitly depend on a persisted, validated “Queue project” selection (a concrete Git repo root) before reading or mutating Beads work, and ensures onboarding/startup reopens when that selection is missing or stale.
Changes:
- Add a Queue project readiness contract (persisted selection, validation, Generate
bd init, and explicitprojectRootscoping for Queue reads/mutations). - Update onboarding and startup gating to require Git + Queue project selection (with E2E seeding/mocks to keep daemon-less specs stable).
- Align subprocess PATH handling for Queue tooling (git/gh/bd) and harden Beads workspace safety via a shared resolver.
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/onboarding-wizard.spec.ts | Updates onboarding E2E expectations for the new required Git + Queue project steps. |
| tests/mobile/code-rail-sheet.spec.ts | Mocks onboarding status route now that status is probed even when onboarding is dismissed. |
| tests/familiar-work-queue.spec.ts | Extends Queue E2E coverage for projectRoot scoping, project switching, and Generate conflict behavior. |
| tests/chat-boot-landing.spec.ts | Adds baseline spec asserting dismissed onboarding remains closed when Queue selection is seeded. |
| src/lib/surface-warmup-registry.ts | Removes the unscoped tasks:queue warmup resource now that Queue requires an explicit projectRoot. |
| src/lib/server/issue-worktree-provision.ts | Uses caveToolSpawnEnv() for git subprocesses in repo provisioning. |
| src/lib/server/beads-workspace.ts | Introduces shared, symlink-safe .beads workspace resolver. |
| src/lib/server/beads-workspace.test.ts | Adds regression test for swapped .beads symlink safety. |
| src/lib/server/beads-cli.ts | Switches bd subprocess env to caveToolSpawnEnv() while keeping secrets scrubbed. |
| src/lib/server/backup-manifest.ts | Adds Queue selection file to backup manifest. |
| src/lib/server/backup-manifest.test.ts | Verifies Queue selection is included in backup listing. |
| src/lib/queue-project-selection.ts | Adds publish/subscribe helpers to broadcast Queue project selection across windows. |
| src/lib/queue-project-readiness.ts | Implements persisted selection storage, Git validation, Beads workspace checks, and readiness caching. |
| src/lib/queue-project-readiness.test.ts | Exercises readiness codes, cache behavior, and safety invariants (including swapped .beads symlink). |
| src/lib/onboarding-gate.ts | Treats Queue project step as structural for auto-open onboarding logic. |
| src/lib/onboarding-gate.test.ts | Adds test that missing Queue project reopens onboarding even when daemon is down. |
| src/lib/coven-bin.ts | Adds caveToolSpawnEnv() and refactors PATH augmentation ordering/caching. |
| src/lib/coven-bin.test.ts | Asserts Queue tools prefer the launch PATH and validates Queue spawn sites use caveToolSpawnEnv(). |
| src/components/workspace.tsx | Always probes onboarding status at startup, but reopens onboarding when Queue project needs repair. |
| src/components/onboarding-overlay.tsx | Adds required Git + Queue project steps and UI for selecting a Queue project via ProjectPicker. |
| src/components/onboarding-model.ts | Adds required project step to onboarding model type. |
| src/components/onboarding-guided-steps.test.ts | Pins out-of-order selection protection logic in onboarding UI. |
| src/components/familiar-work-queue-view.tsx | Requires readiness first, scopes Queue fetches/mutations by projectRoot, and adds Generate recovery. |
| src/components/familiar-work-queue-view.test.ts | Updates string-contract assertions for projectRoot scoping and readiness-driven behavior. |
| src/components/familiar-work-queue-sections.tsx | Threads projectRoot into bead detail reads. |
| src/components/board-view.tsx | Stops invalidating the removed tasks:queue warm resource. |
| src/components/asana-queue-strip.tsx | Threads Queue-selected projectRoot into Asana → bead filing and resets “filed” per project. |
| src/app/api/queue/readiness/route.ts | Adds loopback-only Queue readiness route with select + per-repo Generate lock contract. |
| src/app/api/queue/readiness/route.test.ts | Tests Generate identity binding, locking/idempotency, and partial-init handling. |
| src/app/api/onboarding/status/route.ts | Adds Queue project step and makes Git required (not optional) to support Queue selection. |
| src/app/api/onboarding/status/route.test.ts | Updates assertions to match required Git + cached Queue readiness integration. |
| src/app/api/beads/route.ts | Requires explicit projectRoot, uses shared workspace resolver, and reuses readiness probe output for mode=ready. |
| src/app/api/beads/route.test.ts | Validates projectRoot scoping across reads/mutations and subprocess cwd/BEADS_DIR correctness. |
| src/app/api/beads/prs/route.ts | Requires explicit projectRoot and switches gh env to caveToolSpawnEnv(). |
| src/app/api/api-contracts.test.ts | Registers /queue/readiness in API contract inventory with local origin guard. |
| src-tauri/src/sidecar_archive_manifest.rs | Bumps MAX_FILE_COUNT budget for sidecar archive manifest. |
| scripts/sidecar-runtime-smoke.mjs | Updates sidecar runtime smoke budget to the new file-count ceiling. |
| scripts/sidecar-runtime-closure.test.mjs | Updates sidecar runtime closure test budget for fileCount. |
| scripts/sidecar-runtime-closure.mjs | Updates documented and enforced runtime file-count budget. |
| scripts/sidecar-bundle-deps.test.mjs | Updates assertions for the revised runtime file-count budget. |
| scripts/run-tests.mjs | Wires new tests into suites and alias loader. |
| playwright.config.ts | Seeds Queue selection file for daemon-less E2E runs. |
| CONTRIBUTORS.md | Adds contributor credit entry for the original Queue project readiness work. |
Comments suppressed due to low confidence (1)
src/lib/queue-project-selection.ts:66
- BroadcastChannel will often echo the message back to the sending window. Without a duplicate guard,
onMessagecan re-dispatch the same selection thatpublishQueueProjectSelection()already dispatched locally, causing duplicate Queue reloads.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+42
to
+44
| function dispatch(project: QueueProjectSelection | null): void { | ||
| window.dispatchEvent(new CustomEvent(QUEUE_PROJECT_SELECTED_EVENT, { detail: { project } })); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-lands #3743 by @CompleteDotTech with the open review thread addressed. The original fork branch was deleted after the fork moved, so the PR head is orphaned and cannot receive the fix; this branch carries all 21 original commits with their authorship intact.
Summary
Review-feedback fix (on top of #3743)
beadsWorkspaceStatus()previously accepted a canonical-path mismatch for a contained.beadsdirectory (&&), weaker thanresolveSafeBeadsWorkspace()(||) — readiness could reportreadywhere/api/beadsanswers 422 unsafe. It now delegates the existing-directory verdict toresolveSafeBeadsWorkspace()so both surfaces share one safety contract by construction, with a swapped in-repo.beadssymlink regression test.mkdtemproots in the readiness and workspace tests (macOS/var→/private/varsymlink broke them locally; CI Linux was unaffected).Validation
pnpm typecheckqueue-project-readiness.test.ts,beads-workspace.test.ts,api/queue/readiness/route.test.tspnpm check:tests-wiredMerge note
Squash-merge with an explicit message preserving:
Co-authored-by: Timothy Wayne Gregg <5861166+CompleteDotTech@users.noreply.github.com>Closes cave-dsbj