Milestones start from the latest default branch. Every milestone branch is cut from origin/<base> after a fetch. So milestone 2 builds on the merged milestone 1, and a redo after a closed PR doesn't carry the rejected work. Uncommitted work carries over; if git would conflict, the driver is told.
The next milestone waits for the merge. While the item's own PR (loop.pr) is open, start_milestone is refused and the driver is pointed at wait_for_review. The PR's state is read from Gitea when the call is made, not taken from the last watch round.
"Part of #N" vs "Closes #N".finish_milestone takes final: earlier PRs are part of the issue and the last one closes it. If final is missing it counts as final, as before. An issue that others depend on keeps them blocked until its last PR merges.
close_item with the item's PR still open waits for the merge, then closes. The walk reached this once milestones could follow a live-read merge.
Documents (D2), in the driver's instructions only:
read ARCHITECTURE.md and docs/plans/ before restating;
work longer than about one PR gets a build plan (goal, interfaces, edge cases, and tests as acceptance criteria per milestone), committed with the first milestone and marked done in each PR;
a design change updates ARCHITECTURE.md in the same PR.
A parking fix, found by the walk.
The bug: a half-done review fix was parked by committing it onto the item's branch. The PR had merged meanwhile, so the work sat on a merged branch, and the next milestone, cut fresh from main, didn't have it.
The fix: parking now stashes uncommitted work, untracked files included, and pushes the snapshot to <item>-parked. Resuming puts it back uncommitted, so it goes wherever the work goes next, and deletes the side branch. A closed item's side branch is dropped. The item's branch is pushed only when it has commits of its own.
Architecture change, please check: D4's parking line now reads "Parking pushes the item's work: its branch, and anything uncommitted to a side branch of its own, never onto a PR's branch."
Tests
test_loop_multi.py:
milestone 2 is cut from main with milestone 1 merged, and carries only its own files;
a start while the PR is open is refused;
a merge no watch round has seen yet is read from Gitea;
a redo after a closed PR drops the rejected work;
Part of / Closes;
close_item waits for an open PR.
test_loop_queue.py: the parking test is updated for the side branch, plus a regression test for the parked half-done fix.
Walk: new property milestones_start_fresh. Reverting to fork-from-current fails it in 9 seeds. parked_work_safe now reads full history, since a stash keeps new files in its third parent.
E2E: a two-milestone feature. PR 1 has the plan under docs/plans/ and says "Part of"; PR 2 builds on the merged PR 1 and says "Closes"; the item closes after both merge. scripts/e2e.sh passed 6 of 6 in one run.
Deferred
An empty milestone that wasn't expected to change code still gets raised with you (D4).
M2.4 of the Development Plan (D1, D2, D4).
## What changes
- **Milestones start from the latest default branch.** Every milestone branch is cut from `origin/<base>` after a fetch. So milestone 2 builds on the merged milestone 1, and a redo after a closed PR doesn't carry the rejected work. Uncommitted work carries over; if git would conflict, the driver is told.
- **The next milestone waits for the merge.** While the item's own PR (`loop.pr`) is open, `start_milestone` is refused and the driver is pointed at `wait_for_review`. The PR's state is read from Gitea when the call is made, not taken from the last watch round.
- **"Part of #N" vs "Closes #N".** `finish_milestone` takes `final`: earlier PRs are part of the issue and the last one closes it. If `final` is missing it counts as final, as before. An issue that others depend on keeps them blocked until its last PR merges.
- **`close_item` with the item's PR still open waits for the merge,** then closes. The walk reached this once milestones could follow a live-read merge.
- **Documents (D2), in the driver's instructions only:**
- read `ARCHITECTURE.md` and `docs/plans/` before restating;
- work longer than about one PR gets a build plan (goal, interfaces, edge cases, and tests as acceptance criteria per milestone), committed with the first milestone and marked done in each PR;
- a design change updates `ARCHITECTURE.md` in the same PR.
- **A parking fix, found by the walk.**
- **The bug:** a half-done review fix was parked by committing it onto the item's branch. The PR had merged meanwhile, so the work sat on a merged branch, and the next milestone, cut fresh from main, didn't have it.
- **The fix:** parking now stashes uncommitted work, untracked files included, and pushes the snapshot to `<item>-parked`. Resuming puts it back uncommitted, so it goes wherever the work goes next, and deletes the side branch. A closed item's side branch is dropped. The item's branch is pushed only when it has commits of its own.
- **Architecture change, please check:** D4's parking line now reads "Parking pushes the item's work: its branch, and anything uncommitted to a side branch of its own, never onto a PR's branch."
## Tests
- **`test_loop_multi.py`:**
- milestone 2 is cut from main with milestone 1 merged, and carries only its own files;
- a start while the PR is open is refused;
- a merge no watch round has seen yet is read from Gitea;
- a redo after a closed PR drops the rejected work;
- Part of / Closes;
- `close_item` waits for an open PR.
- **`test_loop_queue.py`:** the parking test is updated for the side branch, plus a regression test for the parked half-done fix.
- **Walk:** new property `milestones_start_fresh`. Reverting to fork-from-current fails it in 9 seeds. `parked_work_safe` now reads full history, since a stash keeps new files in its third parent.
- **E2E:** a two-milestone feature. PR 1 has the plan under `docs/plans/` and says "Part of"; PR 2 builds on the merged PR 1 and says "Closes"; the item closes after both merge. `scripts/e2e.sh` passed 6 of 6 in one run.
## Deferred
- An empty milestone that wasn't expected to change code still gets raised with you (D4).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
- Every milestone branch is cut from the latest default branch: the next
milestone builds on the merged previous one, and a redo after a closed PR
drops the rejected work. Uncommitted work comes along.
- While the item's PR is open, start_milestone is refused, with the PR's
state read from Gitea at that moment, not the last watch round.
- finish_milestone(final): earlier PRs say "Part of #N", the last "Closes
#N"; unsaid, it's final, as before.
- close_item with the item's PR still open waits for the merge (L2: a
closed item leaves nothing open).
- The driver's instructions cover ARCHITECTURE.md and build plans under
docs/plans/ (D2); the harness never parses a plan.
- Parking stashes uncommitted work and pushes it to <item>-parked, put back
on resume, instead of committing it onto the item's branch. The walk
found a half-done review fix parked onto a PR that had merged meanwhile,
where it was lost. Architecture D4's parking line says so.
Tests: unit tests for fresh milestone branches, the merge wait (including
a merge not yet watched), redo after a closed PR, Part of/Closes, close
waiting on an open PR, and the parked-fix regression; the walk's new
milestones_start_fresh property (fork-from-current fails 9 seeds); an e2e
two-milestone feature.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
M2.4 of the Development Plan (D1, D2, D4).
What changes
origin/<base>after a fetch. So milestone 2 builds on the merged milestone 1, and a redo after a closed PR doesn't carry the rejected work. Uncommitted work carries over; if git would conflict, the driver is told.loop.pr) is open,start_milestoneis refused and the driver is pointed atwait_for_review. The PR's state is read from Gitea when the call is made, not taken from the last watch round.finish_milestonetakesfinal: earlier PRs are part of the issue and the last one closes it. Iffinalis missing it counts as final, as before. An issue that others depend on keeps them blocked until its last PR merges.close_itemwith the item's PR still open waits for the merge, then closes. The walk reached this once milestones could follow a live-read merge.ARCHITECTURE.mdanddocs/plans/before restating;ARCHITECTURE.mdin the same PR.<item>-parked. Resuming puts it back uncommitted, so it goes wherever the work goes next, and deletes the side branch. A closed item's side branch is dropped. The item's branch is pushed only when it has commits of its own.Tests
test_loop_multi.py:close_itemwaits for an open PR.test_loop_queue.py: the parking test is updated for the side branch, plus a regression test for the parked half-done fix.milestones_start_fresh. Reverting to fork-from-current fails it in 9 seeds.parked_work_safenow reads full history, since a stash keeps new files in its third parent.docs/plans/and says "Part of"; PR 2 builds on the merged PR 1 and says "Closes"; the item closes after both merge.scripts/e2e.shpassed 6 of 6 in one run.Deferred
🤖 Generated with Claude Code
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE