Skip to content

Going as far as it can: Failed spec runs - #155

Merged
JacobStephens2 merged 5 commits into
mainfrom
issue-144
Sep 30, 2026
Merged

JacobStephens2 merged 5 commits into
mainfrom
issue-144

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

A Spec run now takes every Ticket it can reach. When any Ticket isn't done, it ends as a Failed spec run.

 land_tickets
   push the Spec branch
-  while a Ticket is ready: run it, fail the Spec run if it fails
-  bail "no Ticket is ready, and #… still open"
+  while a Ticket is ready (open, not Unready, no sub-issues, blockers closed, no outcome yet):
+    run it, record Landed(PR) or Failed(cause, session log)
+    re-read the graph
+  if every Ticket is closed: go on to the Spec PR
+  else: report one line per Ticket, exit 1, no Spec PR, no Spec review

The summary on stderr:

thirdshift: #21 failed: claude exited 1 (session log: …/acme-widgets-issue-21-….jsonl)
thirdshift: #22 blocked by #21
thirdshift: #23 landed with https://github.com/acme/widgets/pull/1
thirdshift: #24 unready: labelled needs-info
thirdshift: #25 blocked by #99 (outside the Spec)
thirdshift: #26 in a cycle: #26 blocked by #27 blocked by #26
thirdshift: Tickets not done: #21, #22, #24, #25, #26, …
  • The cause and session log of a failed Ticket come from the last lines of that Ticket's Run. The session log: prefix is now one constant (failed_run::SESSION_LOG), shared by the Run and the Spec run.
  • Help and the README (new "Spec runs" section) explain Unready Tickets, and that a Spec run takes every Ticket it can reach.
  • CONTEXT.md now says a Ticket with sub-issues is treated as an Unready Ticket.
  • help_does_not_mention_the_flag_aliases now matches whole words, because -h appears inside ready-for-human.

Evidence

  • Before: on main, a failed Ticket ended the Spec run at once, and an unready Ticket made it bail with no Ticket is ready. Tickets that didn't depend on them never ran.
    After: new end-to-end tests in tests/spec_run.rs, all passing. The full cargo test suite is green.
    • a_needs_info_ticket_and_what_it_blocks_are_not_run_while_an_independent_ticket_lands
    • each_unready_label_keeps_a_ticket_from_running: covers ready-for-human, wontfix and needs-triage; a ready-for-agent Ticket runs.
    • a_failed_ticket_stops_only_its_dependents_and_is_not_started_again: checks that the sessions are exactly ["21","23","24"], and checks the cause and the session log path.
    • an_open_outside_blocker_holds_a_ticket_back_and_a_closed_one_does_not
    • tickets_in_a_cycle_are_not_run_and_the_summary_names_the_cycle
    • a_ticket_with_its_own_sub_issues_is_unready
    • removing_a_needs_info_label_while_another_ticket_runs_lets_it_run
    • help_explains_unready_tickets_and_that_a_spec_run_takes_every_ticket_it_can_reach
    • Every Failed spec run test asserts exit 1, empty stdout, no Spec PR and no Spec review session.

Merge Danger

Door: two-way

Blast Radius: Spec runs only

Ordinary Runs are unchanged, apart from the help text and the shared session log: constant, whose output is byte-identical.

Unaddressed findings

Standards

  • report prints lines instead of returning them, so it can't be unit-tested. Skipped: the Spec's testing decision is to test only through the end-to-end harness, which already covers every line.
  • run_ticket parses the child's stderr inline. Skipped: the parse is five lines. The shared SESSION_LOG constant removes the hidden coupling, which was the real risk.
  • Primitive Obsession: PR URL and log path are Strings. Skipped: both are read back as text only to be printed again.
  • Duplicated #n formatting and joins. Skipped: each site joins with a different separator, so a helper would save little.
  • report's cascade repeats some of next_ready's checks. Skipped: they answer different questions ("may it start?" and "why is it not done, in priority order"), and sharing one classifier would blur both.

Spec

  • Only Tickets that landed in this Spec run are listed, not ones closed earlier. Skipped: "Landed Tickets are listed with their PR" reads as the Tickets this run landed. Their PR comes from the Ticket's Run.
  • The cause is taken from the child's last stderr lines, which is fragile. Partly addressed: the prefix is now a shared constant, and the test asserts the cause text. A Run prints its error as one line, so a structured channel isn't needed yet.
  • A spawn or read error in run_ticket aborts the Spec run with no summary. Skipped: it means the thirdshift binary itself can't be run, which would stop every Ticket the same way.

Closes #144

🤖 Generated with Claude Code

JacobStephens2 and others added 5 commits September 30, 2026 00:02
A failed Ticket now stops only the Tickets it blocks and is not started
again. When nothing is ready and any Ticket is still open, the Spec run
opens no Spec PR, exits 1, and lists each landed Ticket with its PR and
each Ticket not done with why: failed (cause and session log), blocked,
unready, or in a cycle. Help and the README explain Unready Tickets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Share the session log line's prefix between a Run and the Spec run that
reads it back, name a Ticket's outcome for what it is, say in help that
Tickets in a cycle don't run, count a Ticket with sub-issues as an
Unready Ticket in CONTEXT.md, and check a failed Ticket's cause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep this branch's Failed spec run, where a failed Ticket stops only the
Tickets it blocks and each not-done Ticket is reported, alongside main's
interrupt handling: the Ticket's Run is relayed on its own thread, an
interrupt is passed on to it, and an interrupted Ticket ends the Spec run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 6e7954f into main Sep 30, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-144 branch September 30, 2026 00:38
@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.

Going as far as it can: Failed spec runs

1 participant