feat(dispatch): branch off parent PR when blocker has open PR #465
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!465
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "boss/462"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
When dispatching an issue whose blocker already has an open PR, the spawned worker now branches off
pr/<parent>(latest head SHA) instead ofmain, and is instructed to set the new PR's base to the parent's head ref + includeStacked on #<parent>in the body. Closes #462.apps/server/src/domain/workflow/parent-pr.ts(new) — best-effort resolver that intersects the issue's blockers (native + body-parsed viaparseClosesIssues) with the repo's open PRs. Exact match → that's the parent. Multiple matches → most recentlyupdatedAtwins (with a[parent-pr]warning log). Forge errors returnnull, so behaviour falls back to today'sorigin/HEADcodepath.apps/server/src/infrastructure/vcs/workdir.ts—WorkdirOpts.baseRef(e.g.origin/feat/parent-headRef) is plumbed intoaddWorktree. Only affects the brand-new-branch path; existing local branches reuse history (the rebase cascade handles re-stacking when the parent moves).apps/server/src/background/worker.ts+agent-runner.ts—TaskRequestgainsbase_ref+parent_pr. The runner forwardsbase_refintoWorkdirOpts;parent_prbecomes a{{parent_pr}}template var.apps/server/src/domain/workflow/event-handlers.ts— gated toCODE_FLOW_AGENTS(boss/dev). After the address-review pivot we resolve the parent and, when one exists, prepend a runtime preamble that overrides the static "target main" instruction at the top of the implement skill.Designers don't ship stacked code PRs, so they're explicitly skipped.
Test plan
bun test apps/server/src/domain/workflow/parent-pr.test.ts— 17/17 pass (parser edge cases + resolver dependency-injected with mock forge calls: zero blockers, no matching PR, exact match, Closes/Fixes/Resolves aliases, partial stack with 2 blockers + 1 PR, multiple parents → most recent, forge errors swallowed)bun test apps/server/src/infrastructure/vcs/workdir.test.ts— 19/19 pass (added: child branch tip == parent's pushed SHA whenbaseRef: "origin/parent-branch")bun x turbo run typecheck— 4/4 packages greenbun x turbo run test— full suite 2181 pass / 0 failbun x @biomejs/biome@^2 check .— cleanStacked on #N.CI green. All 4 ACs from #462 are satisfied: detection (exact/multiple/zero),
origin/<headRef>start-point, agent preamble instructing correct base +Stacked on #Nbody marker,{{parent_pr}}template var. DI seam keeps unit tests narrow (no HTTP). Swallow-and-fallback pattern is consistent with the outstanding-review probe it neighbours.Nit not worth blocking: the
beforeMatch === "/"guard inparseClosesIssuesis dead code — the regex's\s+#already prevents same-line cross-repo refs (owner/repo#N) from matching. The test that validates "ignores cross-repo refs" passes because the regex never fires, not because the guard fires. Harmless, but could be removed to simplify the logic.