Skip to content

A Pickup run passes over a Spec whose Tickets are all closed, saying why - #307

Merged
JacobStephens2 merged 4 commits into
mainfrom
issue-303
Oct 2, 2026
Merged

JacobStephens2 merged 4 commits into
mainfrom
issue-303

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

A Spec whose Tickets are all closed, with nothing started, is no longer a Ready issue: a Pickup run passes it over with its own line and goes on to the next candidate.

 standing_of(candidate)            # the Ready issue rule, first reason wins
   Unready label        -> "#<n> labelled <label>"
   Claim                -> "#<n> labelled in-progress"
   sub-issue            -> "#<n> is a Ticket of #<spec>, which is not ready"
   base-fix             -> "#<n> labelled base-fix"
   open blocker         -> "#<n> blocked by #<m>"
   already started      -> "#<n> already started: ..."
+  every Ticket closed  -> "#<n> every Ticket is closed"
   not settled          -> "#<n> not settled: ..."
   otherwise            -> Ready issue

The candidate query now carries each sub-issue's state, so no extra request is made per candidate, and both the Pickup run and the Spec run's own check go through spec_run::all_closed:

 CANDIDATE_QUERY
   parent { url }
-  subIssues { totalCount }
+  subIssues(first: 100) { nodes { state } }

thirdshift <Issue URL> on such a Spec is unchanged: it still stops with every Ticket is closed and there is no Spec branch; nothing to do. CONTEXT.md, the README's Ready issue rule and "Why an issue was passed over", and the pickup help text describe the new condition.

Evidence

  • Before: the four new tests and the extended first-reason test in tests/pickup_run.rs failed against main's code:
    with_only_a_spec_whose_tickets_are_all_closed_the_pass_is_skipped_changing_nothing
      stderr: thirdshift: taking Ready issue #7 "Issue 7", as thirdshift https://github.com/acme/widgets/issues/7 would
              thirdshift: every Ticket is closed and there is no Spec branch; nothing to do
      left: Some(1)   right: Some(0)
    a_spec_whose_tickets_are_all_closed_is_passed_over_and_the_next_ready_issue_is_taken
      no PR from issue-9: []
    a_spec_whose_tickets_are_all_closed_is_never_said_to_be_not_settled
      left:  "thirdshift: #7 not settled: labelled ready-for-agent less than 10 minutes ago\n..."
      right: "thirdshift: #7 every Ticket is closed\n..."
    
    After: cargo test --test pickup_run: 73 passed, 0 failed. They cover the passed-over line, the next Ready issue being taken, the skip (exit 0, GitHub state unchanged, no Run notification), the already started line kept for a Spec branch on origin or a pull request, a Spec with one open Ticket still taken, and every Ticket is closed ahead of not settled.
  • The full suite (cargo test, all 30 test binaries) passed on the first commit, with cargo fmt --check and cargo clippy --all-targets clean. After the review fixes, a rename and a doc comment, pickup_run, spec_run, preflight and fakes were re-run and pass; the full suite was not run again.

Merge Danger

Door: two-way

Reverting restores the old rule; nothing on GitHub is written differently.

Blast Radius: Pickup

Only what a Pickup run takes changes. A Spec with more than a hundred sub-issues is judged on its first hundred, as a Spec run already judges it.

Unaddressed findings

Standards

  • The "nothing started" test differs between the Spec run's check and the Pickup run's (Selection::Fresh in src/run.rs, branch::started in src/pickup.rs): both predicates were there before this change, and the issue fixes the new reason's place as after "already started", so they were left as they are.
  • Possible Speculative Generality: all_closed takes an iterator of open flags, not &[Ticket]: kept, since it is what lets one rule serve the Tickets read and the candidate read, which the issue asks to agree.
  • Possible Primitive Obsession: Vec<bool> for a candidate's sub-issues: partly addressed (renamed sub_issue_is_open, with has_sub_issues() hiding the empty case); a type of its own seemed more than one caller needs.
  • Possible Shotgun Surgery: the Ready issue rule is restated in CONTEXT.md, the README, the help, a doc comment and two tests: this is how the repository already documents the rule; gathering it is a separate change.
  • Possible Duplicated Code: "every Ticket is closed" appears in the Pickup run's line and the Spec run's error: two different messages the issue asks for word for word, each used once.

Spec

  • The first hundred sub-issues only: a Spec with more than a hundred Tickets whose first hundred are closed is passed over even if a later one is open. The Spec run reads the same hundred and would refuse it, so the two agree; paging is out of this issue's scope. The limit is now said in the query's doc comment.
  • Not asked for: the pickup help text and its test: kept, because the help restates the Ready issue rule and would otherwise be wrong.
  • Not asked for: the README's advice to close such a Spec or take its ready-for-agent off, and the example's pull request renumbered to free #33: kept, the first as the way out for the reader, the second so the example has no issue and pull request sharing a number.

Closes #303

🤖 Generated with Claude Code

JacobStephens2 and others added 4 commits October 2, 2026 12:24
… why

A Spec with every Ticket closed and nothing started was a Ready issue on
every pass: the Spec run it was dispatched as refused it before the Claim,
so the next pass took it again and no higher-numbered Ready issue was
reached. The Ready issue rule now reads each sub-issue's state in the
candidate query and passes such a Spec over as `#<n> every Ticket is
closed`, after the already-started check and before the settled one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…undred sub-issues read said in the query's doc

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/spec_run.rs: main moved Parallel to the asks module, this branch
changed all_closed to take each sub-issue's open state; both kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 6b40dba into main Oct 2, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-303 branch October 2, 2026 17:01
@JacobStephens2 JacobStephens2 mentioned this pull request Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A Pickup run takes a Spec whose Tickets are all closed on every pass, and never reaches the next Ready issue

1 participant