aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md48
1 files changed, 47 insertions, 1 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 9957ba8..2663b44 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -127,7 +127,7 @@ taking that too literally.
| 68 | A forwarded subject gets no `passed` tag | workflow | S | open; no subject rule exists, measured 2026-08-11. Decision needed: display mark (XS) or write the flag (S, syncs out) |
| 69 | `passed` and `replied` read as words where every other state is a glyph | presentation | S | open; depends on 68 for what `passed` means |
| 70 | Pane icons are a private set where the main window uses the system theme | presentation | M | open |
-| 71 | A toolbar action does not sync, so the edit sits until the next cron run | workflow | S | open; user decision on the delay |
+| 71 | A toolbar action does not sync, so the edit sits until the next cron run | workflow | S | **done** 2026-08-11; 2s default, `auto_sync_delay_ms` |
| 72 | No khard/khal integration | workflow | ? | open, unspecified; the user places it after send, so v2 at the earliest |
| 73 | This backlog is past four thousand lines | maintenance | S | open |
@@ -4447,6 +4447,52 @@ lock is held. The undo stack has to survive it, which is what item 35 built.
**Size: S** once the delay is chosen.
+**Done 2026-08-11.** The delay is 2000ms by default, chosen by the user, and
+configurable as `auto_sync_delay_ms` in `[general]`. It follows
+`mark_read_delay_ms` exactly, including that zero and negative are not errors:
+zero syncs on the next trip through the event loop and any negative value
+restores the pre-0.16.0 behaviour, which is the switch for a user who wants only
+their cron job.
+
+Armed from `onTagsApplied`, where a write is CONFIRMED and the pending count is
+already current, rather than where one is sent: a sync scheduled for a write the
+worker went on to reject would run for nothing. It is a debounce and not a
+schedule, restarted by each confirmed edit, because "mark all read" confirms one
+write per thread in the view and an arm-per-edit timer would be the storm of
+syncs the debounce exists to prevent. Nothing is armed when the delay is
+negative, when no sync command is configured, or when the pending count is zero,
+which is the case where an edit was netted against its own inverse (item 28).
+
+The constraints held: `runAutoSync` skips rather than queues when
+`m_externalSyncBusy` or a local sync is running, and the edits stay pending
+rather than being lost. Item 35's refresh keeps the undo stack.
+
+Four tests in `test_mainwindow` and four in `test_config`, each mutation-checked:
+removing the `scheduleAutoSync()` call, honouring a negative delay, dropping the
+nothing-pending guard and dropping the already-running guard each failed a test.
+**Follow-up, found by hand testing the same day.** Reading a message in the
+Unread view, the automatic mark-read tagged it, the automatic sync fired two
+seconds later, and the message pane went blank. The stale-thread notice (item 35)
+exists for exactly this and was not the problem: `onSyncFinished` called
+`runCurrentQuery()` where the cron path calls `refreshCurrentQuery()`, and a
+re-run clears the model, the undo stack and the pane, so there was nothing left
+for the notice to describe. The two paths had no reason to differ; before item 71
+a local sync followed only a click on Sync, where blanking was at least
+explicable, so the difference went unnoticed. `onSyncFinished` now refreshes.
+
+Its test asserts on the UNDO STACK, not on the pane. Both paths issue a queued
+query that `test_mainwindow` has no worker to answer, so the pane ends up blank
+either way and an assertion on it passes against both; the undo stack is cleared
+by one and kept by the other, so it names which path ran. Mutation-checked by
+restoring `runCurrentQuery()`.
+
+Two traps met while writing them and worth keeping. The helper first wrote
+`general/auto_sync_delay_ms` and the key silently matched nothing, leaving the
+default in place, exactly the QSettings `[general]` behaviour recorded in
+CLAUDE.md. And a debounce assertion comparing `remainingTime()` before and after
+with `>` is FLAKY, since both reads can land in the same millisecond; assert the
+remaining time went back up near the full interval instead.
+
## 72. No khard/khal integration
**Observed (user, from the notes):** "investigate khard/khal integration (light