Skip to content

feat(folders): pause one source folder without the others (#94) - #100

Merged
elementalvoid merged 3 commits into
mainfrom
feat/per-folder-pause
Nov 14, 2026
Merged

elementalvoid merged 3 commits into
mainfrom
feat/per-folder-pause

Conversation

@elementalvoid

Copy link
Copy Markdown
Owner

Summary

Per-folder pause (#94). A paused source folder is not scanned, watched, hashed, or uploaded; what it queued stays pending, and an upload already on the wire finishes. Resume scans the folder and drains the queue in the usual order. Pause follows Owner.

source_folder
+  paused            -- stored; migration V15, default off, survives a restart
engine
+  scan: skip paused folders, leaving the last-scan time alone
+  watcher: holds no watch on a paused folder, and ignores a racing event
+  upload: Owner's pause checked with the gate immediately before the request
+  resume: lifting the pause asks the scan loop for a pass
dashboard
+  card: Pause/Resume toggle beside Details; the state reads "Paused"
+  detail: the same toggle, with the reason as an Info notice, never an error
+  global card: paused folders left out of counts, progress, rate and activity

The global pause, a folder pause, and the known-network hold are independent and compose; a global resume leaves folder pauses in place. The tray tooltip is unchanged because it reads the activity state (R8.2). SPEC R8.7/R8.1/§5, GLOSSARY.md, README and CONTRIBUTING are updated.

Closes #94.

Evidence

  • Before: two source folders, no paused state anywhere.
    After: the committed docs/screenshot.png — Archive reads Paused with Resume beside Details, while the global card reads 410 uploaded · 11 pending · 7 failed (Archive's 120 uploaded and 9 queued are left out).
  • All four "To close" tests are in: paused folder's queued item stays off the wire while another folder uploads and resuming uploads it (engine::a_paused_folder_holds_its_queued_item_while_another_folder_uploads); a scan skips a paused folder (engine::a_reconciliation_scan_skips_a_paused_folder_until_it_resumes); store migration (store::a_v14_database_gains_the_folder_pause_column); dashboard card reads Paused and an upload on the wire finishes (dashboard::a_paused_folder_card_lets_the_upload_on_the_wire_finish). Also: global/served compose, mid-upload pause, detail reason, and the global sums.
  • Gates: cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo nextest run --workspace → 964 passed, 2 skipped.

Merge Danger

Door: one-way — migration V15 adds source_folder.paused; a database a user has already migrated is not a supported downgrade path.

Blast Radius: sync engine, state store, dashboard.

A paused folder stops consuming scan, watch, hash and upload work. Rolling back after release would need the schema handled before the binary is downgraded.

A paused folder is not scanned, watched, hashed, or uploaded: the
reconciliation scan skips it (so its last-scan time keeps the pass that
actually ran), the watcher holds no watch on it and ignores any event that
races the change, and the upload gate holds its items immediately before the
request. What it queued stays pending and the resume asks for a scan, which
drains it in the usual order; an upload already on the wire finishes. Pause
follows Owner, so pausing a folder stops exactly what its card counts.

The flag is a stored column, so a restart keeps it and a re-add does not clear
it; a database written before it gains it unpaused. The dashboard card and the
folder detail render one shared Pause/Resume toggle, the card reads Paused, and
the detail names the user's own pause as the reason rather than an error. The
global activity reads Paused only when every folder is paused or the global
pause or network hold is on; the global pause and a folder pause compose.
The seed keeps the two demo folders as they were and adds a third, Archive,
paused, with a settled backlog and the queue the pause holds. The new
dashboard capture shows its Paused card beside the two syncing ones, and the
global card leaves the paused folder out of its counts.

The capture was taken with the recipe in CONTRIBUTING.md under Xvfb with
lavapipe: 1200x900, 6467 colours, so the frame is not blank.
The test bound an ephemeral port and released it, then expected the connect
to be refused. In parallel that port can be rebound by another test's server
before the connect: its `about` then answered, and its request landed in the
other server's log, which broke `every_endpoint_the_client_builds_carries_the_
api_prefix` on the Linux CI run.

Port 1 on loopback is privileged and outside the ephemeral range, so nothing
the suite binds can take it.
@elementalvoid
elementalvoid merged commit 58e3266 into main Nov 14, 2026
4 checks passed
@elementalvoid
elementalvoid deleted the feat/per-folder-pause branch November 14, 2026 06: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.

Pause individual folder

1 participant