Skip to content

T-C4B1-vault-writer-task-exports-sessions

State: planning/draft · Impact: high · Complexity: large

Make the export fire for every user, not only on the skip-journal focus branch and the tracked End, and do it off the reducer and IPC tasks. One owned writer serializes all vault writes, so the completion and journal events, which reach the runner from different tasks, cannot race.

LocationRole today
apps/pumice/src-tauri/src/engine/handle.rssession_row builds a VaultWrite on the JSAC-off focus completion (run_deadline_fired) and on every tracked End (run_end, which reads the config itself); CompletionContext carries template and vault_path
apps/pumice/src-tauri/src/runner/handlers/completion_side_effects.rsrenders and writes inline on the runner task during event dispatch
apps/pumice/crates/pumice/src/timer/mod.rsTimerEngine::ended_at is the End-instant rule (paused_at while paused) the end_time column must follow
apps/pumice/src-tauri/src/runner/mod.rsdispatch_event awaits handlers sequentially; apply has no lock across callers
apps/pumice/src-tauri/src/api/v1/journal.rspure DB write plus JournalUpdated event
apps/pumice/src-tauri/src/schema/timer_session.rshas title; no end_time, no note_written_at
apps/pumice/src-tauri/src/persistence/migrations/sea-orm migrations
apps/pumice/src-tauri/tests/engine_deadline_and_display.rsasserts CompletionSideEffects fires on natural completion
apps/pumice/src-tauri/src/engine/handle.rs tests end_tracked_*assert the tracked End’s VaultWrite shape and its JSAC interplay

A migration adds nullable end_time and note_written_at. vault_write leaves CompletionSideEffects; template and vault_path leave CompletionContext. A VaultNoteHandler maps SessionCompleted and JournalUpdated to WriteRequests on a bounded channel. A writer task spawned at startup coalesces per session id, applies the timing rules (defer under journal-after-focus for focus and tracked intervals until journal submit or 120 s, since End requests the journal for both; write immediately otherwise; honour include_breaks and include_cancelled), reads the committed row with Store::get_timer_session, writes through vault-note inside spawn_blocking (a note plus daily line, or one daily entry, per write_mode; in daily-list mode a missing daily note is created), stamps note_written_at, and emits vault:note_written or vault:note_failed through the app handle. A startup sweep writes any completed session with note_written_at IS NULL older than the window. crates/pumice/src/vault.rs and the tera dependency are deleted.

  1. Migration and conversion for the two columns; populate end_time from ended_at.
  2. Remove the reducer-side vault plumbing from run_deadline_fired and run_end; session_row goes with it. Retarget the end_tracked_* and deadline tests at the writer.
  3. Writer task, channel, debounce table, sweep.
  4. Handler registration in lib.rs; event emission through the bridge.
  5. Tempdir end-to-end tests: default-settings completion then journal; skip-journal completion; two events from two tasks; sweep after a missed debounce.
  6. Delete vault.rs and tera.
AreaNote
apps/pumice/src-tauri/src/persistence/migrations/new migration
apps/pumice/src-tauri/src/persistence/db/conversions/timer_session.rsend_time, note_written_at
apps/pumice/src-tauri/src/schema/timer_session.rstwo columns
apps/pumice/src-tauri/src/engine/handle.rsdrop vault plumbing
apps/pumice/src-tauri/src/runner/handlers/completion_side_effects.rsbanner only
apps/pumice/src-tauri/src/runner/handlers/vault_note.rshandler
apps/pumice/src-tauri/src/vault_writer.rswriter task
apps/pumice/src-tauri/src/lib.rsspawn and register
apps/pumice/crates/pumice/src/vault.rssuperseded
apps/pumice/crates/pumice/Cargo.tomldrop tera
apps/pumice/src-tauri/tests/engine_deadline_and_display.rsupdated assertions
apps/pumice/src-tauri/tests/vault_export.rsend-to-end
  • Under default settings, one note and one daily line exist after journal submit; none exist before it. The same holds for a tracked End, and its note carries pumice_title.
  • SessionCompleted and JournalUpdated fired back-to-back from two tasks yield one note and one daily line.
  • No std::fs call executes on the reducer or IPC task (asserted by a test that blocks the writer and confirms the IPC returns).
  • A write failure emits vault:note_failed and leaves note_written_at null.
  • With the vault folder absent, writes fail as vault-missing, and the startup sweep writes them once the folder is back.
  • moon run pumice:codegen-drift, pumice:check, pumice:test green.

← Back to Tasks