Caught by builder pir-272 on 2026-08-31 while preparing PR #309. It did not ship, because the builder checked what its commit actually held rather than trusting the description.
What happens
porch done <id> --merged <N> writes one file, that project's status.yaml, and then commits the tree rather than the file it wrote.
A builder worktree is long-lived. Any sibling project file that changed on main after the worktree last merged main is present in that worktree at its older revision. Committing the tree carries those older revisions along.
The near miss
pir-272's stranded state commit also carried a revert of bugfix-298's state: it would have deleted merged: true and merged_at from codev/projects/bugfix-298-*/status.yaml and rolled updated_at backwards from 20:02:35 to 19:55:09.
bugfix-298 recorded its merge after pir-272 had last merged main, so pir-272 held the older copy.
Why nobody would catch it
The commit is titled as porch bookkeeping and the diff looks like porch bookkeeping. A reviewer skims a status.yaml change on a chore commit and moves on. The project whose state gets rolled back is not the project the PR is about, and its builder has already finished and gone.
The blast radius grows with how many builders run concurrently and how long a worktree lives. Six ran today.
What would close this
- Stage the exact path porch wrote, never the tree. The repository rule already says stage each file explicitly by path; this is the same rule inside porch.
- A guard that refuses to commit a
status.yaml belonging to a different project id than the one being written.
Related
Caught by builder pir-272 on 2026-08-31 while preparing PR #309. It did not ship, because the builder checked what its commit actually held rather than trusting the description.
What happens
porch done <id> --merged <N>writes one file, that project'sstatus.yaml, and then commits the tree rather than the file it wrote.A builder worktree is long-lived. Any sibling project file that changed on main after the worktree last merged main is present in that worktree at its older revision. Committing the tree carries those older revisions along.
The near miss
pir-272's stranded state commit also carried a revert of bugfix-298's state: it would have deleted
merged: trueandmerged_atfromcodev/projects/bugfix-298-*/status.yamland rolledupdated_atbackwards from 20:02:35 to 19:55:09.bugfix-298 recorded its merge after pir-272 had last merged main, so pir-272 held the older copy.
Why nobody would catch it
The commit is titled as porch bookkeeping and the diff looks like porch bookkeeping. A reviewer skims a
status.yamlchange on a chore commit and moves on. The project whose state gets rolled back is not the project the PR is about, and its builder has already finished and gone.The blast radius grows with how many builders run concurrently and how long a worktree lives. Six ran today.
What would close this
status.yamlbelonging to a different project id than the one being written.Related