Repository navigation
ci(release): deploy only after CI and a real mutation run on the same commit - #77
Merged
Merged
Conversation
… commit The release gate deployed when the plan and mutation jobs passed, without waiting for CI or journeys, and accepted a skipped mutation job: a main with no *.workflow.ts planned an empty set and deployed unmutated (R23). The gate now calls ci.yml as a reusable workflow on the same commit, and deploy needs ci, plan and mutation to succeed. The planner refuses a workspace with no *.workflow.ts instead of returning an empty plan. Judgment surfaces changed: .github/workflows/ci.yml, .github/workflows/release-gate.yml, scripts/mutation-shards.ts (GATE1, conductor Q7) Conductor ruling 4
ci.yml no longer triggers on push to main. The Release gate calls ci.yml as a reusable workflow on every push to main, so the standalone push trigger ran the full suite twice per merge. pull_request, workflow_dispatch (release.yml dispatches it on the release PR branch) and workflow_call remain, per conductor ruling 6
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.
Unit U2 of
docs/plans/2026-10-08-0705-feat-gates-bind-and-inline-suppression-plan.md(C1, R23). Conductor rulings 4 and 6.Change
.github/workflows/ci.ymladdson: workflow_call, so the release gate can run CI on its own commit.pull_requestandworkflow_dispatchare unchanged;release.ymlstill dispatchesci.ymlon the release PR branch.ci.ymldrops itspush: branches: [main]trigger. The release gate already runsci.ymlon every push tomain, so the standalone trigger ran the full suite twice per merge. After this change, main's CI runs once, inside the release gate. It lands in the next push, together with a merge ofmain..github/workflows/release-gate.yml:ci: uses: ./.github/workflows/ci.yml;needs: [ci, plan, mutation]. Itsifkeeps only the template guard, so the implicitsuccess()requires all three to succeed. Theneeds.mutation.result == 'skipped'arm is gone;if: packages != '[]', which the planner can no longer produce on success.scripts/mutation-shards.ts: a workspace with no*.workflow.tsis now a refusal (exit 1) instead of an empty plan plus a::notice.scripts/mutation-shards.test.ts: the zero-decision case now expects that refusal. The expected value comes from R23 and CONST-T3, not from the planner's output.Judgment surfaces changed (GATE1, conductor Q7):
ci.yml,release-gate.yml,scripts/mutation-shards.ts.Predicate
*.workflow.ts, the mutation plan refuses and no production deploy runs.journeysfails while mutation passes, no deploy runs. Deploy needsci, which containsjourneys, to succeed.Must not count
githubcontext is the caller's, so it runs on the same SHA.Concurrency groups (KTD1), with the pending
ci.ymlchangeA called workflow evaluates its own workflow-level
concurrencyin the caller's context, so${{ github.workflow }}there is the caller's name (community discussion 30708, answer confirmed by GitHub support).pnpm-release-management's reusablerelease.ymldeclares noconcurrency. No workflow here has amerge_grouptrigger.cancel-in-progressmainrelease-gate.ymlrelease-gate-refs/heads/mainfalsemaincijob)ci.yml, caller's contextRelease gate-refs/heads/maintruemainrelease.ymlrelease-refs/heads/mainfalsemainmain(release step)ci.ymlCI-refs/heads/changeset-release/maintrueci.ymlCI-refs/pull/N/mergetrueci.ymlon ref Rci.ymlCI-RtrueWhy none can cancel another:
release-gate-…,Release gate-…,release-…andCI-…share no string. So a run in one row can never cancel or queue behind a run in another.CI-refs/pull/N/merge. Both the prefix (CIvsRelease gate) and the ref (refs/pull/N/mergevsrefs/heads/main) differ from the gate's CI group. The gate has nopull_requesttrigger. A manual dispatch ofci.ymlonmainlands inCI-refs/heads/main, which is distinct as well.maincannot cancel the gate's CI either. The later gate run waits inrelease-gate-refs/heads/main(cancel-in-progress: false) until the running one finishes. It never starts, so itscicall never reservesRelease gate-refs/heads/mainwhile the earlier gate's CI holds it.ci.ymlresolves toRelease gate-…and its caller holdsrelease-gate-…. Collision there is the failure mode in discussion 30708, where the called workflow cancels its caller. Here the strings differ.ciwould be cancelled and deploy would refuse rather than ship (plan, Risks).Evidence
pnpm test:scripts, locally:ok | 6 passed | 0 failed.pnpm format:check, locally: clean.spike/u2-ae9(384b2a1, deleted afterwards). That branch is this PR's head with every*.workflow.tsdeleted, plus the gate's push trigger extended to the branch. Run 37742540342:plan · mutation shardsjob failed withmutation-shards: no workspace package has a *.workflow.ts file; the release gate refuses an empty setandProcess completed with exit code 1.mutationjob was skipped, so no mutation ran.deploy · productionwas skipped. A caveat: this repo is a template, so its!is_templateguard would also skip deploy. The refusedplanis what blocks deploy in a copy, because the implicitsuccess()requires everyneedsjob to succeed. This run alone can't separate those two causes.ci / …legs also ran in the same run on the same commit. They failed there because the deleted decisions break the tests and build.cfe16b4: run 37742556709, success. The pendingci.ymlchange gets its own PR CI run when it is pushed.