Repository navigation
fix(cmux-next checks): clear the package-deps and crash-ratchet base reds - #28036
Conversation
…cks job (package deps, crash ratchet) Package dependency lists sorted: CmuxNextAccounts' TeamInviteConsentWindow uses DemandTimer from CmuxNextWakeups (a0ee135); the target now declares it. Crash safety: six crash-ratchet rows rose on the tip. Each new hit is fixed in the code, not waived away: - cmux-tui-core unwrap 1149 -> 1150 (915bab1): the roster's agent_records read recovers a poisoned lock (PoisonError::into_inner), as its 340 siblings do. - CmuxNextSidebar dynamic_dispatch 3 -> 5 (f97775b): the disclosure chevron sets its turn as a typed CATransform3D, not by key-value coding. - MessagesLabHome index_subscript (banned) 0 -> 1 (6ac0d64): the row bitmap write takes its slot from out.checkedIndex on the same line again. - MessagesLabHome unchecked 14 -> 16 and unchecked.waived 1 -> 4 (6ac0d64): PaletteScope's main-thread slot, process palette and box table, and Fixture.baseGeneration, move from nonisolated(unsafe) statics into one OSAllocatedUnfairLock. Render workers read the process palette and the base generation while the main thread writes them, so this was a real data race. PaletteBox keeps @unchecked Sendable with a reviewed crash-allow (two lets set before publication): recorded with --record-waivers, waived 1 -> 2. - CmuxNextDesign unchecked.waived 3 -> 4 (17d64ea, #27385): the Dock policy observation keeps its object in an OSAllocatedUnfairLock (uncheckedState) instead of a hand-rolled @unchecked Sendable holder. Patches/ for Fixture, Transcript and WindowView regenerated with sync-messageslab.sh --write-patches (WindowView's patch was already stale on the tip); --check passes. The arch ratchet's global_mutable_statics falls by three; the one lock is a reviewed exception. Red on base b3587f5, green here: python3 scripts/cmux-next/crash_ratchet.py (6 rows), python3 scripts/cmux-next/check-package-dependency-lists.py (CI run on 49d2105). Sidebar-Look: no visual change
|
Owner notice (the pre-push gate names both areas). This PR touches them only to clear the crash ratchet base red:
|
…ble, its owner and its expiry (2026-11-13) A checked Sendable PaletteBox needs a Sendable FixtureTheme, and FixtureTheme.swift:28 holds a CGGradient, which the SDK does not mark Sendable: the fleet probe e72b1f95374d27da0c9f8e94 (scratch 78d5dd9) failed with "stored property 'gradient' ... contains non-Sendable type 'CGGradient'" (NSColor passed). The waiver stays, recorded as before.
|
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)
|
|
Review (independent review subagent, Opus 5.5): SHIP at 98a7c2c Compile: fleet job b9abe4f397655cc8ce7f0615 at this head: CmuxNext (with test targets), app, cmux-tui all ok. publish-before-share proof: confirmed. PaletteBox's init is fileprivate, and Non-blocking follow-ups: (1) arch-ratchet.py --update to lower the recorded global_mutable_statics total; (2) make PaletteBox checked Sendable by building the CGGradient from gradientStops at draw time, before the 2026-11-13 expiry; (3) the crash ratchet does not count OSAllocatedUnfairLock(uncheckedState:) or withLockUnchecked (a gap in the rule, not a defect here). |
…ecks-red # Conflicts: # plans/cmux-next/arch-ratchet.json
|
Found 22 test failures on Blacksmith runners: Failures
...and 12 more test failures. View all on Blacksmith
|
|
Review (independent review subagent, Opus 5.5): SHIP at 5f14c23 merge-only delta of feat tip 70b40c7, conflict in arch-ratchet.json resolved by keeping both 2026-10-30 entries.
exception reviewed: ok (global_mutable_statics, owner and expiry 2026-11-13, unchanged from 98a7c2c) Static checks at this head (reviewer ran them):
compile 03f0c961: running; the lead adds ready-to-land only after it passes. |
|
Compile of the exact head 5f14c23 passed: fleet job 03f0c961a98a3e0b45c9317b, CmuxNext ok, app ok, cmux-tui ok. ready-to-land is removed and added again after the merge of the feat tip 70b40c7. The remaining crash-ratchet row (MessagesLabHome index_subscript in HomeMapping.swift, from feat commit 71076ff, not a file of this PR) goes to a follow-up PR. |
|
State at 07:5xZ: the only red checks are base reds, not this PR's own.
|
|
Independent review (codex gpt-6.1-sol high; Astra via SR2 hung): SHIP at 5f14c23 No concrete correctness defects found. PaletteScope’s lock is not held across drawing/AppKit calls, generation arithmetic is preserved, chevron and DockBadge behavior remain correct, and all three Catalyst patches reverse-apply cleanly to the vendored sources. No builds or tests were run, per instruction. Coordinator check (merging under the rulebook's red-fix exception for a teammate PR that fixes a base red): |
|
Shipped in:
|
… 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.
…ring PaletteBox waiver goes away (#28259) * fix(home): HomeMapping caches a thread root with updateValue (crash ratchet base red) 71076ff added `mapped.entries[root] = .some(entry)` in HomeMapping.roots, a subscript write that the crash ratchet counts as a banned index_subscript in MessagesLabHome (a dictionary write cannot trap, but the module also declares an `entries` that is not a dictionary). The cache now writes with `updateValue(entry, forKey:)`, as the same function does at line 45. The value is the same: a found root, or nil for a miss (cached too). Red on base 84bca8e, green here: python3 scripts/cmux-next/crash_ratchet.py ("banned index_subscript in .../Cmux/HomeMapping.swift: 1 hit(s)"). * fix(home): PaletteBox and FixtureTheme are checked Sendable; the PaletteBox waiver goes away #28036 kept PaletteBox `@unchecked Sendable` with a crash-allow that expires 2026-11-13, because FixtureTheme stored a CGGradient, which the SDK does not mark Sendable (fleet probe e72b1f95374d27da0c9f8e94). FixtureTheme.Colors now keeps the sent bubble's gradient stops ([HomePalette.GradientStop], Sendable) and makes the CGGradient from them when a bubble draws. FixtureTheme, Colors and PaletteBox are checked Sendable, so the crash-allow is gone. PaletteScope's lock state is Sendable too, so it uses OSAllocatedUnfairLock(initialState:) and withLock, not uncheckedState / withLockUnchecked. crash_ratchet.py --update-baseline: MessagesLabHome unchecked.waived 2 -> 1. * test(home): OutgoingGradientCostBench measures one sent-bubble gradient creation (R10 number) Prints nanoseconds per creation (p50/p95/p99/max over 20,000) for the draw-time path (Colors.outgoingGradient: stops -> CGColor -> CGGradient) and for a gradient from ready CGColors. A measurement, not a gate. * fix(home): the theme keeps its gradient's ready CGColors; a draw only allocates the CGGradient The Swift 6 probe (job cc4b222b913bea77571982d7) compiled a Sendable struct of [CGColor]: CGColor is Sendable, CGGradient is not. So FixtureTheme.Colors makes its CGColors and locations once, at build time, and outgoingGradient makes only the CGGradient from them. OutgoingGradientCostBench measures that per-draw path, and the HomeColor-stops path for comparison. * test(home): OutgoingGradientCostBench type-checks in reasonable time Bench be852e69acae5d2126be56ed failed to compile its own file (OutgoingGradientCostBench.swift:20: the compiler is unable to type-check this expression in reasonable time). The stop list is now a plain loop over typed locals, and the report lines are built from named values. * test(home): a palette's draws must share one gradient object (red); the draw bench replaces the creation bench The draw bench (fleet step a8c873017d9189e8692656f7) showed a new CGGradient per draw costs 10.8 µs more per bubble at p99 than a reused one: CoreGraphics does about 10 µs of work on a gradient object's first draw. Creation alone is 0.5 µs, so OutgoingGradientCostBench measured the wrong thing; it is removed. PaletteGradientReuseTests.twoDrawsInOnePaletteUseOneGradient fails at this commit: Fixture.outgoingGradient makes a new gradient for every draw. OutgoingGradientDrawCostBench times lookup or creation plus the draw, for the app's path and for a new gradient per draw, in a warm and a fresh context. * fix(home): a palette makes its sent-bubble gradient once; every draw in it reuses that object The draw bench (fleet step a8c873017d9189e8692656f7) showed a new CGGradient per draw costs 10.8 µs more per bubble at p99 than a reused one. PaletteBox now makes the themed gradient once (outgoingGradient), and Fixture.outgoingGradient returns the effective palette's gradient. The measured (non-themed) gradients were already static lets. CGGradient is not Sendable in the SDK, so PaletteBox keeps it in a one-let SharedGradient wrapper (@unchecked Sendable, with a crash-allow that names CGGradient's immutability, an owner and a review date): recorded with --record-waivers, MessagesLabHome unchecked.waived 1 -> 2, the same count as on the base (this PR still removes the broad PaletteBox waiver). PaletteGradientReuseTests.twoDrawsInOnePaletteUseOneGradient goes green.
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
The
cmux-next checksjob is red on everyfeat-cmux-nextpush since 8ac1d73, so every PR that merges the base inherits it (83 PRs wait withready-to-land). This PR fixes two of the three red checks. The third (Check the app FFI pin) needs a published artifact and is not in this PR (see the end).Package dependency lists sorted.
CmuxNextAccountsimportsCmuxNextWakeups(DemandTimerinTeamInviteConsentWindow, from a0ee135) but did not declare it. The target now declares it.ui->coreis an allowed layer edge.Crash safety (crash ratchet). Six rows rose. Each new hit is fixed in the code:
cmux-tui-coreunwrap 1149 -> 1150agent_records.lock()recovers a poisoned lock (unwrap_or_else(PoisonError::into_inner)), like the other 340 sites in the crateCmuxNextSidebardynamic_dispatch 3 -> 5CATransform3DMakeRotation, not withsetValue(_:forKeyPath:). The turn is the glyph's only transform, so the value is the same.MessagesLabHomeindex_subscript (banned) 0 -> 1out.checkedIndex(i)on the same line againMessagesLabHomeunchecked 14 -> 16, unchecked.waived 1 -> 4PaletteScope's main-thread slot, process palette and box table, andFixture.baseGeneration, move fromnonisolated(unsafe)statics into oneOSAllocatedUnfairLock. Render workers read the process palette and the base generation while the main thread writes them, so this was a real data race.PaletteBoxkeeps@unchecked Sendablewith a reviewedcrash-allow(twolets set before the box is published). This is recorded with--record-waivers: waived 1 -> 2.CmuxNextDesignunchecked.waived 3 -> 4OSAllocatedUnfairLock(uncheckedState:), not in a hand-made@unchecked Sendableholder. The lifetime does not change: the object stays alive until termination and is then released.The
Patches/files for Fixture, Transcript and WindowView are made again withsync-messageslab.sh --write-patches. The WindowView patch was already stale on the tip. Now--checkpasses. The arch ratchet'sglobal_mutable_staticsrow goes down by three. Its one new lock site has a reviewed exception inarch-ratchet.json.Owners: the sidebar owner (a590) for
DisclosureChevronView(no visual change) and PL-daemon for the oneagent_roster_fold.rsline.Testing
python3 scripts/cmux-next/crash_ratchet.py: red on base b3587f5 (6 rows, the same as the CI log of 49d2105). On the head it printscrash-ratchet: ok.python3 scripts/cmux-next/check-package-dependency-lists.py: red in CI on base (CmuxNextAccounts: imports CmuxNextWakeups but does not declare it). It passes on the head. Its self-test passes too.scripts/cmux-next/check-crash-safety.sh: ok.sync-messageslab.sh --check: ok.python3 scripts/cmux-next/prepush-gate.py: no new violations.b9abe4f397655cc8ce7f0615(cmux-ci compile-check --app --package CmuxNext --recipe-version 2): CmuxNext (with test targets), app and cmux-tui all ok. The first head 9d40107 also compiled (job77d862cc17adfe165114e0c0).@unchecked Sendablewaiver (MessagesLabHome unchecked.waived 1 -> 2): a checked Sendable needs a Sendable FixtureTheme, and FixtureTheme.swift:28 holds a CGGradient, which the SDK does not mark Sendable (Swift 6 probe jobe72b1f95374d27da0c9f8e94). The crash-allow names its owner and expires 2026-11-13.Observed / Not run
Observed: the static check scripts above, red on the base and green on the head, run on cmux-orchestrator-1. Not run: Swift or Rust tests. The changes keep behavior the same (lock-guarded reads of the same values, the same transform value, the same lifetime). DockBadge's lifetime tests and the MessagesLab palette tests run in the next fleet test round.
Not in this PR:
Check the app FFI pin. The FFI sources changed after pin 619b1a3. The tip's FFI sources are the same as at b02c564. Theapp FFI releaserun for that commit (40992288584) has been queued forblacksmith-6vcpu-macos-26since 02:32Z, and 21 jobs wait for that label. When the run builds, its publish job releasescmux-app-ffi-b02c5645478...and its last job opens the re-pin PR. That PR moves the pin. The bot PR #26434 (ff720d8) is out of date.Changelog
none
Proof
No capture: there is no visual change. The chevron gets the same transform through a typed setter, and the other changes are lock and ratchet changes.
Summary by cubic
Fixes the
cmux-next checksjob, which has been red on everyfeat-cmux-nextpush, so every PR that merges the base inherits it (83 PRs wait withready-to-land). The package-deps and crash-ratchet checks now pass; the third check (app FFI pin) needs a published artifact and is not in this PR.Package dependencies
CmuxNextAccountsnow declaresCmuxNextWakeups, which it imports (DemandTimerinTeamInviteConsentWindow) but never declared.Crash ratchet
cmux-tui-core: the roster'sagent_recordsread recovers a poisoned lock withunwrap_or_else(PoisonError::into_inner), matching the other 340 sites in the crate.CmuxNextSidebar: the disclosure chevron sets its turn as a typedCATransform3DMakeRotationinstead ofsetValue(_:forKeyPath:), with no visual change (same transform value).MessagesLabHome: the row bitmap write gets its slot fromout.checkedIndex(i)on the same line again.MessagesLabHome:PaletteScope's main-thread slot, process palette, box table, andFixture.baseGenerationmove fromnonisolated(unsafe)statics into oneOSAllocatedUnfairLock, fixing a real data race where render workers read the process palette and base generation while the main thread writes them.PaletteBoxkeeps@unchecked Sendablewith a reviewedcrash-allow(twolets set before the box is published).CmuxNextDesign: the Dock policy observation keeps its object in anOSAllocatedUnfairLock(uncheckedState:)instead of a hand-made@unchecked Sendableholder, with the same lifetime.The Fixture, Transcript, and WindowView patches were regenerated with
sync-messageslab.sh --write-patches(WindowView's was already stale), the arch ratchet'sglobal_mutable_staticsrow falls by three with one reviewed exception, and the static check scripts are red on the base and green on this head. Swift and Rust tests were not run.Written for commit 9d40107. Summary will update on new commits.