Repository navigation
Commit 209707e
F6a: push the rewritten head behind a durable marker (#153)
* F6a: push the rewritten head behind a durable marker
prepare-merge now pushes a rebased head whose review is still clear over
exactly the PR head it rewrote, before running command checks. A schema
v18 marker (tasks.push_in_progress) is written before the first external
write and cleared only after a read of the branch settles the outcome;
while it exists, merge, runner admission, status changes, rebases and
other pushes refuse. Preparation and a tracked startup job settle an
interrupted push. GitBranchPusher gains an exact expected-head lease and
a branch read; remotePair reports the task PR's branch.
Part of #22 (F6a).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Settle pushes cancel-safely and wait for the pushed head
Push settlement reads now abort only on shutdown, so a cancel can no
longer strand the marker; the in-run read is bounded by the remaining
preparation deadline. Startup settlement runs under the verified runner
lock and closes the PRs of a task it closed. After a push, preparation
waits (bounded) until GitHub's PR API reports the pushed head, and a move
seen then is reviewed from the pushed head. Adds regressions for each,
plus production push wiring and server startup wiring tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Wait for the pushed head even when the base moves
GitHub can report a moved base while its PR API still shows the pre-push
head. The visibility wait now ends only when the head changes, so the
review is never refreshed back onto a head the branch no longer holds.
The test remote's branch read honours its abort signal, so a cancel that
stopped push settlement would fail a test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* State the pushed-head wait bound exactly
The visibility wait starts no inspection after 30 seconds, so it lasts at
most 30 seconds plus one inspection. Say so in the code and the docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Settle a stranded push on cancel; wait for the PR head after a refusal
A cancel requested while no preparation runs and a push marker remains
now starts the tracked settlement job, so the task and its PRs close
without a restart. After a refused push, preparation waits for GitHub's
PR API to report the branch's new head before reviewing it, as it does
after a push. Renames settleAtStartup to settlePendingPush and corrects
the architecture doc's not-built list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bind a post-push visibility failure; test startup settlement faithfully
A preparation that fails waiting for GitHub to show the pushed head now
binds its failure to the post-push task state, so it is not reported as
stale at once. The startup-settlement server test now builds the state a
crash leaves (a push marker plus a pending cancel) instead of having the
fake job cancel the task itself.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Retry push settlement on a repeated cancel; test the push boundary
Repeating a cancel that waits on an unsettled push now reads the branch
again instead of refusing, so the task can close without a restart.
Adds push-boundary regressions for a pending cancel and a changed
snapshot, and documents the retry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Trace a moved PR head through the whole rewrite lineage
After a push or a refusal, a moved PR head is now reviewed by tracing
history from the reviewed head and its rewrite lineage, nearest first,
so an earlier rewrite codeboost already pushed is reviewed against its
own base instead of the original one. Any failure after the push or
refusal is now bound to the post-push task state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test the push boundary's state check and every settlement bound
Adds regressions for a plan revision applied at the push boundary (only
the task state version changes, so that check is load-bearing), for the
visibility wait ending at the preparation deadline, for the settlement
read's deadline bound, and for shutdown aborting a startup settlement.
States in the docs that a killed push may still land later, harmlessly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Cover cancel-safe settlement, admission and shutdown reads
Adds regressions for a cancel during the next preparation's push
settlement, attempt admission and reassignment refusing while a push is
in flight, and shutdown starting no branch read. The push-boundary
cancel test now cancels through the coordinator while the push reads the
remote, as production does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test that a failed push is reported as current
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bind a failed push to the state its own settlement left
A failed push's settlement read can take up to 30 seconds. The failure
now adopts the task state version that clearing the marker produced only
when nothing else wrote during the read; otherwise it stays bound to the
claim's version, so a plan revision applied meanwhile marks it stale.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bind every push exit to the state that push left
Success, refusal and settlement now share one rule: the version clearing
the push marker produced counts only when nothing else wrote since the
claim; otherwise a later failure stays bound to the claim's version, so
a plan revision applied while the push was in flight marks it stale.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse checks after a push if the task changed while it was in flight
After the pushed head appears, preparation now requires the task state,
review version and snapshot to be exactly what the push left before any
cmd: check runs, so a plan revision or review edit applied during the
push fails it instead of being adopted. The publish guard returns to its
rebase-only form: publishing cannot overlap a push by status, which the
docs now state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Describe the pusher's expected-head rule in its doc comments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test the push claim's admission guards and the busy settlement skip
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address Copilot: capture the claim version, finalize at Git start, reserve settlement
- The push claim uses the task state version captured before the
asynchronous trust refresh, so a reassignment during it refuses.
- Production returns the last guard as the pusher's synchronous
finalizer, closing the gap between validation and the Git push.
- A settlement read keeps the process-settlement reserve inside its
limit and does not start with less than that reserve left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* State that a deadline-ended push leaves its marker unread
When the preparation's own deadline ends the push, less than Git's
settlement reserve is left, so no branch read starts and the marker
stays, as for an unreadable branch. The docs, the code comment and the
test now say so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Name schema version 18 in the architecture doc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address Copilot: a branch read never waits on an escaped pipe holder
Production readBranch ran Git without allowUnsettledReturn, so a process
that left Git's group while holding its output could hold the push
settlement read, startup recovery, a repeated cancel or shutdown without
bound. A read changes nothing, so it now returns failed after the
bounded drain, and the push marker stays.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address Copilot: bound only escaped pipe holders on branch reads
allowUnsettledReturn also stopped waiting for processes still in Git's
group, which a read has no durable ownership of. A new process-group
option, boundEscapedOutput, bounds only the wait for a process outside
the group that holds the output; group members are still waited for,
fail-closed. Branch reads use it. Tests cover both cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Say which branch-read case the settlement bound excludes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Name both unbounded subprocess cases, and an inspection's full settle time
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bound cat-file reads like ls-remote; correct stale rebaser doc line
cat-file only reads, so a process that left Git's group but holds its
output no longer holds fetchCommits or the push's head check: the call
fails after the pipe drain. The reserve comment now lists the Git calls
that still wait (fetch, update-ref, push). The pre-merge-rebase doc no
longer says no production request starts the rebaser.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address Copilot: review a collaborator head found after an unknown push outcome
When the push's read-back fails because a collaborator moved the branch,
the settlement read now returns moved and preparation reviews that head
(review-required, attribution and approvals refreshed), as after a
refusal, instead of failing with the read-back error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address Copilot: recheck the push binding before reviewing a refused or moved push
A plan revision or review edit that landed during the wait for the new
head (or the fetch) was adopted when the observed head was recorded.
The binding the push left is now checked before and after the fetch, as
on the pushed path; such a change fails the preparation as stale.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test the binding check after the fetch; document the stale outcome
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test that the binding check before the fetch runs first
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse a push whose post-rebase review reload adopted a change (F6a, #170)
Since #170 the review reload after a rebase awaits a history worker.
A reassignment or review edit landing during it was adopted into the
push's binding, so the push could run under a state the caller never
checked. The task and review the rebase left are now checked again
after the reload. Regressions for both cases fail without the check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Guard every preparation reload and report its refusals as stale (F6a, #170)
Since #170 each review reload in a preparation awaits a history worker.
The reload after a command check adopted a reassignment into readiness,
and every reload recorded the post-await state before its guard ran, so
a refusal was reported as current rather than stale. A guarded reload
now checks the state it must still match before recording the view;
every reload uses it. Regression for the command-check reload, and stale
assertions on every reload refusal; both fail without the change. Both
gaps also exist on main since #170.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bind preparation failures as current or stale by their cause (F6a, #170)
- A failure of the review reload after a rebase (a worker timeout) is
bound to the state the rebase left, so it is reported as current.
- A command check that a reassignment settled as stale no longer adopts
the reassigned state, so its failure is reported as stale (pre-existing
since F5).
- Regressions for both, and for a change request added while a check
runs, which is refused as stale rather than adopted as review-required.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse a command check whose context changed after it settled (F6a, #170)
runner.settled() resolves only after the runner releases the check's
workspace. A reassignment or plan change in that window left the
attempt completed and was adopted into readiness. The check's state is
now adopted only while its context equals the current one; otherwise
the preparation is refused as stale. The test fixture's failing load now
rejects after the real load settles, as a worker failure would, so no
abandoned load rejects after the test. Docs note that a refresh's
closing reload is not guarded and why.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Give the preparation reload rules their own doc section
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Restore the blank line before the push table
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse a rewritten-head push once shutdown has begun, and kill every escaped test process
Server shutdown sets the runner's admission flag in its first step but closes the pre-merge
coordinator only after the HTTP drain. The push boundary and its failure-path branch read now
check the runner's flag, so no push or new GitHub read starts in that interval.
The cat-file escape test appends each holder's PID, so both detached sleeps are killed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Scope the shutdown comment on the push failure path to its own read
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>1 parent 49f03db commit 209707e
20 files changed
Lines changed: 1618 additions & 108 deletions
File tree
- agents
- docs
- implementation
- runner
- test
- web
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
52 | 59 | | |
53 | 60 | | |
54 | 61 | | |
| |||
94 | 101 | | |
95 | 102 | | |
96 | 103 | | |
97 | | - | |
| 104 | + | |
| 105 | + | |
98 | 106 | | |
99 | 107 | | |
100 | 108 | | |
| |||
175 | 183 | | |
176 | 184 | | |
177 | 185 | | |
178 | | - | |
| 186 | + | |
179 | 187 | | |
180 | 188 | | |
181 | 189 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
46 | | - | |
47 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| |||
357 | 357 | | |
358 | 358 | | |
359 | 359 | | |
360 | | - | |
| 360 | + | |
361 | 361 | | |
362 | 362 | | |
363 | 363 | | |
| |||
410 | 410 | | |
411 | 411 | | |
412 | 412 | | |
413 | | - | |
| 413 | + | |
414 | 414 | | |
415 | 415 | | |
416 | 416 | | |
| |||
419 | 419 | | |
420 | 420 | | |
421 | 421 | | |
422 | | - | |
| 422 | + | |
423 | 423 | | |
424 | 424 | | |
425 | 425 | | |
| |||
0 commit comments