Skip to content

SettingsFeature: every .binding does a full-file persist + full effect fanout with no debounce #626

Description

@onevcat

Problem

The catch-all case .binding persists on every mutation (SettingsFeature.swift:300-306persist at :468-486): a synchronous whole-file JSON write of @Shared(.settingsFile) (SettingsFilePersistence.swift:119-133 has no throttle, unlike Sharing's FileStorageKey), one settings_changed analytics event, and a .delegate(.settingsChanged) that fans out to ~8 effects in AppFeature.swift:433-510 (terminal IPC, dock badge, GitHub toggle, worktree watcher, Sparkle, …).

Failure scenario

Dragging the tint ColorPicker (AppearanceSettingsView.swift:58-60, bound straight to $store.windowTintCustomColor) or typing in the worktree base-path field emits one full-file write + full fanout + one analytics event per frame/keystroke — main-thread hitching and heavily polluted analytics.

Suggested fix

Debounce the persist/settingsChanged effect (.debounce(id:)), or give continuous controls (color picker, text fields) a commit-only action while keeping instant persistence for discrete toggles.

Origin

TCA-conventions audit of the Settings area (2026-07-30), agent finding — the write path is confirmed by inspection; measure the actual hitching before choosing the debounce window.

Metadata

Metadata

Assignees

No one assigned

    Labels

    cleanupDead code, drift, and small hygiene fixes

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions