Skip to content

Release with one approval per Ship run #747

Description

@shiny-code-app

Objective

One human approval per Context Panel release, not one per job.

Why

On 2026-10-03, Ship run 37124932609 asked Chris for the release environment approval twice: once for Validate Release Intent (ship.yml), then again for the channel jobs (release.yml "Build macOS App" and app-store-connect-upload.yml "Upload Mac App"), because GitHub requires environment approval per job and the channel jobs reach the gate only after the intent job passes. Chris: "I thought we had one click release." No earlier decision makes release a single approval; Ship is one dispatch, but the approval count grows with the channels. Seven workflows attach environment: release today.

Owner decision

Chris, 2026-10-03, typed in the direction session codex-skills-d2, recorded by it: yes, make it a single approval.

Finish Line

  • The Director's required review sits on exactly one job per Ship run (the release-intent gate).
  • Channel jobs that need signing or upload secrets use a separate environment with no required reviewer, restricted to the protected main branch, and run only after the approved intent job (job dependency), so the secrets stay reachable only through an approved Ship run.
  • Standalone channel workflows that can be dispatched directly (TestFlight, App Store review submission, screenshots, companion upload) keep a required review, or are reachable only through Ship; say which on the PR.
  • Executed tests or a dry-run proof show one approval prompt for a full Ship run.
  • The release doc says how many approvals a release takes and why.

Hand step for Chris (posted by the implementing session when ready)

Creating the new environment, its branch rule and moving the channel secrets into it is an access change, so it is Chris's by hand, with exact clicks; the agent never copies or reads secret values.

Current Status

State: Complete. Source merged and Chris completed the environment-role hand setup; fresh read-only live checks and all-channel structural dry-run satisfy the finish line.
Merged: #751 at 5af6bb8, correcting merged #748 under Owner decision 5969947705.
Owner completion: #747 (comment). Existing release secrets stayed untouched; release-channels never existed. RELEASE_APPROVALS_CONFIGURED=true is owner-confirmed, not independently read by this bot.
Live evidence: Landed scripts/check-release-approval-environment.py full mode exited 0: required owner review verified. --probe exited 0: secret-store protection metadata verified. Additional GET-only metadata assertions verified release has no required reviewer and neither environment has a nonzero wait timer. release-approval requires exactly cbusillo (User), allows solo self-review, disables administrator bypass; both use protected-branches-only and the checker verified main is the sole protected branch. No secret endpoint or secret value was read.
Dry-run evidence: Landed scripts/check-release-approvals.py exited 0 at exact merge 5af6bb8. Ship has one reviewed approve job for all four channels, zero gate secret references, and release as the sole secret environment. Each of six standalone workflows has one reviewed approve gate. Docs explain that count. This is the finish line's permitted structural dry-run, not an observed release prompt.
Engineering evidence: 4/4 PR checks and exact landing CI/CodeQL green; commit gate passed with 1,203 Swift tests, focused release suite 118 passed, final approval fixtures/fast Python gate/actionlint passed. Exact 15-file PyCharm inspection GREEN, zero findings. Five independent Anthropic review dispositions recorded on #751; final approval implementation matches reviewed source. Four pre-existing Markdown MD013 findings reproduced on base.
Residuals: No live release dispatched or prompt exercised. The next separately authorized release will execute the activation-variable guard. Secret inventory is owner-confirmed. The documented optional ad-hoc signing mode remains. Historical-rerun exposure was accepted in switch-now Owner decision 5970898082; no 30-day wait remains. Computed future environment names remain separate #750; #749 and #736 were not started here. Sanitized secret scanning unavailable, not clean; no open CodeQL alerts observed during engineering closeout.
Next action: None required to complete #747. Future releases remain separately authorized; this worker must not dispatch or rerun one.
Blocked by: None.
Cleanup: Own implementation worktree/branches and task scratch removed; no transient job remains. One unowned SDK preserved. Clean primary main deliberately remains stale under no-primary-edit authority; fast-forward before future default-branch work/audits. Installed runtime, the 1.0.69 release session/run/worktree and other worktrees untouched.
Admission: direction#16 spare-capacity engineering rule recorded in claim 5970387065; claim released.
Last verified: 2026-10-03, fresh GET-only probe after Owner completion.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    plan:donePlan completed or superseded

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions