Skip to content

Settings child features persist inside cancellable .run effects; edits can be silently dropped on sidebar switch #622

Description

@onevcat

Problem

AppFeature nils the Settings child states (repositorySettings, globalCustomCommands, agentProfiles) on every setSelection (AppFeature.swift:381-419), and ifLet cancels all in-flight child effects when child state goes nil. Several child features perform their @Shared persistence and file operations inside .run effects, so a sidebar switch races the write:

  • GlobalCustomCommandsFeature.swift:51-57persist in .run
  • RepositorySettingsFeature.swift:450-464 (persistAppearance), :470-483 (removeAbandonedUserImage), :280-290 (importUserImage)

Failure scenario

Edit a global command (or pick a repo icon/color), then immediately click another row in the Settings sidebar. The .run effect is cancelled before the @Shared write / file operation executes: the edit is silently lost (reappears on next load), and for the appearance path the imported asset bookkeeping can leak. The delegate send is cancelled too, so the live app never applies the change.

Suggested fix

Perform @Shared writes synchronously in the reducer (the pattern SettingsFeature.persist already uses, and AgentProfilesFeature.persist was moved to on the agent-profiles branch), keeping effects only for delegate sends and genuinely async work. Destructive file work should live at a level that survives the pane teardown.

Origin

TCA-conventions audit of the Settings area (2026-07-30), agent finding — cancellation semantics confirmed for the equivalent AgentProfilesFeature case (fixed on the agent-profiles branch); the listed sites should be re-verified line by line when picking this up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions