Skip to content

ci(risk): an update channel setting is normal; the update path stays high - #23371

Merged
teamleaderleo merged 4 commits into
feat-cmux-nextfrom
ci-speed/risk-tier-update-channel
Oct 21, 2026
Merged

teamleaderleo merged 4 commits into
feat-cmux-nextfrom
ci-speed/risk-tier-update-channel

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Asked by claude-sr2 (relayed by held-queue triage), 2026-10-21. Leo approved #22781 after the fact and said that update-channel and dev-build settings changes like it do not feel high-risk to him. The decision: keep the updater's install, signing and feed-verification code at risk:high, and let a settings-only channel toggle that reuses the existing signed feeds be normal. The gate has no "medium" tier; normal is the middle tier.

scripts/ci/risk_tier.py now has a normal rule, ahead of the high update-path rule, for the two files that only hold the channel and preference values:

  • CmuxUpdater/UpdateRing.swift: the user's ring, the updates.channel setting (Stable, Nightly, Canary or Dev) and the Sparkle channels each ring accepts;
  • CmuxNextUpdater/UpdatePreferences.swift: install-on-quit, how to notify, how many versions to keep.

Every other updater code file stays high (the updater's views, share sheet and strings were already normal or low and are unchanged), including:

  • UpdateTrack.swift, the build's own release line, which also decides whether Sparkle runs at all;
  • AppcastParser, AppcastSelector, UpdateProber and UpdaterService+Flow;
  • UpdateInstallPreflight, RollbackSwap and UpdateTransfer.

The settings schema and CmuxNextSettings were already normal or low. docs/ci/risk-tiers.md records the distinction.

#22781 itself would still grade high, since it also changed the appcast parser and the prober.

The CmuxUpdater package is now high too (coord-deputy, 2026-10-21: in this PR, so the risk gate changes once). Before this PR no high rule covered Packages/macOS/CmuxUpdater/, so these files graded normal:

  • the channel switch's AppSignatureVerification and SecurityAppSignatureInspector;
  • UpdateFeedResolver;
  • the Sparkle driver (UpdateDriver*);
  • the install code (UpdateController+InstallAttempt, +BackgroundInstall, InstallWatchdog).

The high update-path rule now includes Packages/macOS/CmuxUpdater/*. UpdateRing.swift stays normal, because the channel rule sits above it, and the package's Tests/ stay low.

Nothing else changes: no other path changes tier.

Testing

python3 tests/test_risk_tier.py on huge-blue: 31 tests OK. On the base risk_tier.py, both new tests fail (12 failures).

test_an_update_channel_setting_is_normal_and_the_update_path_stays_high checks two things:

  • a channel PR made only of these files and the settings schema grades normal;
  • adding any one of eight update-path files (UpdateTrack.swift among them) grades it high.

test_the_cmux_updater_package_is_the_update_path checks that each of these grades high on its own: the signature check, the signature inspector, the channel switcher, the feed resolver, the three Sparkle driver files, the two install-attempt files, InstallWatchdog and Package.swift. It also checks that UpdateRing.swift is normal and that the package's tests are low.

Observed / Not run

Observed: the test runs above, and prepush-gate.py with no new violations. Not run: the risk-tier workflow on a real channel-only PR.

Changelog

none

Agent session: cosmic-gray

🤖 Generated with Claude Code

…high

Leo, after #22781: a settings-only channel toggle that reuses the signed
feeds is not high-risk. UpdateTrack.swift and UpdatePreferences.swift (the
channel and preference values) are now normal. Parsing, probing, installing
and verifying an update stay high.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdac-78a0-ac2e-a3aef81402c7&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:high Risk tier (docs/ci/risk-tiers.md) label Oct 21, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by ci-speed on cosmic-gray · session

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review b75370c: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr23371 -f ref=ci-speed/risk-tier-update-channel -f platform=macos -f backend_mode=local

Review of #23371: UpdateTrack is the build's release line and decides whether
Sparkle runs, so it stays high (now pinned by the test). The user's ring is
UpdateRing in the CmuxUpdater package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdac-78a0-ac2e-a3aef81402c7&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 34b13f3. Nit carried forward: the high-table note in docs/ci/risk-tiers.md says "CmuxNextUpdater (except the channel and preference values below)" while UpdateRing.swift lives in CmuxUpdater; the bullet below names both paths correctly. This PR edits risk_tier.py, so it is risk:high and waits for a collaborator approval or risk:human-ok.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-zl5dq created for this PR by the cmux coordinator.

Signature verification, the feed resolver, the Sparkle driver and the install
code graded normal because no high rule named the package. Only UpdateRing
stays normal; each file is pinned by a test that fails on base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdac-78a0-ac2e-a3aef81402c7&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 0b7d7fe. All 44 non-test CmuxUpdater files except UpdateRing.swift grade high, its tests grade low, and nothing outside the updater changes tier. Nits, not fixed: docs/ci/risk-tiers.md says Package.resolved grades normal, but CmuxUpdater/Package.resolved (the Sparkle pin) now grades high, which is intended. UpdateRing.acceptedSparkleChannels grading normal follows the requested channel decision. risk:high: this waits for a collaborator approval or risk:human-ok.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent): SHIP at 0b7d7fe

@blacksmith-sh

blacksmith-sh Bot commented Oct 21, 2026

Copy link
Copy Markdown

Found 1 test failure on Blacksmith runners:

Failure

Test View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at b75370c

Re-review of the feat merge into the reviewed 0b7d7fe: same changed lines (3 files, +57/-3); feat has no commits to risk_tier.py, test_risk_tier.py or risk-tiers.md since the old base; tests/test_risk_tier.py 31 OK at the merged head (huge-blue). The fast-tier red (run 39597903330: PaletteMenuVocabularyTests.swift #expect without try) is in a file this PR does not touch.

@teamleaderleo
teamleaderleo merged commit 7d02a0b into feat-cmux-next Oct 21, 2026
@teamleaderleo
teamleaderleo deleted the ci-speed/risk-tier-update-channel branch October 21, 2026 22:35
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 22, 2026
… read or a pending compile warns and merges (#24265)

* merge-compile-guard tests: only a compile that finished red refuses (red)

The guard's GitHub reads timed out under load on cosmic-gray and refused #23660 and #23371 for hours with
a SHIP receipt at the head and a green compile. These tests expect a pending compile, an unreadable GitHub,
a merge the guard can't name and guards it can't load to warn and let the merge through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* merge-compile-guard: only a compile that finished red refuses; the rest warns and merges

Under load on cosmic-gray (2026-10-21) the guard's GitHub reads timed out and refused #23660 and
#23371 for hours with a SHIP receipt at the head and a green compile. Leo: "IF THE MERGE HOOK IS
WRONG THEN JUST FUCKING MERGE". HQ's landing gate (require-cmux-guards.py, cmuxterm-hq#2976)
already refuses only a missing SHIP, a failed compile, --admin and an unpinned --auto; this repo
hook now agrees with it.

- A compile still waiting, a GitHub read that failed or ran out of time, a merge the guard can't
  name and a checkout it can't read are a Hold: a systemMessage plus additionalContext, no
  permissionDecision, and the merge goes ahead.
- A red compile still refuses, and a Hold earlier in the command never hides a red later in it.
- guards-from-base.sh and the settings hook warn instead of refusing when they can't load the
  guards from the base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* merge-compile-guard tests: a red fleet compile, a crashing guard and a hidden update-branch warning (red)

From the Codex review of #24265: a failed build-fleet compile next to a queued Release compile read as
a wait; a guard exiting 2 blocks the tool call; a merge warning short-circuited the update-branch warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* merge-compile-guard: a red fleet compile refuses beside a queued Release compile; a guard's failure and a merge warning never block or hide

From the Codex review of #24265:
- fleet_red(): a build-fleet compile that finished red with no passing attempt (of it or of the Release
  compile) refuses before any pending state, and compile_wait() no longer reads it as a wait, so neither a
  queued Release compile nor a fleet pass turns it into a warning.
- guards-from-base.sh runs both guards. A refusal is the answer at once; otherwise every warning is joined
  into one answer, so a merge's warning never hides the update-branch warning of the same command. A guard
  that exits non-zero is a warning, never the exit 2 that blocks a tool call.
- The settings hook exits 1 (a non-blocking error) when the launcher itself fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* guards-from-base tests: a refusal in any JSON spacing still refuses (red)

Codex review of #24265, round 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* guards-from-base: read a guard's refusal as JSON, not as text

The loop matched "permissionDecision": "deny" literally, so a valid refusal written with other spacing was
merged into a warning and lost (Codex review of #24265, round 2). The merger now parses each answer and
passes a refusal through as it is before joining warnings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* guards-from-base tests: a refusal never waits for the next guard (red)

Codex review of #24265, round 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

* guards-from-base: a guard's refusal is the answer the moment it is given

Both guards ran before any refusal was read, so a slow update-branch warning could run the hook past its
120 s timeout with the refusal unprinted, and the merge went through (Codex review of #24265, round 3).
Each answer is read as JSON right after its guard; a refusal is printed and the loop ends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1602e-bc09-7990-8c75-5c412a66b114&host=Air-Blue

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant