Problem
porch approve <id> <gate> (and porch status <id>) run from the workspace root resolve the project via findStatusPath, which walks .builders/* alphabetically and returns the first worktree containing codev/projects/<id>-*. In multi-PR flows an early phase merges status.yaml to the integration branch, so any later builder worktree branched from that branch carries a stale copy of the project dir. If that worktree sorts before the owning one, the approval is written — and committed (writeStateAndCommit) — onto the unrelated builder's branch.
Observed
- Owning worktree:
.builders/spir-5147 (gate verify-approval: pending).
- Sibling:
.builders/bugfix-5163, branched from ci after 5147's PR merged; carried codev/projects/5147-*/status.yaml.
porch approve 5147 verify-approval --a-human-explicitly-approved-this from the root wrote build-complete (auto), gate-approved, protocol complete commits onto bugfix-5163's branch. The owning worktree stayed pending; the builder's porch done kept blocking; a second porch approve from root reported "already approved".
porch pending (which enumerates all projects) showed the pending gate from spir-5147 while porch approve acted on bugfix-5163 — the two commands disagree.
Suggested fix
When multiple worktrees hold the same project id, prefer the worktree whose registered builder id / branch matches the project (e.g. .builders/<protocol>-<id> or the af registry), and refuse with a clear "ambiguous: N copies" error otherwise. At minimum, print which status.yaml path a mutating command is about to touch.
@cluesmith/codev as installed via Homebrew, dist/commands/porch/state.js findStatusPath.
Problem
porch approve <id> <gate>(andporch status <id>) run from the workspace root resolve the project viafindStatusPath, which walks.builders/*alphabetically and returns the first worktree containingcodev/projects/<id>-*. In multi-PR flows an early phase mergesstatus.yamlto the integration branch, so any later builder worktree branched from that branch carries a stale copy of the project dir. If that worktree sorts before the owning one, the approval is written — and committed (writeStateAndCommit) — onto the unrelated builder's branch.Observed
.builders/spir-5147(gateverify-approval: pending)..builders/bugfix-5163, branched fromciafter 5147's PR merged; carriedcodev/projects/5147-*/status.yaml.porch approve 5147 verify-approval --a-human-explicitly-approved-thisfrom the root wrotebuild-complete (auto),gate-approved,protocol completecommits ontobugfix-5163's branch. The owning worktree stayed pending; the builder'sporch donekept blocking; a secondporch approvefrom root reported "already approved".porch pending(which enumerates all projects) showed the pending gate fromspir-5147whileporch approveacted onbugfix-5163— the two commands disagree.Suggested fix
When multiple worktrees hold the same project id, prefer the worktree whose registered builder id / branch matches the project (e.g.
.builders/<protocol>-<id>or the af registry), and refuse with a clear "ambiguous: N copies" error otherwise. At minimum, print whichstatus.yamlpath a mutating command is about to touch.@cluesmith/codevas installed via Homebrew,dist/commands/porch/state.jsfindStatusPath.