Skip to content

Tracer bullet: a linear Spec run to a ready Spec PR - #152

Merged
JacobStephens2 merged 2 commits into
mainfrom
issue-141
Sep 29, 2026
Merged

JacobStephens2 merged 2 commits into
mainfrom
issue-141

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

thirdshift <Issue URL> on a Spec now works through its Tickets one at a time, in dependency order, and ends with a ready Spec PR. An issue with no sub-issues is still an ordinary Run.

 run::run(issue)
   preflight::check
+  github::tickets(issue)                 # one GraphQL query: sub-issues, labels, nested count, blockedBy
   branch::select / check_base_branch / launch.pull   # once, for the Spec
   Worktree::create_fresh | continue_existing
+  if Spec:
+    spec_run::run
+      push Spec branch
+      while a Ticket is ready (open, blockers closed, lowest number first)
+        "starting #n"
+        child: thirdshift --spec-branch <Spec branch> <Ticket URL>
+          # a Merge run into the Spec branch, no Run notification, no launch.pull
+          # stderr relayed as "#n: …"
+        "#n landed"; re-read the graph
+      open the Spec PR into the Base branch: Spec's title, "Closes #<spec>", ready
   implement … (unchanged)
  • --spec-branch is a hidden argument. It is not in help.
  • Reached now carries the goal it reached and an optional session log, so the Spec run can report "ready for review" whatever merge asked. The Spec PR's Self-merge comes in a later Ticket.
  • Harness changes:
    • The fake gh serves the Tickets query from sub_issues, labels and blocked_by state. Scenario::spec_has_tickets sets these up.
    • The fake claude picks a script by the issue in the prompt and that issue's session count, set with agent_does_for and agent_does_for_in_session.

Evidence

tests/continuation.rs now also expects the api graphql call among a Run's gh calls.

Merge Danger

Door: two-way

Revert the PR and single-issue Runs are back to exactly what they were.

Blast Radius: moderate

Every Run now makes one extra gh api graphql call after preflight. If GitHub rejects the subIssues/blockedBy fields, or the call fails, every Run fails before it creates anything, including Runs on issues that are not Specs.

Unaddressed findings

Standards

  • The spec_branch: Option is matched in several places (main.rs, run.rs twice), and (goal, email, launch_pull) are overridden together. A "Ticket's Run" type could hold all of this. Skipped for now: the override in main is 6 lines, and the right shape will be clearer once later Tickets add more Ticket-Run behaviour.
  • run::run now also hands off to a Spec run, and Selection is matched twice. Skipped: the Spec run needs the same preflight, Issue branch selection, Base branch checks and worktree as a Run. Handing off after those steps keeps a single copy of them.
  • Reached is shared by a Run and a Spec run, and log became an Option. Skipped: the notification already handles a missing log for failed Runs, so an Option fits both.
  • "landed" is not a glossary term. Skipped: Tracer bullet: a linear Spec run to a ready Spec PR #141 asks for the #<n> landed line word for word.
  • The --spec-branch arm has its own repeated-argument check instead of ask_once. Skipped: ask_once compares enum variants, and this flag takes a value.

Spec

  • Preflight doesn't run only once: each Ticket's Run repeats Origin match, the issue-open check and the git identity check. Skipped: these are cheap safety checks for the Ticket's own issue, which the Spec run's preflight doesn't cover. The notification checks and launch.pull are skipped in Ticket Runs, as asked.
  • Unready Tickets and Tickets with sub-issues are skipped, which Tracer bullet: a linear Spec run to a ready Spec PR #141 didn't ask for. Kept: the glossary and Spec runs: work through a Spec's Tickets in dependency order, in parallel, into one Spec PR #139 define ready this way. It keeps a nested Spec or a needs-info Ticket from being implemented, and it uses fields the query already reads.
  • An existing open Spec PR is reused, and marked ready if it is a draft. Kept: this is a few lines, and without it a Spec branch that already has a PR would fail at gh pr create.
  • The interrupt check in the Ticket loop. Kept: it only stops the loop from starting a new Ticket after Ctrl-C. Full interrupt handling is still a later Ticket.
  • A Spec run sends a Run notification with no session log. Kept: it comes from the existing Run path unchanged, and is covered by the test that expects exactly 1 request. The per-Ticket body is a later Ticket.

Closes #141

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits September 29, 2026 23:35
…c PR

An issue with sub-issues is now a Spec: thirdshift picks and pushes its Spec
branch, runs each ready Ticket in dependency order as a child thirdshift, a
Merge run into the Spec branch told so by a hidden --spec-branch argument,
relays its stderr with a #<n>: prefix, and opens the Spec PR into the Base
branch once every Ticket has landed. The fake gh serves the Tickets query and
the fake claude picks scripts by the issue a session is for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit c99e8c2 into main Sep 29, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-141 branch September 29, 2026 23:42
@JacobStephens2 JacobStephens2 mentioned this pull request Sep 30, 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.

Tracer bullet: a linear Spec run to a ready Spec PR Headless sessions leave smoke-test files in /tmp

1 participant