Repository navigation
feat(promotion-train): cut a candidate only on a dispatch - #2540
Merged
Merged
Conversation
The hourly schedule cut a candidate whenever staging held something new and the last promotion was synced, so a batch closed at whatever tip the first eligible tick saw. Now only a dispatched promotion-prep tick cuts; the schedule advances an open candidate to the merge as before and, with none open, reports a batch ready to cut, naming the dispatch command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NtSiNeMSRGjEKSx7yTfdu
…scribed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019NtSiNeMSRGjEKSx7yTfdu
modelmirror
approved these changes
Oct 18, 2026
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.
What changed and why
The promotion train now cuts a candidate only when promotion-prep is dispatched (
gh workflow run promotion-prep.yml --ref main), so the maintainer decides when a batch closes. The hourly schedule still carries an open candidate through every later step: dispatch the gate, mark it ready, re-fire, merge. With no candidate open, a scheduled tick reports in its run summary that a batch is ready to cut, names the dispatch command, and cuts nothing.src/fedcourtsai/promotion_train.py)Observed.cut_requested, defaultFalse, so a caller that passes nothing never cuts.CUT_COMMANDconstant._cut_stepchecks the request last. A dispatch that can't cut (candidate open, sync pending, nothing to promote, tip already cut) gives the same reason a scheduled tick would. Only a batch that is otherwise ready gets the dispatch hint.fedcourts promotion-train-step --cut-requested.promotion-prep.yml)--cut-requestedwhengithub.event_name == workflow_dispatch. The run gate already limits dispatches and re-runs to the logins inconfig/dispatchers.json.maincan't cut, becausewritebindsprod, which admits onlymain.promotion_body.py).promote.yml's header and its step-summary hint.docs/pipeline.md: the train section, the cut row, the closed-candidate paragraph, operator step 2, and the trigger table.docs/cli.md.Artifact served: the
promote/<date>candidate and its promotion PR. The change controls when one is created.Checks run
ruff format --check,ruff check, andmypyon a fresh cache: clean.pytestontests/test_promotion_train.py,test_workflow_promotion_train.py,test_workflow_promote.pyandtest_promotion_body.py: 218 passed.docs-testslane: 9 passed.workflow_dispatch;CUT_COMMANDverbatim.--offline --persona=regular) onpromotion-prep.ymlandpromote.yml: clean.Review
workflow-reviewer: no blockers. Its recommended fixes are all applied: the stalepromote.ymlheader andpromotion_body.pyline, and the cancelled-dispatch edge now documented. Its nits are applied too: reflowed comments, and "and a dispatch" added to the closed-candidate reason.code-reviewer:promote.ymlheader, is fixed.promote.ymlstep-summary hint now names the dispatch, and the re-run and cancelled-dispatch behaviour is documented.CUT_COMMANDtie, and the history-leaning wording removed.Left for the maintainer. This touches
.github/workflows/, so it is maintainer-owned and needs your code-owner review. I have not merged it intostaging.Effect check (handover note)
Once promoted, no tick cuts unless it is a dispatch.
promotion-preprun's summary should readpromotion train: wait — staging <sha> carries a batch over main, ready to cut; … gh workflow run promotion-prep.yml --ref main, and no newpromote/branch should appear:gh workflow run promotion-prep.yml --ref mainshould cutpromote/<date>and open its draft PR (gh pr list --base main --search head:promote/).Generated by Claude Code