Skip to content

cmux NEXT: per-PR kill switches (registry, expiry lint, signed Swift reader) - #24212

Merged
teamleaderleo merged 27 commits into
feat-cmux-nextfrom
release-rings/kill-switches
Oct 29, 2026
Merged

teamleaderleo merged 27 commits into
feat-cmux-nextfrom
release-rings/kill-switches

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Leo-ask: ask-8ae00152f6

"shouldn't there be ways to make things more resilient? ... shouldnt we be able to just do partial rollbacks on the fly?"

Leo, 2026-10-22: "shouldn't there be ways to make things more resilient? if we're like bb (or better) and are able to hot reload and hot swap and have richer changelog situations, shouldnt we be able to just do partial rollbacks on the fly?"

Design: partial-rollback.md, section 2 (per-PR kill switches). This is PR 1 of 3 for that section: the registry, the lint and the Swift reader.

What it does

  • killSwitch("pr-N") (CmuxNextCompat/KillSwitches.swift): a risky change keeps its old path and asks if killSwitch("pr-23456") { old } else { new }. It returns true only when the signed flags document has turned that PR's change off. The key is a StaticString, so it has to be a literal.
  • Reader (CmuxNextUpdater/KillSwitchReader.swift, ReleaseNotes/KillSwitchDocument.swift, ReleaseNotesStore.flags()): reads the notes/flags.json that every nightly already publishes and signs. It uses the release-notes fetch, so it gets the same Ed25519 check and verified cache. It applies the DisabledFeatures entries named pr-<N> for the app's ring: the cohort is updates.channel, and a cohort's list replaces the default's, as cmux-tui's feature_flags.rs does.
    • It reads at launch when the updater attaches, when a check leaves the checking phase, and when the ring moves.
    • Unsigned, mis-signed, missing or non-version-1 input turns nothing off. A verified cached document still answers when the Mac is offline.
    • The list changes only between reads. Call sites read it when they create something, never during a gesture.
  • Registry (release-notes/next/kill-switches.json, empty for now): {"pr-N": {"pr": N, "owner", "expires": "YYYY-MM-DD", "default": "new-path"}}.
  • Lint (scripts/cmux-next/check-kill-switches.py, with tests/test_cmux_next_kill_switches.py): rejects missing or mismatched PR numbers, missing owner/expiry, expired or over-90-day entries, a non-new-path default, non-literal/undeclared/duplicate call sites, undeclared entries, and flags that turn off an undeclared pr-N.

The registry is empty, so this PR changes no default behavior. KillSwitchReader.follow() uses one ObservationStream over updater ring and flow phase, with cancellation and no timer or polling. Release-notes work stays on the existing concurrent path. The reader is outside UpdaterService and starts at the updater composition seam.

What follows (PRs 2 and 3): the web reader/bootstrap and a per-merge signed flags-publish workflow. Those need separate review of web wiring and trust policy. This PR does not add call sites, signing secrets, workflow permissions, or a publishing path.

No capture: no visible change.

Changelog

none

Testing

The original failing tests were committed first; the final head is rebased onto feat-cmux-next at 2241229c6708f7cb07bd2507f86806e49468febc.

Observed on final head 06b2074b13339f58bd537524bbc25fa4a1bee877:

  • python3 tests/test_cmux_next_kill_switches.py: 24 passed.
  • python3 scripts/cmux-next/check-kill-switches.py: ok.
  • python3 scripts/cmux-next/prepush-gate.py: no new violations; the required stateful_singletons +2 exception is recorded in plans/cmux-next/arch-ratchet.json.
  • python3 scripts/ci/validate_test_execution_registry.py --repo-root .: valid (549 tests; only pre-existing unregistered-test warnings).
  • git diff --check origin/feat-cmux-next...HEAD: clean.

Observed / Not run

Observed:

  • The focused lint regression is red before the implementation and green on the final head.
  • The exact-head managed-fleet cmux-ci compile-check --app --recipe-version 2 completed successfully for 06b2074b13339f58bd537524bbc25fa4a1bee877 as job a788f9a14f35e4d105fd035b (artifact sha256:ba6d822f3c3dc804bc028e7d4c0e624158c25d296233002307000e3b229309dc).
  • Independent Codex Astra review: SHIP at 06b2074b13339f58bd537524bbc25fa4a1bee877.
  • The optional swift test mobile-core (portable) red is in untouched Packages/iOS/CmuxMobileShellModel; it is a base finding and is not caused by this updater-only change. Required checks are complete (requiredMissing: []); remaining guard jobs are non-required.

Not run:

  • CmuxNextAppTests/KillSwitchesTests cannot run until the existing base test-target compile red (AgentPaneTabRowHolesTests.swift:103, HoleRecordingPage does not conform to PageChromiumPage) is repaired; this PR does not touch that test fixture.
  • No DEV app launch: the registry has no call sites and the UI is unchanged.

Risk: risk:high because this is updater-path code. The change only consumes an already-signed, already-verified document and does not touch signing, install, secrets or workflow permissions.

Agent session: agent session

teamleaderleo and others added 2 commits October 22, 2026 05:08
…Swift reader (failing)

The lint refuses an entry without a PR number or expiry and fails past expiry; the Swift reader
turns off only what a verified flags.json lists for the ring, and nothing otherwise.

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
killSwitch("pr-N") (CmuxNextCompat) answers whether the signed notes/flags.json beside the feed
turned PR N's change off; KillSwitchReader (CmuxNextUpdater) reads it at launch, when a check ends
and when the ring moves, verified with the content-signing key, and turns nothing off without a
verified document. release-notes/next/kill-switches.json declares each switch with its PR, owner
and expiry; scripts/cmux-next/check-kill-switches.py (cmux-next checks) refuses an entry without a
PR number or expiry, fails past expiry, and checks call sites and flags.json against it.

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
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 06b2074: 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=pr24212 -f ref=release-rings/kill-switches -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 2241229 to compare; do not merge until green; see lane-rules

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 7 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpaldm7mtw/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmphns0i3r5/summary-fail.json (live):/summary-fail.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
test_nightly_keeps_a_margin_under_the_limit (main.WorkflowFileSizeTest.test_nightly
_keeps_a_margin_under_the_limit)/
test_nightly_keeps_a_margin_under_the_limit (main.WorkflowFileSizeTest.test_nightly
_keeps_a_margin_under_the_limit)
View Logs

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

@github-actions github-actions Bot added risk:high Risk tier (docs/ci/risk-tiers.md) and removed risk:normal Risk tier (docs/ci/risk-tiers.md) labels Oct 22, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

…int reads whole calls

Review fixes: a read carries a generation, so an older read for a ring the updater moved back to
never overwrites the newer list; KillSwitchReader.start(updater:) keeps the app's reader in
KillSwitchReader.app and stops the one before; the lint finds a call split over lines and counts
every evaluation, not files; the reader tests keep the weakly held updater alive.

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
…s and sees qualified calls

Second review fixes: reads no longer overlap, so an older fetch can't rewrite the verified cache
after a newer one; a read for another ring runs after the one in flight, and a read whose ring moved
applies nothing. The lint masks comments and string contents before finding calls (reading the
literal argument back from the source) and counts CmuxNextCompat.killSwitch(...) too.

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
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next fast gates / post cmux-next/fast-gates is red on 17 of 21 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

…t, definition lines keep offsets

Third review fixes, plus the Python test execution registry entry for the new lint test.

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
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (Codex gpt-5.x, xhigh, independent, run on cmux16 from the diff): SHIP at 4e7a799

Four rounds. Rounds 1 to 3 asked for FIX (read ordering and generations, the reader's owner, one read at a time so verified-cache writes can't reorder, and lint tokenizing: multiline, qualified, comments, strings, interpolation, nested Swift comments, per-evaluation counting). All of those are fixed in 1f55d68, 4026da4, 14637db and 4e7a799. Round 4: "No findings. The three prior lint issues are fixed correctly, and the full diff reveals no blocker or should-fix bugs."

@cursor

cursor Bot commented Oct 22, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 12 h, and no lane holds a lease on it. The orphan sweep could not merge feat-cmux-next in: conflicts in tests/test-execution.toml. Listed for a lane to resolve.

…rings/kill-switches

# Conflicts:
#	tests/test-execution.toml
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 17 of 18 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Checks job structure is red on 12 of 12 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

… a same-ring read during a fetch (failing)

Review of f53b67c (gpt-6.1-sol): `let check = killSwitch; check("pr-999")` passes the lint, a
flags.json root that is not an object crashes it, and a read asked while the same ring's fetch is
out joins that fetch and keeps its stale answer.

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
Restore the CI lint and registry wiring, and fence in-flight reads when a reader is stopped or replaced.\n\nAgent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

Agent-Session: https://cmux.com/deeplink/agent?id=aid-4777d4f75452817a742b
Reject boolean and fractional flags documents before signing or publishing them.\n\nAgent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

Agent-Session: https://cmux.com/deeplink/agent?id=aid-4777d4f75452817a742b
Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c
Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c
Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c
Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c
@teamleaderleo
teamleaderleo merged commit 52c918f into feat-cmux-next Oct 29, 2026
153 of 160 checks passed
@teamleaderleo
teamleaderleo deleted the release-rings/kill-switches branch October 29, 2026 05:15
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40822487758 at cc6b506 failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at fb5c0aa. This pull request is one of 2 merged since: #27172, #24212.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40823474936 at c8b6445 failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at fb5c0aa. This pull request is one of 3 merged since: #27172, #24212, #27107.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

teamleaderleo added a commit that referenced this pull request Oct 29, 2026
…reader) (#24212)

* test(kill-switches): per-PR kill switch registry lint and the signed Swift reader (failing)

The lint refuses an entry without a PR number or expiry and fails past expiry; the Swift reader
turns off only what a verified flags.json lists for the ring, and nothing otherwise.

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

* feat(next): per-PR kill switches read from the signed flags document

killSwitch("pr-N") (CmuxNextCompat) answers whether the signed notes/flags.json beside the feed
turned PR N's change off; KillSwitchReader (CmuxNextUpdater) reads it at launch, when a check ends
and when the ring moves, verified with the content-signing key, and turns nothing off without a
verified document. release-notes/next/kill-switches.json declares each switch with its PR, owner
and expiry; scripts/cmux-next/check-kill-switches.py (cmux-next checks) refuses an entry without a
PR number or expiry, fails past expiry, and checks call sites and flags.json against it.

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

* kill switches: newest read wins, the app's reader has an owner, the lint reads whole calls

Review fixes: a read carries a generation, so an older read for a ring the updater moved back to
never overwrites the newer list; KillSwitchReader.start(updater:) keeps the app's reader in
KillSwitchReader.app and stops the one before; the lint finds a call split over lines and counts
every evaluation, not files; the reader tests keep the weakly held updater alive.

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

* kill switches: build the reader's observation outside its weakly held task

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

* kill switches: one read at a time; the lint skips comments and strings and sees qualified calls

Second review fixes: reads no longer overlap, so an older fetch can't rewrite the verified cache
after a newer one; a read for another ring runs after the one in flight, and a read whose ring moved
applies nothing. The lint masks comments and string contents before finding calls (reading the
literal argument back from the source) and counts CmuxNextCompat.killSwitch(...) too.

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

* kill switches lint: interpolations are code, Swift block comments nest, definition lines keep offsets

Third review fixes, plus the Python test execution registry entry for the new lint test.

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

* test(kill-switches): a function reference, a malformed flags.json and a same-ring read during a fetch (failing)

Review of f53b67c (gpt-6.1-sol): `let check = killSwitch; check("pr-999")` passes the lint, a
flags.json root that is not an object crashes it, and a read asked while the same ring's fetch is
out joins that fetch and keeps its stale answer.

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

* kill switches: the lint refuses a reference to killSwitch and a malformed flags.json; a read asked during a fetch reads again after it

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

* test(kill-switches): the same-ring read test swaps the document only once both fetches are out

Without the wait, the reader's fetches could start after the swap and the test passed on the old reader.

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

* fix(kill-switches): keep portable checks and scoped change size

Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16a58-a194-77a2-8388-63f4c432541c&host=huge-blue

* fix(kill-switches): keep portable checks and scoped change size

Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16a58-a194-77a2-8388-63f4c432541c&host=huge-blue

* ci: record kill switch singleton exception

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

* test: reject stale kill switch reads and malformed versions

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

* fix: close kill switch reader races

Reject stale ring generations, cancel observation with updater teardown, and require strict integer version documents.\n\nAgent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

Agent-Session: https://cmux.com/deeplink/agent?id=aid-4777d4f75452817a742b

* fix: wire and stop kill switch readers

Restore the CI lint and registry wiring, and fence in-flight reads when a reader is stopped or replaced.\n\nAgent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

Agent-Session: https://cmux.com/deeplink/agent?id=aid-4777d4f75452817a742b

* fix: validate nightly flag versions strictly

Reject boolean and fractional flags documents before signing or publishing them.\n\nAgent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

Agent-Session: https://cmux.com/deeplink/agent?id=aid-4777d4f75452817a742b

* test: reject malformed disabled feature lists

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

* fix: reject malformed disabled feature lists

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

* fix: allow omitted empty feature lists

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

* fix: keep defaults guard stable for switch validation

Agent-Session: 01a16c64-8a5c-7b91-a64f-94c2bf076d8c

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Leo Li <t@e>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-289f5b14ddf157d9472f
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40823842282 at 6ac0d64 failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at fb5c0aa. This pull request is one of 3 merged since: #27172, #24212, #27107.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40823925460 at 698b3ef failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files.
Those jobs last passed at fb5c0aa. This pull request is one of 3 merged since: #27172, #24212, #27107.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

lawrencecchen added a commit that referenced this pull request Oct 31, 2026
… capture backdrop is DEBUG/bench only (#28263)

* fix(design): the capture backdrop panel is DEBUG and bench only, as its only callers are

An independent exception review (reward-hacking audit, arch-ratchet tip rises) found that
CaptureBackdropPattern.swift (8fb4805, #27514) ships its CaptureBackdropPanel, its willClose
observer and NSWindow.setCaptureBackdrop in Release, although its only callers
(DebugWindowSnapshot.captureBackdrop, the debug.capture_backdrop route in AppControl+Input) are
`#if DEBUG || CMUX_BENCH_HOOKS`, and its exception said "DEBUG-only". The panel, its view and the
two NSWindow members that make or read it now sit in the same `#if`; Release keeps the two read
helpers that NSWindow+Snapshot uses, as constants (no backdrop: none to skip, nothing behind).
The pattern enum stays (a value type, no observer). Release behavior: unchanged, since nothing
could make a backdrop there.

* arch-ratchet.json: 12 reviewed exceptions for the tip rises an independent reviewer judged needed; 9 unreviewed pending entries removed

Reward-hacking audit (handoff/followups.md "arch-ratchet tip rises (no exceptions)"). An independent
exception reviewer (it wrote none of the code and none of the old reasons) judged 14 candidates at
2391c5e: 12 EXCEPTION-OK, 2 FIX (AppDelegate.swift:514's quit flush, on fix/arch-rise-quit-flush;
the capture backdrop, gated in 2391c5e and then accepted). The reviewer wrote each entry's
receipt itself; each has author, owner and expiry 2026-11-30, one site per entry (allow 1):
global_mutable_statics PaletteScope lock (#28036), CrashWatcher descriptor (#22844);
stateful_singletons KillSwitches.shared (#24212), BlockingViolationTable.shared (f668c89);
observer_sites DesktopWallpaperWatch :144 :147 :148 :149 (#25308), IPhoneHostService wake (#27297),
DebugWindowRecord willClose (#23680), CaptureBackdropPattern willClose (#27514);
blocking_allow_escapes SingleInstanceGuard (#25918), plus its escape_reviews entry (read by the rule
of #28195).

Removed: the 9 PENDING entries with no review that these replace or that cover no site any more
(CrashWatcher, BlockingViolationTable, DesktopWallpaperWatch +7, SingleInstanceGuard, HomeReduceMotion
(a FIX), kill switches +2, PaletteScope +4 (statics gone) and +1, CaptureBackdropPanel). No applied
entry, total or measured_sha changes; no ratchet number is raised. --update still refuses until the
fix PRs land; it is run after them.
lawrencecchen added a commit that referenced this pull request Oct 31, 2026
… become instances (#28266)

* arch: active-look glass scope, batch-close set and kill-switch reader become instances

Lowers the arch-ratchet rows these sites raised with no reviewed exception
(audit-rh, cmux-ad); no behavior change.

- CmuxNextDesign/GlassPanelView.swift: the seven ActiveLookScope statics
  (windows, pending, candidate, materialSite, installed, counts, kinds;
  1335e10, #25704) are one ActiveLookScope instance. The AppKit getter
  hook that its first ActiveLookGlassEffectView installs captures it.
  AppServices makes it once and hands it to the app's ThemeStore
  (ThemeStore.activeLook). The main window gets it through
  WindowRootView(activeLook:), every window-kit window through
  NSWindow.install (scope.store.activeLook) and WindowSurfaceView, and the
  backdrop through WindowMaterialView(activeLook:) and
  GlassPanelView(activeLook:). The hook itself is unchanged.
- CmuxNextAppCore/WorkspaceSelectionCloseFlow.swift: the static running set
  (a439d29, #24341) is WorkspaceSelectionCloseFlow.Running, one per app
  (AppServices.selectionCloses), passed to every batch close and read by
  Close Workspace. It stays app-wide, as the static was.
- CmuxNextUpdater/KillSwitchReader.swift: the static weak app reader and
  start(updater:) (52c918f, #24212) are gone; UpdaterService stops its
  previous reader through its own killSwitchReader property.
- CmuxNextApp/MainMenu+Placements.swift: removes the unused helpGroups,
  groupedItems and otherItems (dead since #24615), which pays for the
  AppServices wiring (app_lines -24).

Tests construct their own ActiveLookScope (InactiveWindowTintTests), and
one more check proves a backdrop with no scope keeps plain glass.
Not compiled or run here (no Swift on the agent VM); fleet compile-check
of the pushed head follows.

* arch: thread the active-look scope to every window owner, no ThemeStore slot; one getter hook per process

Review of 723ce04 (FIX): ThemeStore.activeLook put the one
ActiveLookScope in a public settable slot on ThemeScope.app.store, a static
by another name, read by six window owners through NSWindow.install.

- ThemeStore.activeLook is removed. AppServices holds the scope
  (AppServices.activeLook) and passes it down.
- NSWindow.install(kind:content:scope:activeLook:) takes the scope as a
  parameter with no default, and every caller passes it:
  - the main window (WindowController), from AppServices;
  - browser popups (BrowserPopupWindows, from AppServices) and sign-in
    panels (WebAuthSessionWindows from AppDelegate, then
    WebAuthSessionWindow, then BrowserPopupWindow);
  - the onboarding tool window (OnboardingService, then
    OnboardingWindowPresenter, then OnboardingWindowController);
  - Debug Settings (DebugSettingsService, then
    DebugSettingsWindowController);
  - DevTools and the page info windows, which are child windows: they pass
    their owner window's NSWindow.backdropActiveLook, which reads the
    owner's own WindowMaterialView (as they already take the owner's
    themeScope);
  - BrowserDebugWindow passes nil: it has no entry point.
- ActiveLookScope.install adds a marker method to NSWindow with
  class_addMethod. Only the first install can add it, so the getter hook is
  installed once per process and a later scope (a test's) never stacks a
  second hook over the first. A stacked hook could push the reader past the
  16-frame forcingDepth.
- Tests pass activeLook: nil where they built these windows.

Not compiled here (no Swift on the agent VM); the fleet compile-check of the
pushed head follows.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 06b2074b Deployed Oct 29, 2026 by teamleaderleo via namespace autofix #5998
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