Repository navigation
test(autoland): pin step execution behavior with golden scenarios - #68
Merged
Merged
Conversation
## Summary Phase 0 of the autoland step-abstraction stack: before `execute_plan` and its step rendering/persistence are refactored (an `AutolandStep` base class, `StepView`, injected services, plan optimization, cancellation), this pins what a user can observe of a whole autoland run today, so those refactors can show they change nothing. Each scenario runs the real `stack-pr autoland` flow (`run_autoland` → fresh/resume/replan → `engine.execute_plan`) against a scripted GitHub and local clone, and compares five artifacts with golden files in `tests/golden/autoland/`: - `<scenario>.out.txt`: the full console output (plain console, rich off), including what was typed at prompts - `<scenario>.checkpoint.json`: the last checkpoint the run saved - `<scenario>.status.txt` / `<scenario>.status.json`: `autoland --status` and `--status -o json` over that checkpoint - `<scenario>.plan.txt`: that plan as the `-i` editor shows it; the test also checks it parses back (`parse_plan`) to the same text Scenarios: 1. `one_at_a_time`: two PRs landed one at a time, with a workflow and a confirmation between them (checks pending at first, a review that comes in later, one wrong answer at the prompt) 2. `merge_as_stack`: a run of two `l` steps merged as a GitHub stack, then a workflow, a bare `c`, and a lone `l` 3. `stack_merge_falls_through`: the stack merge fails after landing only its bottom PR; the rest lands one at a time 4. `checks_fail`: checks still fail after their rerun, so the run aborts 5. `workflow_fails`: every deploy run fails, so the workflow checkpoint times out and the run aborts 6. `confirm_eof`: a confirmation with no terminal (EOF), so the run aborts 7. `resume_mid_plan`: `--resume` after a workflow timeout, in a plan with an already-landed prefix (`l 101`, `l 102`) and assumed-completed workflow/confirm steps 8. `landed_prefix`: a fresh run of a plan whose first PRs already landed 9. `replan_carry_over`: `--replan` with an edited plan file; finished checkpoints carry over, a new one runs, and a removed one is reported as not carried over All scenario setup is in `tests/autoland_scenarios.py`, and every patch is in its `_install_seams`, so when the next commits move a seam, only that function needs re-pointing. The patches: `runtime.console` (the plain console, with scripted `input()`), `runtime.HAVE_RICH`, `display.GLYPHS`, `runtime.resilient_sleep` (advances the fake's clock instead of sleeping), and `shell_commands.run_shell_command` / `cli.get_command_output`, which a `FakeWorld` answers for `gh` and `git`. It also stubs `cli.get_stack` and `cli.command_submit`, pins `git.get_current_branch_name`, and makes any real subprocess fail the test. Because the fake sits at the subprocess boundary, the real `gh.GitHub` client, the retry wrapper, and its `$ gh ...` echo all run. The golden artifacts come from real output and the real checkpoint file, so they don't depend on how anything is patched. Temp paths become `<TMP>` and save times `<SAVED>`; SHAs are deterministic. To regenerate after an intended behavior change (then review the diff): ```bash UPDATE_GOLDEN=1 uv run --no-sync pytest tests/test_autoland_golden.py ``` No `src/` changes. ## Test plan - [x] New `tests/test_autoland_golden.py`: 9 golden scenarios, about 0.2s total, no real sleeps or subprocesses - [x] Regenerating twice gives byte-identical golden files (deterministic) - [x] Passes with gh unauthenticated (`GH_CONFIG_DIR=$(mktemp -d) GH_TOKEN=`) - [x] Editing a golden file makes its scenario fail, with a message pointing at `UPDATE_GOLDEN=1` - [x] Reviewed every golden output by hand; it reads like real autoland output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> stack-info: PR: #68, branch: micahjsmith/stack/2
micahjsmith
force-pushed
the
micahjsmith/stack/2
branch
from
October 12, 2026 23:05
04dd488 to
33fe55f
Compare
This was referenced Oct 12, 2026
micahjsmith
added this pull request to stack #77
October 12, 2026 23:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked PRs:
Summary
Phase 0 of the autoland step-abstraction stack: before
execute_planand its step rendering/persistence are refactored (anAutolandStepbase class,StepView, injected services, plan optimization, cancellation), this pins what a user can observe of a whole autoland run today, so those refactors can show they change nothing.Each scenario runs the real
stack-pr autolandflow (run_autoland→ fresh/resume/replan →engine.execute_plan) against a scripted GitHub and local clone, and compares five artifacts with golden files intests/golden/autoland/:<scenario>.out.txt: the full console output (plain console, rich off), including what was typed at prompts<scenario>.checkpoint.json: the last checkpoint the run saved<scenario>.status.txt/<scenario>.status.json:autoland --statusand--status -o jsonover that checkpoint<scenario>.plan.txt: that plan as the-ieditor shows it; the test also checks it parses back (parse_plan) to the same textScenarios:
one_at_a_time: two PRs landed one at a time, with a workflow and a confirmation between them (checks pending at first, a review that comes in later, one wrong answer at the prompt)merge_as_stack: a run of twolsteps merged as a GitHub stack, then a workflow, a barec, and a lonelstack_merge_falls_through: the stack merge fails after landing only its bottom PR; the rest lands one at a timechecks_fail: checks still fail after their rerun, so the run abortsworkflow_fails: every deploy run fails, so the workflow checkpoint times out and the run abortsconfirm_eof: a confirmation with no terminal (EOF), so the run abortsresume_mid_plan:--resumeafter a workflow timeout, in a plan with an already-landed prefix (l 101,l 102) and assumed-completed workflow/confirm stepslanded_prefix: a fresh run of a plan whose first PRs already landedreplan_carry_over:--replanwith an edited plan file; finished checkpoints carry over, a new one runs, and a removed one is reported as not carried overAll scenario setup is in
tests/autoland_scenarios.py, and every patch is in its_install_seams, so when the next commits move a seam, only that function needs re-pointing. The patches:runtime.console(the plain console, with scriptedinput()),runtime.HAVE_RICH,display.GLYPHS,runtime.resilient_sleep(advances the fake's clock instead of sleeping), andshell_commands.run_shell_command/cli.get_command_output, which aFakeWorldanswers forghandgit. It also stubscli.get_stackandcli.command_submit, pinsgit.get_current_branch_name, and makes any real subprocess fail the test. Because the fake sits at the subprocess boundary, the realgh.GitHubclient, the retry wrapper, and its$ gh ...echo all run. The golden artifacts come from real output and the real checkpoint file, so they don't depend on how anything is patched. Temp paths become<TMP>and save times<SAVED>; SHAs are deterministic.To regenerate after an intended behavior change (then review the diff):
No
src/changes.Test plan
tests/test_autoland_golden.py: 9 golden scenarios, about 0.2s total, no real sleeps or subprocessesGH_CONFIG_DIR=$(mktemp -d) GH_TOKEN=)UPDATE_GOLDEN=1🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 5.5 (1M context) noreply@anthropic.com