Skip to content

The Claim limit, and taking in-progress off closed issues - #297

Merged
JacobStephens2 merged 5 commits into
issue-212from
issue-284
Oct 1, 2026
Merged

JacobStephens2 merged 5 commits into
issue-212from
issue-284

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

Closes #284

A Pickup run now makes the Sweep and holds the repository against its Claim limit before it looks for a Ready issue:

 thirdshift pickup
   User config                      # pickup.limit: whole number from 1 up, default 3
   preflight checks
   lock                             # held → skipped, nothing below runs
+  Sweep
+    list closed issues labelled in-progress
+    for each: DELETE the label     # other labels kept; a failure is a `warning:` line
+  Claim limit
+    count open issues labelled in-progress, whoever started them
+    if count >= pickup.limit
+      skipped: exit 0, stdout empty,
+        "at the Claim limit on <owner>/<repo>: <count> open issue(s) labelled in-progress, pickup.limit is <limit>"
   search for the lowest-numbered Ready issue
   dispatch
src/
├── claim.rs     # sweep(), open_count()
├── pickup.rs    # Skipped::AtClaimLimit; lock → Sweep → Claim limit → search
├── config.rs    # pickup.limit, read and written by Setup at 3 with its comment, never asked about
└── github.rs    # closed_issues_labelled(), remove_label()
tests/fakes/gh.rs  # issue list --state closed; api --method DELETE …/labels/<label>; `fake fails` takes a longer prefix
README.md, CONTEXT.md, help   # pickup.limit, the Claim limit, the Sweep

Seams tested at: the thirdshift pickup command (tests/pickup_run.rs), thirdshift setup (tests/setup.rs), thirdshift help (tests/command_surface.rs), and UserConfig::parse (unit tests in src/config.rs).

Evidence

  • Before: with three open issues labelled in-progress, the pass took Numbered Issue branches after a merged or closed PR #7 and started a session:
    test with_three_open_issues_in_progress_and_no_pickup_limit_the_pass_is_skipped ... FAILED
      left: "thirdshift: taking Ready issue #7 \"Issue 7\", as thirdshift …/issues/7 would\n…"
     right: "thirdshift: at the Claim limit on acme/widgets: 3 open issue(s) labelled in-progress, pickup.limit is 3\n"
    test a_pass_takes_in_progress_off_every_closed_issue_and_leaves_its_other_labels ... FAILED
      left: ["bug", "architect-plan", "in-progress"]
     right: ["bug", "architect-plan"]
    
    After: cargo test: all 30 test binaries pass, 0 failed; cargo clippy --all-targets -- -D warnings and cargo fmt --check clean. New end-to-end cases in tests/pickup_run.rs:
    with_three_open_issues_in_progress_and_no_pickup_limit_the_pass_is_skipped
    with_two_open_issues_in_progress_the_pass_takes_a_ready_issue
    over_the_claim_limit_the_pass_is_skipped_naming_the_count_and_the_limit
    pickup_limit_in_the_user_config_raises_and_lowers_the_claim_limit
    a_closed_issue_labelled_in_progress_does_not_count_against_the_claim_limit
    a_pickup_limit_that_is_not_a_whole_number_from_1_up_stops_the_pass_naming_the_file_and_key
    a_pass_takes_in_progress_off_every_closed_issue_and_leaves_its_other_labels
    the_sweep_runs_on_a_pass_that_is_then_skipped_for_the_claim_limit
    the_sweep_runs_on_a_pass_that_is_then_skipped_for_having_no_ready_issue
    the_sweep_does_not_run_on_a_pass_skipped_for_the_lock
    a_sweep_that_fails_prints_a_warning_and_the_pass_carries_on
    a_sweep_that_cannot_list_the_closed_issues_prints_a_warning_and_the_pass_carries_on
    the_sweep_takes_the_label_off_as_the_closed_issue_spells_it
    
    plus setup_writes_pickup_limit_at_3_with_its_comment_and_keeps_one_already_there and help_documents_the_claim_limit_and_taking_in_progress_off_closed_issues.

Unaddressed findings

Standards

  • Shotgun Surgery, the default 3 written in UserConfig::defaults, DEFAULTS, the help and the README: skipped. It is how spec.parallel already writes its default, and a unit test holds DEFAULTS to UserConfig::defaults. The part I agreed with is fixed: the help and README no longer state 3 as a fixed fact.
  • Interface widening, claim::IN_PROGRESS made pub: skipped. READY_FOR_AGENT is pub for the same reason, and the skip reason should spell the label from the one constant rather than a second literal.
  • Primitive Obsession, issues_labelled(.., state: &str): skipped. It is private and reached only through open_issues_labelled and closed_issues_labelled; the reviewer recommended leaving it too.

Spec

  • Scope creep, the Sweep's progress line taking in-progress off #<n>, which is closed before a skipped pass's reason: skipped. A pass that changes labels on GitHub should say so, as the Claim does; Pickup runs: thirdshift takes ready-for-agent issues on its own #212 already allows lines before the reason ("after any passed-over lines"), and the reason is still the last line.
  • Scope creep, a count that fails stops the pass with exit 1: skipped. The spec is silent; without a count the Claim limit can't be held, and it matches how a failed listing of Ready issues ends the pass.
  • Scope creep, the Sweep removes the label as the closed issue spells it: skipped. GitHub's label names are case-insensitive and the rest of claim already treats them so; one test covers it.
  • Scope creep, whole_number_from_1 shared with spec.parallel, and the fake gh's fails taking a longer prefix: skipped. Both serve the ticket: the first avoids a second copy of the parse, the second is what lets a test fail the Sweep without failing the Claim.
  • Caveat, both listings use --limit 1000: skipped. Immaterial at any realistic Claim limit, and the same cap the Ready issue listing has.

Merge Danger

Door: two-way

Reverting restores the old pass. Labels the Sweep took off closed issues stay off, which is the state they should be in.

Blast Radius: Pickup runs

Only thirdshift pickup changes behaviour: with 3 or more open in-progress issues in a repository, scheduled passes now skip until one is closed or pickup.limit is raised, and each pass makes up to one DELETE per closed in-progress issue. A User config with a [pickup] typo now stops every command that reads it, as other unknown keys do. gh issue list gets --state before --repo, with no change in what it returns.

🤖 Generated with Claude Code

JacobStephens2 and others added 5 commits October 1, 2026 19:13
…imit open Claims, and takes in-progress off closed issues

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…label, one error for a whole number from 1 up, the Claim limit over 3 and a Sweep that can't list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: both sides added github::remove_label and the fake gh's label
DELETE. The Claim keeps issue-284's has and spelling helpers, with the
release and removal from issue-212; the README keeps When the Claim ends
and points to the Sweep for an issue closed some other way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m limit before a search that says why it passed an issue over

The Claim's is_on and its ready-for-agent test use github::has_label, the
one home for a label whatever its case; the Sweep keeps its own spelling
helper, since it needs the label as the closed issue spells it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m limit beside a Pickup run's one Run notification

The notification's checks stay first, then the pass is run with pickup.limit.
A pass skipped for the Claim limit sends no notification: the case #298 left
for this branch is tested here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 9e29883 into issue-212 Oct 1, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-284 branch October 1, 2026 20:20
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.

1 participant