Files
msd-core/.changeset/merry-otters-wave.md
Tom Boucher 8c8eda46b0 fix(#4225): scope the sibling-worktree phase-number horizon to the active workstream (#4450)
* test(#4225): failing-first matrix for phase.add --ws workstream-scoped numbering

Nine rows driven through the real CLI: the issue's verbatim topology
(root roadmap @39 committed, workstream @2, sibling git worktree carrying
the root roadmap), same-workstream sibling boundary, empty-workstream
first phase, coincidental root-maximum, no---ws control (the #3849
global horizon, byte-for-byte), cross-workstream isolation, sibling
lacking the workstream (fail open), add-batch parity, and a
next-decimal control. Rows 1/2/3/6/7/8 are RED on next @38e4ce5f62
(numbering computed from the sibling ROOT roadmaps: 40 instead of 3).

* fix(#4225): scope the #3849 sibling-worktree widening horizon to the active workstream

collectSiblingWorktreePhaseNums scanned each sibling git worktree's ROOT
.planning/ (phases/ dirs + ROADMAP.md headers) unconditionally. Under
--ws (GSD_WORKSTREAM), every local number source flows through
planningDir(cwd) and lands in the workstream scope, but the widening
horizon still merged the siblings' ROOT-roadmap numbers into it — so
phase.add --ws in a workstream at Phase 2 inside a project whose root
roadmap sits at Phase 39 minted Phase 40 (directory 40-<slug>, and a
Depends on: Phase 39 that does not exist in the workstream's numbering
universe).

The horizon now resolves each sibling's planning dir through the SAME
canonical resolver, planningDir(wt, ws), with the env workstream read
once via planningDir's own discriminator: a workstream-scoped allocation
scans the sibling's copy of the SAME workstream (a number taken by that
workstream on another branch is still taken — the #3849 widening
survives, scoped), and never the sibling's root roadmap or another
workstream's. No workstream active: ws is null and the root-scope
horizon is byte-for-byte the #3849 behavior. A sibling lacking the
workstream directory contributes nothing (fail open, unchanged).

phase.add and phase.add-batch share the helper; both scopes of both
verbs are covered by the matrix in the previous commit. Output shape
and the publishStateContract boundary are untouched — only the number
changes.

* fix(#4225): rename siblingPlanning -> siblingPlanningDir (review nit)

* chore(#4225): changeset fragment (pr number to backfill)

* chore(#4225): backfill PR number in changeset

---------

Co-authored-by: sim <sim@local>
2026-09-06 22:24:07 -04:00

649 B

type, pr
type pr
Fixed 4450

phase.add --ws now numbers the next phase from the workstream's own roadmap — in a project with sibling git worktrees, phase.add/phase.add-batch with --ws minted a phase number pulled from the root roadmap's maximum (e.g. Phase 40 in a workstream whose own roadmap stopped at Phase 2), creating a 40-<slug> directory and a Depends on: Phase 39 entry pointing at a phase that does not exist in the workstream. The sibling-worktree widening horizon is now scoped like every other number source: a workstream-scoped allocation counts numbers held by the same workstream in sibling worktrees only. (#4225)