Skip to content

Autosync: decouple pull cadence from push quiet window - #690

Merged
fiskus merged 17 commits into
mainfrom
feat/autosync-settings-decouple
May 21, 2026
Merged

Autosync: decouple pull cadence from push quiet window#690
fiskus merged 17 commits into
mainfrom
feat/autosync-settings-decouple

Conversation

@fiskus

@fiskus fiskus commented May 20, 2026

Copy link
Copy Markdown
Member

Summary

Shipping as v0.18.1 — disk JSON stays backward compatible, so this is a UX iteration on the autosync settings popup rather than a new feature.

  • Splits AutosyncSettings into nested pull: PullSettings { enabled, focused_secs, unfocused_secs, closed_secs } and push: PushSettings { enabled, idle_timeout_secs }. The disk JSON shape stays flat (via #[serde(flatten)]) so existing 0.18.0 files load unchanged.
  • The publish-branch quiet window now reads push.idle_timeout_secs (default 30 s) instead of cadence_for_mode(...). Pull cadence and push quiet window are now independent knobs.
  • The Settings popup collapses to two numeric inputs — Pull interval and Wait after last edit before publishing. The closed-window row + the "takes effect once tray icon ships" hint are hidden (still on disk for forward compatibility).
  • update_autosync_settings becomes a merge over disk state: it takes a single AutosyncSettingsData arg, validates zero, and preserves closed_secs flowing through untouched.
  • Removed the early-alpha migration code (LEGACY_FILE_NAME, rename step, #[serde(alias = "enabled")], any_enabled() helper) — 0.18.0 already shipped the new file name and flat schema.

Behaviour change worth flagging

For users running an unfocused window on 0.18.0, the quiet window shrinks from 120 s to a constant 30 s. Quiet on the focused window path stays at 30 s. The new idle_timeout_secs field defaults to 30 and is editable in the popup.

Test plan

  • cargo test --workspace — 581 passed / 0 failed / 1 ignored
  • cargo clippy --workspace -- -D warnings — clean
  • rumdl check . --respect-gitignore — clean
  • New unit tests cover: nested round-trip, 0.18.0-shaped JSON load with default idle_timeout_secs, missing-keys default to false, publish defers while inside the idle window, focused→pull_interval projection on divergent files, merge preserves closed_secs, validation rejects zero in either numeric field
  • Manual: launch quilt-sync, open Settings → Autosync, verify two inputs render with current values and Save persists
  • Manual: edit autosync_settings.json to give focused_secs and unfocused_secs different values, reopen Settings, verify Save unifies them (UI ties focused == unfocused) while closed_secs survives untouched

Greptile Summary

This PR decouples the autosync push quiet window from the pull cadence by splitting AutosyncSettings into nested PullSettings and PushSettings structs. The disk JSON shape remains flat via #[serde(flatten)], so 0.18.0 files load unchanged, and idle_timeout_secs defaults to 30 s when missing. The Settings popup is simplified to two numeric inputs, the legacy migration code is removed, and update_autosync_settings is refactored to merge over disk state so that closed_secs is preserved without appearing in the UI.

  • The push-side quiet window now reads push.idle_timeout_secs (constant 30 s default) instead of cadence_for_mode(...), meaning unfocused-window users who were on 0.18.0 will see their push quiet window drop from 120 s to 30 s — this behavioral change is clearly documented in the PR description and changelog.
  • The update_autosync_settings command now holds the SharedAutosyncSettings write lock across the async disk save in order to keep the disk and in-memory state atomic; this is correct but may briefly block the tick loop if it fires concurrently with a settings save.

Confidence Score: 4/5

Safe to merge — the refactor is well-tested, backward-compatible on disk, and the one concern (holding a write lock during file I/O) is unlikely to cause observable problems in practice given the small file size and infrequent save operations.

The settings restructure is clean and comprehensively tested (round-trip, 0.18.0 compat, missing-key defaults, merge-preserves-closed_secs, idle-window deferral). The only code-level concern is that update_autosync_settings now holds the SharedAutosyncSettings write lock across the async save() call, whereas previously the save ran before the lock was acquired. The tick loop reads settings under a read lock, so a concurrent tick could block briefly during a settings save. Given the file is tiny and user-triggered saves are infrequent, this is not expected to surface as a user-visible issue.

quilt-sync/src-tauri/src/commands.rs — the write lock scope around the async save is the only area that warrants a second look.

Important Files Changed

Filename Overview
quilt-sync/src-tauri/src/autopull/settings.rs Core refactor: AutosyncSettings now nests PullSettings and PushSettings with #[serde(flatten)] for backward-compatible flat JSON. Well-tested with seven unit tests covering round-trips, defaults, and backward compatibility.
quilt-sync/src-tauri/src/commands.rs update_autosync_settings now takes a single AutosyncSettingsData, validates zeros, and merges over disk state to preserve closed_secs. The write lock on SharedAutosyncSettings is held across the async disk save — a deviation from the original pattern where save happened outside the lock.
quilt-sync/src-tauri/src/autopull/tick.rs quiet_window now reads push.idle_timeout_secs directly instead of cadence_for_mode(), decoupling push timing from pull cadence. New unit test confirms publish is deferred while inside the idle window even when pull cadence is shorter.
quilt-sync/ui/src/commands.rs Frontend command wrapper updated to match new IPC shape — single AutosyncSettingsData struct passed under a 'settings' key. AutosyncSettingsData gains Serialize to allow it to be sent over the IPC boundary.
quilt-sync/ui/src/pages/settings.rs Settings popup collapsed from three numeric inputs to two. Closed-window row removed from UI while disk field is preserved via merge. Validation and Reset-to-defaults correctly updated.
quilt-sync/src-tauri/src/autopull.rs cadence_for_mode signature narrowed from &AutosyncSettings to &PullSettings, and the watcher loop passes settings.pull. Minor cleanup: LogReporter allow(unused_imports) removed.

Sequence Diagram

sequenceDiagram
    participant UI as UI (settings.rs)
    participant FECmd as ui/src/commands.rs
    participant BECmd as commands.rs (backend)
    participant Disk as autosync_settings.json
    participant Watcher as Watcher / Tick

    UI->>FECmd: update_autosync_settings(AutosyncSettingsData)
    FECmd->>BECmd: tauri::invoke(update_autosync_settings)
    BECmd->>BECmd: validate_autosync_settings_data()
    BECmd->>BECmd: autosync_settings.write() [WRITE LOCK acquired]
    BECmd->>BECmd: merge_autosync_settings_data(current, incoming)
    BECmd->>Disk: merged.save() [async I/O while lock held]
    Disk-->>BECmd: Ok
    BECmd->>BECmd: "*current = merged"
    BECmd->>BECmd: [WRITE LOCK released]
    BECmd->>Watcher: clear_all_paused() [if off-on edge]
    BECmd-->>UI: Ok(())

    Note over Watcher: On each tick
    Watcher->>BECmd: settings.read() — pull.enabled / push.enabled
    Watcher->>BECmd: settings.read() — push.idle_timeout_secs
    Watcher->>BECmd: "settings.read() — cadence_for_mode(&pull, mode)"
Loading

Reviews (1): Last reviewed commit: "chore(autosync): retarget release as v0...." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@fiskus
fiskus marked this pull request as ready for review May 21, 2026 12:10
Comment thread quilt-sync/src-tauri/src/commands.rs
@fiskus
fiskus merged commit 51866ff into main May 21, 2026
4 checks passed
@fiskus
fiskus deleted the feat/autosync-settings-decouple branch May 21, 2026 13:11
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.

1 participant