Originally created by: Akarsh-Hegde
Replaces the manual "remember to tag a runtime release" flow — the footgun that left production stuck on a broken 1.66.2 runtime — with merge-triggered publishing, gated so it can never downgrade or silently no-op.
There is no paths: filter, so the moment this lands on pre-main, the next push to pre-main runs the gate, sees pre-main's version (1.64.x) > staging-live (1.63.0), and auto-builds + publishes a staging runtime. If this merges before the others, it would publish a runtime that still contains the WORKLOG_SYSTEM bug, smoke-tested by the old weak smoke script that can't catch it.
Required order on pre-main:
WORKLOG_SYSTEM fix — so the published runtime isn't broken.Merging this to pre-main triggers an immediate staging runtime build + publish (a long macOS CI job), not a passive config change. That's desirable here (staging is behind at 1.63.0), but it's not silent — flagging so it's not a surprise.
build-mlx-runtime.yml)gate job (scripts/runtime-publish-gate.sh), the single source of truth: derives the channel (pre-main → runtime-staging, main → runtime-latest) and decides should_publish by comparing services/pyproject.toml to the channel's live runtime-manifest.json.> live (no downgrade, no equal-version churn — a merge that lands a stale version just doesn't ship).runtime-publish-gate.sh --self-test (20 assertions).build runs only when the gate says publish (or workflow_dispatch for a test build). Two explicit publish jobs; publish-production runs in the production-runtime GitHub Environment → required-reviewer approval, so a main merge can't reach customers unattended. (Environment already created: reviewers Akarsh-Hegde + adityaharishch, main-only.)build cancels stale in-flight runs. Release upload factored into scripts/publish-runtime-channel.sh (shared by both publish jobs).paths: filter: GitHub applies paths: to tag pushes too, which would silently break the runtime-v* rollback hatch. The version gate self-limits to one publish per version-ahead state, so a path filter would be redundant.services-version-bump.yml)services/** must bump the version above its target channel's live runtime (main → runtime-latest, pre-main → runtime-staging), via scripts/check-runtime-version-bump.sh. Catches the silent no-op before merge.max(both channels)) on purpose: pre-main legitimately trails main under set-version lockstep, so max() would make every staging services PR unmergeable. Promotion safety still holds — a pre-main → main promotion is a PR with base = main, so it's checked against production-live and fails loudly on a stale version.runtime-publish-gate.sh --self-test: 20/20 (strict-> for branches, differ for tags, fail-closed on error, channel mapping incl. app v* tags → no publish).pre-main → should_publish=true (1.64.0 > 1.63.0); main with a stale 1.64.0 → should_publish=false (would-be downgrade blocked).pre-main passes (1.64.0 > 1.63.0); base main fails loudly (1.64.0 ≯ 1.66.2).publish-production carries environment: production-runtime.Build artifacts have retention-days: 7. If a production approval ever sits >7 days in the environment gate, the publish job would fail on artifact download. Unlikely; noting it.
🤖 Generated with Claude Code
Originally posted by: coderabbitai[bot]
✨ Finishing Touches
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests - [ ] Commit unit tests in branch `ci/runtime-auto-publish`Comment
@coderabbitai helpto get the list of available commands.Originally posted by: Akarsh-Hegde
Update — review finding addressed, CI green ✅
Pushed
9416e434resolving the one actionable issue from the review.Fixed (🟠 [#1] — dead self-test): added
.github/workflows/runtime-gate-selftest.yml, apull_requestcheck that runsscripts/runtime-publish-gate.sh --self-test(the decision-table tests forversion_gt/decide_publish/channel_for_ref— the downgrade-prevention and fail-closed logic). It was previously wired into no workflow.gatejob — so it catches regressions before they reachpre-main/main, and a self-test failure can never block a live runtime publish (the gate→publish path stays uncoupled from the test).Left as notes (non-blocking, no code change):
services-version-bump.ymlis ever marked a required status check, thepaths: services/**filter will make PRs that don't touchservices/**hang (GitHub's required-check + paths trap). Keep it non-required, or make it an always-run job that self-skips.fetch_live_versionfail-closes permanently if a channel release exists but itsruntime-manifest.jsonasset is missing/corrupt. Correct (never the wrong publish); just a known half-published-release recovery case.Merge-readiness ✅
pre-main: #365 (WORKLOG_SYSTEMfix) and #369 (hardened smoke). The "merge this last" ordering is satisfied.pre-main, the gate will publish:services/pyproject.tomlis 1.64.1 > liveruntime-staging1.63.0 →should_publish=true→ build → smoke → publishruntime-stagingat 1.64.1 (carrying the [#365] worklog fix).Good to merge.
Related
Tickets:
#1Tickets:
#2Tickets:
#3Tickets:
#365Ticket changed by: Akarsh-Hegde