Skip to content

fix(theme): stop double PUT /api/theme on token edits (cave-gvtw)#3745

Merged
BunsDev merged 1 commit into
mainfrom
fix/theme-double-put
Jul 24, 2026
Merged

fix(theme): stop double PUT /api/theme on token edits (cave-gvtw)#3745
BunsDev merged 1 commit into
mainfrom
fix/theme-double-put

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 24, 2026

Copy link
Copy Markdown
Member

Problem

Both persistThemeTokens (AppearanceSection's on-change effect) and RemoteThemeController.publishCurrentTheme PUT /api/theme after every token edit — byte-identical tokenOnly payloads (measured double PUT at t=4433 in the cave-hkfq repro). Wasteful, and the second write opens a 409 window if another device writes between them.

Fix

Single-publisher ownership: RemoteThemeController (mounted in the root layout) is the sole change-driven publisher. Every selection, mode flip, and token commit in the settings section already lands in updateAppPreferences; the store notify runs the controller's reconcile, whose runtime signature ([theme.id, resolvedMode, custom]) changes for exactly those edits → one flushAppPreferences() → one PUT (with resolvedMode, which the settings-side PUT never carried).

  • Removed the section's on-change persistThemeTokens effect.
  • Kept persistThemeTokens for the manual Resync to phone button — user-invoked healing when the daemon lost state.
  • Updated the setCustomData identity-preservation comment (still needed for render/reloadKey stability, no longer about echo PUTs).
  • New pins in settings-appearance.test.ts: no void persistThemeTokens() may reappear; the manual-only contract comment must stay.

Validation

  • node --test with alias loader: settings-appearance, theme-token-hex, remote-theme-controller, theme-store, ios-theme-api, ios-theme-override11/11 pass
  • pnpm typecheck clean, pnpm lint clean (design gates included)

Closes bead cave-gvtw.

Every theme selection, mode flip, and token commit in AppearanceSection
writes updateAppPreferences, whose store notify already runs
RemoteThemeController's reconcile -> publishCurrentTheme -> PUT
/api/theme. The section's own on-change effect fired a second,
byte-identical PUT for each edit (measured at t=4433 in the cave-hkfq
repro) and opened a 409 window when another device wrote between the
two.

Drop the settings-side on-change effect and make the controller the
sole change-driven publisher. persistThemeTokens stays for the manual
"Resync to phone" button (user-invoked healing when the daemon lost
state). New source pins keep the effect from being reintroduced and
document the single-publisher ownership.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 24, 2026 04:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Eliminates redundant theme-token publishing by removing the settings-side on-change /api/theme PUT, making RemoteThemeController the sole automatic publisher while keeping a manual “Resync to phone” escape hatch.

Changes:

  • Removed the AppearanceSection useEffect that auto-called persistThemeTokens() on token/theme changes.
  • Updated persistThemeTokens’s doc comment and nearby state-identity comment to reflect the new single-publisher model.
  • Added test pins to prevent reintroducing the automatic persist side effect and to enforce the manual-only contract documentation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/components/settings-shell.tsx Removes the settings-driven auto-publish effect; retains manual resync and updates explanatory comments.
src/components/settings-appearance.test.ts Adds regression tests/pins for the single-publisher ownership model and updates related assertions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +442 to +446
assert.doesNotMatch(
settings,
/void persistThemeTokens\(\)/,
"no automatic persistThemeTokens call may remain — RemoteThemeController is the sole on-change publisher (cave-gvtw double PUT)",
);
@BunsDev
BunsDev merged commit 550d7ab into main Jul 24, 2026
16 checks passed
@BunsDev
BunsDev deleted the fix/theme-double-put branch July 24, 2026 04:51
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