Skip to content

A Pickup run owns its lifecycle to its dispatch, tested in-process behind the Pass seam - #416

Merged
JacobStephens2 merged 2 commits into
issue-413from
issue-414
Oct 5, 2026
Merged

JacobStephens2 merged 2 commits into
issue-413from
issue-414

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

A Pickup run now owns its whole lifecycle, from its gates to the Spec run or Run it dispatches. Everything after the lock runs in pickup::run_through, which is generic over the Pass seam.

 main::pickup
   command::start
-  pickup::run                     # lock, gates, skip, Harness check, start
-  Asks::of_ready_issue
-  run::run_to_end
+  pickup::run                     # lock + preflight, lock skip, builds LaunchAndGitHub
+    run_through(outside)          # generic over the Pass seam
+      gates                       # Sweep, Claim limit, Ready issue search (unchanged)
+      outside.skipped             # skip with its reason
+      outside.step                # "taking Ready issue #n …"
+      outside.check_harness
+      outside.started
+      outside.dispatch(ReadyIssue { issue, is_spec, base }) -> Ended
   started.took / built_with
   started.finish

Changes to the Pass seam (src/pass.rs):

  • OnGitHub is renamed LaunchAndGitHub. It holds the Launch directory, the repository, the Harness choice (&mut), the command's flags and the User config.
  • The seam gains four calls: skipped, check_harness, started and dispatch.
  • dispatch takes Dispatch::ArchitectPlan { plan, base } or Dispatch::ReadyIssue { issue, is_spec, base }. It builds the Asks with the checked Harness, then calls run_to_end with the dispatch's Base branch.
  • InMemory records each new call in its one ordered call list. Its Harness check can be scripted to fail, and its dispatch returns a scripted Ending.

The Architect run builds the renamed adapter and its gates and conclusion use it unchanged. Its Harness check and start now go through the seam. Its dispatch still lives in main until #415.

Evidence

  • Before: the rules of a Pickup run's lifecycle (the line naming the issue taken, no Harness check for a skipped Pass) could only be tested end-to-end, through a whole thirdshift pickup run against the fake binaries.

  • After: new in-process tests in pickup::tests, through run_through with InMemory:

    • a skip for no Ready issue or at the Claim limit is recorded with its reason, and the exact call list shows no Harness check, start or dispatch;
    • the full order is checked: … ReadySearch, Step("taking Ready issue #9 …"), HarnessCheck, Started(Some(9)), Dispatch { 9, is_spec: false, base: "main" };
    • a Spec is dispatched with is_spec: true on the Pickup run's Base branch;
    • a failed Harness check fails the run, and its last call is HarnessCheck, so there is no start and no dispatch;
    • the Pickup run returns the issue it took, with the dispatched run's Ending.

    The end-to-end tests a_progress_line_names_the_issue_taken_before_it_is_dispatched and a_skipped_pass_makes_no_check_of_its_harness_or_model are removed. The ones covering the lock, the preflight checks, the notification, flags reaching the dispatched run and its ending are kept.

    cargo test passed, and cargo clippy --all-targets is clean. One spec_run end-to-end test, two_tickets_meeting_the_same_inherited_failure_share_one_base_fix, failed once under load. It passed three times on its own and on the final full run, and it doesn't touch the Pickup run.

Merge Danger

Door: two-way

The change is meant to be a pure refactor, so it should change nothing on stdout, stderr, the Activity log, the Command log or the Run notification. A Pickup run that fails before it takes an issue still ends through the command's plain failure. started.took and built_with now run after the dispatch rather than before it, but both only fill in the notification, which is read at finish.

Blast Radius: thirdshift pickup

A wiring mistake would show up in Pickup runs started from cron. The Architect run only switches to the renamed adapter.

Unaddressed findings

Standards

  • Divergent Change / Mysterious Name: LaunchAndGitHub names only two of its concerns. Skipped: the Spec decides this exact name, matching the Run's own start adapter.
  • Speculative Generality: Dispatch::ArchitectPlan is under #[expect(dead_code)], and the in-memory dispatch leaves it unimplemented!. Skipped: the acceptance criteria require both variants now, and An Architect run owns its lifecycle to its dispatch, tested in-process behind the Pass seam #415 wires the Architect run's dispatch through the seam.
  • Speculative Generality: architect::run passes flags and config that its path doesn't read yet. Skipped: the Spec has the one adapter hold them, and An Architect run owns its lifecycle to its dispatch, tested in-process behind the Pass seam #415 uses them for the plan's dispatch.
  • Duplicated Code: the Architect run still records its gate skip with logs::skipped rather than outside.skipped. Skipped: that is the Architect run's lifecycle, which is An Architect run owns its lifecycle to its dispatch, tested in-process behind the Pass seam #415.
  • Message Chain: running.0 replaces the removed Skipped::repo(). Skipped: architect::run reads it the same way, so a helper for one field isn't worth it.
  • Data Clump: issue and base travel together in Dispatch and are unpacked into a tuple. Skipped: the enum is that bundle, and the tuple is local to one match.
  • Mysterious Name: run_through, and Outcome::Took. Skipped: <name>_through is the codebase's convention, and the Spec asks for it.
  • Workaround comment: the Harness is cloned for the review session. Skipped: the Spec decides this clone, so the closure can take the seam mutably.

Spec

Closes #414

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits October 5, 2026 04:38
…hind the Pass seam (#414)

The Pass seam grows calls to record a skip and a start, check the Harness
and dispatch an issue, and its production adapter is renamed Launch and
GitHub. Everything in a Pickup run after its lock runs in run_through,
generic over the seam, and the entry point no longer builds Asks or calls
run_to_end for one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le call list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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