Skip to content

A failing or stopped Run drafts a pull request another live Run is delivering #960

Open

Description

@JacobStephens2

This was generated by AI during triage.

Split from #839, whose Agent Brief covers CI watch reading superseded checks. This is #839's third point, kept here so it isn't lost when #839 closes.

What happened

On 2026-10-19 two Runs worked #812 at once and both pushed to issue-812 and PR #834. When one of them was stopped, its Failed run path pushed an empty salvage commit, 1b54f53, with the same tree as the other Run's head, and converted #834 back to a draft. The other Run then ended failed: PR … is a draft mid-CI watch, leaving its Claim and worktree behind.

Wanted

A failing or stopped Run shouldn't draft a pull request another live Run is delivering. At the least, the other Run should be told why, rather than failing on "is a draft".

Context

The Pickup reservation (ADR 0017) now stops two Pickup runs taking one issue, so this needs a Run started by hand on an Issue URL overlapping another Run. Converting the PR to a draft is part of the Failed run contract today.

Decisions needed

  • How a Run would know another live Run is delivering the same pull request, across machines.
  • Whether the Failed run path should skip drafting then, or draft and tell the other Run why.

Activity

  1. added
    in-progressA Claim: thirdshift has taken this issue
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Nov 10, 2026
  2. JacobStephens2 commented on Nov 10, 2026

    @JacobStephens2
    OwnerAuthor

    This was generated by AI during triage.

    Investigation summary

    The base branch still has the bug. It needs two design decisions before an agent can take it.

    Confirmed in code

    • PullRequest::finish_failed_run (src/pull_request.rs:589-605) observes the Issue branch's open PR and calls adapter.draft(...) whenever the PR is ready and keep_ready is false. The only thing that sets keep_ready is the failing Run's own hold state (FailedRun::held, src/failed_run.rs:30). Nothing checks whether another live Run is delivering that PR.
    • The live Run fails in PullRequest::validate (src/pull_request.rs:704-705) with PR <url> is a draft. It is not told why, and its Claim and worktree are left behind, as A failing or stopped Run drafts a pull request another live Run is delivering #960 describes.
    • claim::make (src/claim.rs:75-81) accepts an issue that is already in-progress and makes no request and gives no warning. A second Run started by hand on an Issue URL therefore can't tell that another Run is live.
    • ADR 0017 (docs/adr/0017-pickup-reserves-issues-on-origin.md) says Issue URL commands keep their old behavior and take no reservation. The thirdshift/pickup/<n> reservation ref therefore doesn't currently show that a hand-started Run is live.

    Inferred

    • This can only happen when a Run started by hand on an Issue URL overlaps another Run on the same issue (Pickup vs. Pickup is excluded by ADR 0017).
    • Signals that could be used, none currently consulted on the failure path: an in-progress Claim that this Run did not add (Claimed already records whether making it added the label), a Pickup reservation ref, or the PR head having moved beyond this Run's last push. Say which machine holds a Claim #833 ("Say which machine holds a Claim") is related and would help identify the other Run's host.

    Related

    Next steps

    The Day shift answers the questionnaire. The issue can then be rewritten with an Agent Brief: a detection rule, a failure-path change in finish_failed_run, and, if chosen, a clear error in validate when another Run drafted the PR. Tests go in src/pull_request.rs tests and the fake-gh suite (tests/).

    Questionnaire

    For the Day shift: #960. A failing or stopped Run converts its pull request to a draft (finish_failed_run, src/pull_request.rs:589). If another Run is delivering the same PR at that moment, that Run fails with an unexplained PR … is a draft and leaves its Claim and worktree behind. This only happens when a Run started by hand on an Issue URL overlaps another Run, because Pickup reservations (ADR 0017) already keep Pickup runs apart. Today claim::make accepts an issue that is already in-progress without a warning, and hand-started Runs take no reservation.

    1. How should a Run know that another live Run is delivering the same PR, across machines? Options: (a) a hand-started Run also takes the thirdshift/pickup/<n> reservation (or a similar ref) and the failure path checks it; (b) a Run that found the issue already in-progress when it made its Claim treats the PR as shared; (c) the failure path skips drafting if the PR head is not the commit this Run last pushed; (d) something else. Your answer sets the detection rule the fix will implement.
    2. Should a hand-started Run on an issue that is already in-progress be refused, or warned about, at Claim time instead? Refusing would prevent the overlap and make question 3 moot.
    3. When another live Run is detected, should the failing Run (a) skip drafting the PR and its salvage commit, or (b) still draft it, but leave a PR comment or marker so the other Run fails with a message naming the stopped Run? This decides what the Failed run contract becomes.
    4. Should the live Run, when it finds its PR drafted mid-CI-watch, release its Claim and worktree the usual way, or leave them for the Day shift? This decides the cleanup expected after such a failure.
  3. added and removed
    in-progressA Claim: thirdshift has taken this issue
    on Nov 10, 2026
  4. JacobStephens2 commented on Nov 11, 2026

    @JacobStephens2
    OwnerAuthor

    This was generated by AI during triage.

    Another instance, on #1494 / PR #1982 (thirdshift 0.27.2), 2026-11-10 20:08 EST. A scheduled Fix run on one host (test) and the Ticket run for #1494 on another (orchestrate) were both delivering issue-1494 at once. They ended in the same minute:

    • the Fix run: cannot push issue-1494: non-fast-forward; reconcile origin/issue-1494 first
    • the Ticket run: PR https://github.com/JacobStephens2/thirdshift/pull/1982 is a draft

    The Fix Pass picked a pull request whose issue had a live Claim on another host. Either a Fix Pass should skip pull requests whose issue is in-progress, or this is the drafting race this issue describes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingready-for-humanRequires human implementation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions