Repository navigation
nightly-next: new builds go to the Dev ring first and move to Nightly on a canary pass - #23835
Conversation
…ghtly on a canary pass With repository variable NIGHTLY_NEXT_DEV_RING=on, every new cmux NEXT build is tagged sparkle:channel cmux-next-dev, so only apps on the Dev ring get it. Its durable canary verdict (verdicts/<build>.json) of pass moves it to cmux-next: nightly-next-verdict.yml retags the live feed after each verdict (If-Match), and republish-nightly-deltas tags the earlier builds it lists from the same verdicts. Nightly and builds from before rings accept only cmux-next, so they never see an unpromoted build. The old cmux NIGHTLY-identity feed copies only Nightly builds. Unset or off keeps every item on cmux-next, as today. nightly-next-guard.py accepts exactly one of the four ring tags per item; a test keeps the guard, the ring script and UpdateRing.swift on the same tags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
|
|
Found 2 test failures on Blacksmith runners: Failures
|
|
Review (independent subagent): SHIP at c169198 Off by default ( Reds on this head that are not this PR's: release-notary on |
|
Bead |
|
Shipped in:
|
… republish's tooling checkout (#24273) * ci(nightly guards): release-notary checks the renamed legacy step and republish's tooling checkout Two base reds in "workflow-guard-tests / release-notary", both from tests that did not follow a workflow change: - #24019 renamed "Skip a build older than the old feed's" to "Skip a build the old feed already has"; test_nightly_universal_build.sh still asked for the old name and exited there, so every check after line 1265 never ran. - #23835 gave republish-nightly-deltas a sparse checkout of its publication tooling at github.sha into .publish-tooling, as publish-nightly has; test_nightly_cmux_tui_resolve.py exempted that checkout only in publish-nightly. The exemption now applies to any job, and only to a sparse checkout of scripts into .publish-tooling, never the build tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 * ci(nightly guards): the tooling exemption holds only a whole sparse value of scripts paths From the Codex review of e572b24: the exemption matched a prefix, so a sparse list with a trailing /* (the whole tree at github.sha) slipped through. The whole value must now name paths under scripts/, with no dot segments; rejection cases for /*, a trailing /* and scripts/../ pin it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 * ci(nightly guards): a blank line in the tooling sparse list does not end it From the Codex review of 17db2ce: the scan stopped at a blank line, so a /* after one slipped through. The block scalar now runs to the first non-blank line indented no deeper than its key; an explicit case with an empty line before /* pins it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 * nightly resolve test: an inline sparse value continued on deeper lines is not exempt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 * nightly resolve test: the tooling checkout's indent is spaces only, so blank lines can't hide a continuation Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 * nightly resolve test: drop only the validated tooling checkout, by its span Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a160a7-80b6-7101-bcbe-c94cbb747f12&host=cmux16 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
With NIGHTLY_NEXT_DEV_RING on (#23835), every new build is published as cmux-next-dev, and the verdict moved only appcast-arm64.xml to Nightly. Now that each nightly-next build also ships x86_64, its appcast-x86_64.xml item would have stayed on Dev, so a Mac on the Nightly ring would never be offered an Intel update. The promotion step retags both cmux NEXT feeds from the same verdicts. The old cmux NIGHTLY-identity feed stays arm64 only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed purple) (#31288) * Agent chat: a pull request chip's mark takes its state's colour (merged purple) Leo 2026-10-23, of a merged pull request's blue #23835 chip: "I feel like this should be purple". The chip's GitHub mark now reads the pull request's state from the host's cache (one cache-only pr.inspect when it first draws, never a GitHub read) and colours it as the hover card's glyph does: open green, merged purple, closed red; a draft or an unknown one keeps the link colour. Colour only, so the chip never reflows. Tests: bun test test/bare-pr-refs.test.tsx test/url-chip-hover.test.tsx test/bare-ref-repo.test.tsx test/pr-hover-card.test.tsx (+ link/pr card suites): green; the new chip-state test fails on base (no data-pr-state). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-9cf9f3a64099b06033f4 * Agent chat: a card's read waits behind a chip's cache-only ask instead of being dropped Review follow-up on the chip state colour: a card opened while the chip's cache-only pr.inspect was in flight lost its read to the one-ask-per-link rule. It now reads once that ask settles. The chip test asserts the state without a hover and checks all three state rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-9cf9f3a64099b06033f4 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Picking Dev in cmux NEXT's Update Channel does nothing today: every item on the cmux NEXT feed is tagged
cmux-next, which every ring accepts. With this change and repository variableNIGHTLY_NEXT_DEV_RING=on, each new nightly-next build goes out ascmux-next-devfirst, so only apps on Dev get it right away (same app,com.cmuxterm.app.nightly.cmux-next, updating in place). It moves tocmux-next(Nightly) once the canary passes it. Unset oroffkeeps every item oncmux-next, which is today's behavior, so merging this changes nothing until someone sets the variable.How a build moves from Dev to Nightly
build-sign-notarize-nightly, the recovery path andgenerate-nightly-deltastag new itemscmux-next-devwhen the variable ison.verdicts/<build>.jsonispass. It's the signal that already exists, and the train already uses it for its base. I didn't add a soak timer: nothing in the workflows has one, and a timer would promote builds the canary never saw.nightly-next-verdict.ymlsets every feed item's channel from the verdicts after it writes each verdict. The write is If-Match on the bytes it read, like the rollback.republish-nightly-deltas, which lists earlier builds again, tags them from the same verdicts before publishing. The verdict documents are the only source of truth, so any later writer corrects a missed promotion. Turning the variable off puts every item back oncmux-nextat the next verdict or publication.legacy-identity-target(the cmux NIGHTLY-identity feed for pre-NEXT installs) copies only builds already oncmux-next.scripts/ci/nightly_next_ring.py(channel,retag,select).Old builds never see an unpromoted item
Builds from before rings allow only
cmux-next:UpdateFeedResolver.Channel.allowedSparkleChannelsisallowedSparkleChannels(ring: .nightly), andUpdateDriver+SPUUpdaterDelegate.allowedChannels(for:)returns it to Sparkle. Sparkle drops an item whosesparkle:channelisn't inallowedChannels, and the app's own model of this (AppcastItem.isOffered(allowing:)on the release-rings branch: an untagged item is always offered, a tagged one only when allowed) works the same way. Main's builds allow no channel at all. The new testtest_nightly_and_older_builds_never_see_an_unpromoted_buildchecks that rule for Dev, Nightly, pre-ring and main updaters on a retagged feed.The guard
nightly-next-guard.py appcastused to require exactly[cmux-next]. It now requires exactly one tag per item, from the four ring tags (cmux-next-stable,cmux-next,cmux-next-canary,cmux-next-dev). An untagged item, a second tag or a foreign tag is still refused. A test checks that the guard,nightly_next_ring.pyandUpdateRing.swift/UpdateFeedResolver.swiftname the same four tags. Nothing publishes canary or stable items yet.How much faster Dev is
Not much, in the best case:
UpdateSettings.scheduledCheckInterval = 60 * 60). For a Mac checking hourly, Dev is ahead of Nightly by less than one check interval.Right now,
onwould freeze Nightly. The only verdict written so far is afail(build 3968001295301, 22:18 UTC). Every scheduled canary run I opened that actually ran the canary failed (6 of them between 17:25 and 22:13 UTC); the others skipped already-checked builds. That's why the switch defaults to off and the doc says to turn it on only while the canary passes.A Nightly app can be offered a promoted build only while that build is on the feed. The first publication writes a single-item feed with only the new build, and the delta republish adds up to 5 earlier builds back. Between those two writes, Nightly is offered nothing new. That's safe, but it's a delay.
Risk
risk:high: release/updater publication. Mitigations:selecton the old feed, and an extra feed read in the verdict job that writes only if a channel differs (it won't).republish-nightly-deltasnow runs the guard and the ring script from the workflow commit (.publish-tooling, aspublish-nightlyalready does), because the build ref can predate them.Changelog
none
Observed / Not run
Observed, on c169198:
python3 tests/test_nightly_next_ring.py: 17 tests OK. The workflow test for the verdict promotion was red before the verdict workflow change.python3 tests/test_nightly_next_guard.py: PASS. Against the base guard it fails on the three new ring-tag cases and the tag-sync check (red on base, green here).test_nightly_next_feed_rollback,test_nightly_next_recovery,test_nightly_next_post_publish,test_nightly_next_train,test_nightly_republish_delta_guard,test_ci_test_execution_registry,test_ci_workflow_guards_are_wired,test_ci_run_guards,test_ci_linux_guard_routing,test_cmux_next_guards_route,test_feat_ci_guard_group,test_pr_lane_coverage,test_ci_actionlint_covers_every_workflow,test_ci_workflow_run_sources,test_ci_reusable_workflow_permissions,test_ci_release_product_reuse.actionlinton the three changed workflows: the only finding is base's 17-inputworkflow_dispatchon nightly.yml, which is the same on base. Runner-label noise is ignored.python3 scripts/cmux-next/prepush-gate.py: no new violations.Not run:
test_ci_guard_workflow_structure.pyandtest_ci_change_areas.pyfailed only because files were missing from my sparse checkout (agent-chat/package.json,cmux.xcodeproj). CI runs them.Agent session: huge-blue
🤖 Generated with Claude Code
Summary by cubic
Picking Dev in cmux NEXT's Update Channel does nothing today: all items on the feed are tagged
cmux-next, which every ring accepts. With this change, setting repository variableNIGHTLY_NEXT_DEV_RING=onpublishes each new nightly-next build ascmux-next-dev(Dev ring only) and moves it tocmux-next(Nightly) once its durable canary verdict ispass. Unset oroffkeeps every item oncmux-next, so merging this changes nothing until someone enables the variable.nightly-next-verdict.yml(retags the live feed with If-Match) and inrepublish-nightly-deltas; the verdict documents are the single source of truth.cmux-next, so they never see an unpromoted build; the old cmux NIGHTLY-identity feed copies only Nightly items.cmux-next; a test keeps the guard, the ring script, andUpdateRing.swiftin sync.on, Nightly gets nothing new while the canary passes no build, so the variable should be enabled only while the canary is green.Written for commit c169198. Summary will update on new commits.