Skip to content

Complete the native release cutover - #2202

Merged
JacobStephens2 merged 5 commits into
issue-2054from
issue-2160
Nov 14, 2026
Merged

JacobStephens2 merged 5 commits into
issue-2054from
issue-2160

Conversation

@JacobStephens2

@JacobStephens2 JacobStephens2 commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

Closes #2160

The Release run is now only thirdshift release. The release integration suite drives the compiled binary against an isolated bare origin, with fake gh and fake Harness executables. The shell release script, its Python Experiment helper, scripts/release-summary.md and the hidden --release-summary flag are gone, along with its Console parity exclusion. scripts/release-notes.sh stays for the release-notes workflow. The manual, the generated docs and prompts pages, and the home, how-it-works and architecture pages describe scheduled Release Passes and on-demand Release runs.

 scripts/
-├── release.sh               # retired entry point
-├── release-experiment.py    # retired Experiment helper
-├── release-summary.md       # prompt moved to src/prompt.rs earlier
 └── release-notes.sh         # kept: .github/workflows/release-notes.yml
 src/
-├── harness/summary.rs       # --release-summary shim
 ├── release.rs               # + tag-on-origin refusal, failed-job report
 ├── release/recovery.rs      # + closed PR with deleted branch starts over
 └── release/workflow.rs      # + draft hint on post-publication merge failure
 tests/
 ├── release.rs, release/*.rs # ported: every scenario runs the binary
 ├── experiments/release.rs   # real release Experiment transitions
 └── fakes/gh.rs              # script-only --jq branches removed

The review turned up behaviour the retired script had and the native Command had lost. It is restored here:

 thirdshift release <version>
   discover unfinished cuts
-    closed bump PR → refuse "reopen its PR" (even with its branch deleted)
+    closed bump PR, branch gone from origin → no earlier run; start over
   fresh cut
+    v<version> on origin → refuse "v<version> already exists on origin" (before CI selection)
   publish → merge bump PR
-    merge fails → "the Day shift must merge <url>"
+    merge fails on a draft → "<url> is a draft; … gh pr ready <url>"
   release workflow failed
-    gh run view fails → that error replaces the failure
+    gh run view fails → "release workflow failed: <conclusion> (job details unavailable …); recover with gh run rerun --failed <id>; tag is left for the Day shift"

Earlier commits on this branch also restore failed-job names, the run URL and the rerun hint for a failed release workflow. They refuse an overtaken merged release. The manual's Release runs section now documents these.

Test seams: the compiled thirdshift release, status and stop commands, using real isolated Git repositories, fake GitHub and Harness executables, and Resend. Also tested: the retained release-notes shell interface and the public static site's pages.

Evidence

Execution evidence

All Rust runs below used cargo test --locked in a rust:1.99.1-bookworm container on this worktree, with bubblewrap and socat installed (this host has no C linker).

  • Before: cargo test --test release -- a_tag_that_exists_on_origin_is_refused a_tag_on_main_that_exists_on_origin_is_refused_as_on_origin a_draft_bump_pr_after_publication_names_the_ready_step a_failed_release_workflow_still_reports_failure_when_its_details_cannot_be_read a_main_whose_ci_appears_after_a_few_polls_is_released, with the restored assertions and new tests, on cfe30809's code:
    test a_tag_on_main_that_exists_on_origin_is_refused_as_on_origin ... FAILED
    test a_tag_that_exists_on_origin_is_refused ... FAILED
    test a_draft_bump_pr_after_publication_names_the_ready_step ... FAILED
    test a_main_whose_ci_appears_after_a_few_polls_is_released ... ok
    test a_failed_release_workflow_still_reports_failure_when_its_details_cannot_be_read ... FAILED
    test result: FAILED. 1 passed; 4 failed
    
    The origin-tag cases stopped at "no candidate main commit". The draft case said only "the Day shift must merge …". The unreadable-details case ended with gh run view failed: HTTP 502: Bad Gateway, which replaced the failure message.
    After: the same tests, plus a_tag_that_exists_locally_is_refused, a_tag_with_no_bump_pr_is_refused, a_tag_that_is_not_on_the_bump_head_is_refused, a_bump_pr_closed_without_merging_and_its_branch_deleted_starts_over and a_bump_pr_closed_without_merging_is_refused: test result: ok. 11 passed; 0 failed.
  • After, whole binaries: cargo test --locked --no-fail-fast --test release: 136 passed, 0 failed, 3 ignored. cargo test --test experiments: 206 passed, 2 ignored, plus 1 failure, model_graders::a_sandboxed_model_grader_sees_only_its_packet. That container had no socat, which docs/testing.md requires. With socat installed it passed: 1 passed.
  • cargo clippy --locked --all-targets -- -D warnings: clean. cargo fmt --check: clean.
  • npm test --prefix site (includes docs:check): 70 passed, 0 failed. python3 -m unittest discover -s scripts -p 'test_*.py': 72 tests OK (test_generate_release.py: 10 OK).
  • Full Rust suite (cargo test --locked --no-fail-fast) on db185341 in the same container: 4,443 passed, 93 failed, across activity_log, console, launch_pull, process, process_identity, run_notification, security_run, stop and trial_scope. The same nine binaries on CI-green cfe30809 in that container fail with identical per-binary counts. Within run_notification and launch_pull, a different single test fails on each run. So these failures come from the container environment, not from this change. Every other binary, including release and experiments, passed. On db185341 itself, CI passed all four Rust partitions and the coverage gate, plus the site and Console checks; release builds also passed.
  • On cfe30809, CI passed all four Rust partitions, the coverage gate, Python tooling, formatting, clippy, and the site and Console browser checks. Earlier focused runs: slow_release_workflow_listing_keeps_startup_room and a_merged_untagged_release_overtaken_on_main_cannot_be_published each failed before their fixes and passed after.

Visual evidence

Home: Release override on fail or inconclusive — 1440×900

Before
After

Home: Release override on fail or inconclusive — 390×844

Before
After

Manual: Release runs refusals and recovery — 1440×900

Before
After

Manual: Release runs refusals and recovery — 390×844

Before
After

Earlier captures of the cutover itself (home, how-it-works, architecture, manual and release-summary prompt, both viewports) are in this Gist.

Unaddressed findings

Standards

  • 7. Duplicated test support (three summary-Harness installers, a hard-coded Command-log path, duplicated Experiment polling loops). Declined; this is a judgement-call smell. The installers serve different fixtures: the Release end-to-end fixture (tests/release.rs, Release::summary_says), the per-Harness sandbox matrix (tests/release/summaries.rs) and the command-line contract cases (tests/release/native.rs). tests/experiments/release.rs is a separate test binary from tests/release/experiments.rs, so it cannot share their helpers without moving them to tests/support/. That refactor belongs in its own change.
  • 8. Revert the find-replace rewrites of historical records. Partly declined. The garbled sentences are fixed, but the rewrite stays: the issue asks that "nothing in the repository references the retired script or flag". The .scratch/triage.md replacements are bracketed and say "omitted", so they read as editorial notes, not captured output.

Spec

  • 8 (part). Restore a common refusal prefix in assert_refused_by. Declined. The native Command has no shared refusal prefix. assert_refused_by (tests/release.rs) still requires exit code 1, every named reason, unchanged origin refs and unchanged PRs.
  • 9 (part). More --with-experiment tests. The declined-override case was added. Declined:
    • A separate fail-Verdict test. Fail and Inconclusive share one branch in src/release/controls.rs (Conclusion::Fail | Conclusion::Inconclusive), which the inconclusive cases already exercise.
    • A release-level skipped-Experiment test. controls::experiment returns Ok(()) when evals::experiment::for_release returns None. The no_suites and baseline_without_trial skips of that same function are tested in tests/experiments/release.rs.
    • The resume and race cases. workflow::finish runs controls::experiment before notes and PR opening for every untagged or recut cut. repaired_content_waits_for_its_own_experiment_before_tagging covers content changing before tagging.

None of these needs a Spec or Day shift decision, so no issue was filed.

Review coverage: both axes read every changed path, including removed contents. site/docs/index.html is a generated-output exclusion: its source docs/guide.md was reviewed, npm run docs:check --prefix site passed, and npm test --prefix site passed 70/70. Its output was not read. Partial reads: the deleted scripts/release.sh (Standards sampled lines below 87 by grep; Spec read lines 1-720 in full and lines 720-1049 by function header only). The fixes in db185341 were made after the review and were not re-reviewed. Standards: 8 findings (worst: the failed-workflow message lost when its details can't be read). Spec: 9 findings (worst: a closed bump PR with a deleted branch blocked its version permanently). Reports and the finding-count summary are saved with the Session trace.

Security review outcome

No unaddressed introduced findings.

Merge Danger

Door: two-way

A revert restores the retired entry points. Published tags are unchanged. The discovery change only affects a closed bump PR whose branch is gone from origin.

Blast Radius: releases

The changes affect release tests, release refusals, recovery and diagnostics, CLI parity and release documentation.

Built with claude 2.1.322 · claude-opus-5-5 · high

@JacobStephens2

Copy link
Copy Markdown
Owner Author

Delivery completed on agent-authored or reviewed head cfe3080.

Refuse a fresh cut whose tag is already on origin before candidate
selection, name gh pr ready when a draft bump PR blocks the merge after
publication, start over when a closed bump PR's branch is gone, keep the
failed-workflow message when its job details cannot be read, and name the
PR when its head cannot be fetched. Restore the ported tests' specific
assertions, the polling and local-tag scenarios and the declined Experiment
override; remove the fake gh's script-only jq branches; correct the manual,
testing and navigation docs and the homepage override rule.
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