Skip to content

Settings store imports appearance at init instead of live-applying it (restores 70bcbda20e) - #8913

Merged
austinywang merged 1 commit into
manaflow-ai:mainfrom
ejc3:fix/settings-store-appearance-decoupling
Jul 27, 2026
Merged

austinywang merged 1 commit into
manaflow-ai:mainfrom
ejc3:fix/settings-store-appearance-decoupling

Conversation

@ejc3

@ejc3 ejc3 commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Launch the app with an appearance mode in cmux.json and the settings file store applies it live while the store singleton is still initializing — reaching appearance application and terminal-theme synchronization from inside init, which is exactly the re-entrancy 70bcbda removed in May. The store is supposed to only import the value into UserDefaults; the app-lifecycle observer owns live application.

What happened: 70bcbda ("fix: decouple settings appearance replay from Ghostty reload") shipped the decoupling and added KeyboardShortcutSettingsFileStoreStartupTests to pin it. Six days later, e788e56 ("Add Agent Hibernation") re-added the entire pre-decoupling machinery verbatim inside KeyboardShortcutSettingsFileStore.swift — the appearanceEnvironment field, the synchronizeManagedAppearanceTerminalTheme threading, and both live-apply branches — without touching those tests. The diff shape reads as a rebase that resolved against the older version of the file; nothing in the hibernation feature uses the re-added machinery, and no other file references it. The pinning suite has been red since (18 of 24 tests), which dispatch-only CI never surfaced.

This restores the decoupled shape on today's file: the appearance key is guarded out of managed-default side effects at the source, both live-apply branches are gone, and the dead parameter chain comes out end to end. Newer code that grew around the clobber (the legacy warn-before-quit parameters, the language-override branch, today's reload() return type) is preserved untouched.

One test-side change rides along: the startup suite's mock records every live apply, including the global appearance-defaults observer's legitimate reaction to the UserDefaults writes the store makes while importing. The suite now stops that observer in setUp and restarts it in tearDown, so it measures only what the store itself does.

Verified on this branch, each suite alone against a fresh test build: KeyboardShortcutSettingsFileStoreStartupTests 24/24 green (18 failures on main), and AppearanceSettingsTests — the suite pinning the observer half of the contract — 24/24 green.


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


Summary by cubic

Stop live-applying appearance during settings store initialization. The store now only imports appearanceMode into UserDefaults; the app lifecycle observer applies it after launch to prevent re-entrancy.

  • Bug Fixes

    • Removed live application of appearance from KeyboardShortcutSettingsFileStore init/reload and guarded the appearance key out of managed-default side effects.
    • Updated startup tests to pause the global appearance UserDefaults observer in setUp and resume in tearDown to measure only the store’s behavior.
  • Refactors

    • Removed appearanceEnvironment, appearance/terminal-theme sync code, and the synchronizeManagedAppearanceTerminalTheme plumbing; simplified side-effect types and method signatures.

Written for commit 61fde69. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved settings restoration and application behavior by removing inconsistent appearance synchronization handling.
    • Ensured appearance preference observation is correctly paused during settings resets and restored afterward.
  • Refactor
    • Simplified internal settings side-effect processing for more predictable startup and reload behavior.

70bcbda decoupled settings appearance replay from Ghostty reload:
the file store imports appearanceMode into UserDefaults and the
app-lifecycle observer owns live application, so the store cannot
re-enter Ghostty while this singleton initializes. e788e56 (Agent
Hibernation) re-added the pre-decoupling machinery verbatim in a
rebase, without touching the tests that pin the decoupled contract.
This restores the decoupling, and the startup suite now silences the
global appearance-defaults observer so it measures only what the
store itself does.
@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 14813fa1-7e81-4e74-adcd-63b2c0102963

📥 Commits

Reviewing files that changed from the base of the PR and between da8a58a and 61fde69.

📒 Files selected for processing (2)
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift

📝 Walkthrough

Walkthrough

CmuxSettingsFileStore removes appearance synchronization state from initialization, reload, managed settings restoration, and deferred side-effect handling. Startup tests now isolate defaults resets from the appearance observer and restore observation during teardown.

Changes

Managed settings refactor

Layer / File(s) Summary
Reload and initializer contracts
Sources/KeyboardShortcutSettingsFileStore.swift
Removes the stored appearance environment and the appearance synchronization parameter from initialization, reload, reapplication, and managed-settings application paths.
Managed settings side-effect flow
Sources/KeyboardShortcutSettingsFileStore.swift
Simplifies backup restoration and managed default side effects to track only defaults keys, removing appearance-mode-specific application logic.
Observer test lifecycle
cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift
Stops the appearance defaults observer during test resets and restarts it during teardown.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: austinywang

🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: importing appearance at init instead of live-applying it.
Description check ✅ Passed The description covers the summary, rationale, and testing results in enough detail, even though demo video and checklist sections are missing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Diff only removes appearanceEnvironment/synchronization plumbing; no new MainActor/Sendable isolation debt was introduced in production code.
Cmux Swift Blocking Runtime ✅ Passed PASS: The patch removes appearance-sync plumbing and adds only test observer stop/start; no new waits, sleeps, sync calls, polling, or locks were introduced.
Cmux Browser Automation Off-Main ✅ Passed Diff only touches keyboard-shortcut settings store and its startup tests; no browser socket automation, routing, or policy-test files changed.
Cmux Expensive Synchronous Load ✅ Passed Patch only removes appearance-sync plumbing and tweaks test observer setup; no heavy agent-history loader or broad parse was added on an interactive path.
Cmux Cache Substitution Correctness ✅ Passed The patch removes appearance live-apply plumbing but persistence/restore paths still read fresh from UserDefaults; no authoritative read was replaced by a stale cache.
Cmux No Hacky Sleeps ✅ Passed Diff only changes Swift store logic and test setup; no sleeps, timers, polling, or wall-clock delays were introduced, and the rule excludes Swift/test scaffolding.
Cmux Algorithmic Complexity ✅ Passed The diff only removes dead appearance side-effect plumbing and adds test scaffolding; no new scalable scans or batch rescans were introduced.
Cmux Swift Concurrency ✅ Passed PASS: The patch removes appearance-related async plumbing (Task/DispatchQueue/Combine path) and only adds XCTest observer setup/teardown; no new legacy async patterns were introduced.
Cmux Swift @Concurrent ✅ Passed No async/concurrent annotations or heavy async UI call sites were added; the diff only removes appearance live-apply plumbing and adjusts test observer setup.
Cmux Swift Package Boundaries ✅ Passed The diff only removes app-specific appearance plumbing and adjusts tests; it doesn't add or expand reusable domain logic in the app target.
Cmux Swiftpm Lockfiles ✅ Passed PR only changes source and test files; no .gitignore, Package.swift, Package.resolved, or Xcode package-reference files are in diff.
Cmux Swift Logging ✅ Passed Diff adds no print/debugPrint/NSLog or new file logging; existing Logger remains nonisolated private let and unchanged.
Cmux User-Facing Error Privacy ✅ Passed Diff only removes appearance-sync plumbing and adds a developer comment; no user-facing error, alert, or recovery copy was introduced or changed.
Cmux Full Internationalization ✅ Passed The PR only removes appearance-plumbing code and adds a test-only observer comment; no new user-facing strings or locale assets were introduced.
Cmux Swiftui State Layout ✅ Passed No new SwiftUI state/layout patterns were added; the diff only removes store plumbing and tweaks test observer setup. Existing ObservableObject/@published state is untouched legacy code.
Cmux Architecture Rethink ✅ Passed PASS: The PR removes the store’s appearance live-apply/sync path, keeps UserDefaults import as the owner, and limits observer stop/start to test-only synchronization.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only changes settings-store logic and tests; no NSWindow/NSPanel/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes appear in the diff.
Cmux Source Artifacts ✅ Passed Only hand-written source/test files changed; no logs, temp dirs, build output, or other artifacts appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production diff only removes appearance live-apply plumbing; no debug/test-only accessor, wrapper, or widened seam was added.
Cmux No Ambient Global State ✅ Passed PASS: The diff removes appearanceEnvironment plumbing and only uses an existing AppearanceSettingsUserDefaultsObserver.shared in tests; no new ambient global surface is added.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR restores lifecycle-owned appearance application.

  • The settings file store now imports managed appearance values into UserDefaults without directly applying UI or terminal-theme changes.
  • Appearance-specific live-apply state and parameter threading are removed from the store.
  • Startup tests temporarily stop the global defaults observer so they measure only store-owned behavior.

Confidence Score: 5/5

The PR appears safe to merge with no actionable defects identified.

Startup still reads and applies the appearance imported into UserDefaults, while post-launch file reloads write through UserDefaults with the lifecycle observer active to update both application and terminal appearance.

Important Files Changed

Filename Overview
Sources/KeyboardShortcutSettingsFileStore.swift Consistently removes direct appearance application while preserving startup import and observer-driven post-launch updates.
cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift Isolates store behavior from the global appearance observer during startup tests.

Reviews (1): Last reviewed commit: "settings: import appearance at store ini..." | Re-trigger Greptile

@austinywang
austinywang merged commit 18396f2 into manaflow-ai:main Jul 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants