Commit Graph
6 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 78810d8832 DRY pass #3: core tests open their store and seed a label one way (#5373)
Five test modules wrote the same db() over memory_conn, and portable.rs
unwrapped it inline; local::test_db() is that. Four pull/push tests wrote the
same label INSERT; local::seed_label(conn, id, name, dirty) is it. Both are
cfg(test), beside memory_conn, as wire::sample_note is beside wire::Note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:17:30 -04:00
bvandeusenandClaude Opus 5.5 2dec89bf8c Core tests make a throwaway blob store with blobs::scratch
blobs, store and portable each built a BlobStore in a temp directory their own
way: pid+tag twice, a uuid once. blobs::scratch(tag) is that, with a counter, so
two tests can never share a directory even if they pick the same tag. The
desktop's and ffi's temp-dir helpers stay, one per crate: sharing them would
need a test-util feature on the core crate.

DRY pass #2, batch 2, F9 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:24:52 -04:00
bvandeusenandClaude Opus 5.5 3ea7c817bf Core tests open their store through local::memory_conn
Seven test modules each built a migrated in-memory store by hand: open, migrate,
and (in sharing) wrap it in a Db. local::memory_conn() is that, and
open_in_memory uses it too. Each module's db() is now one line, and the schema,
Connection and Mutex imports it needed are gone.

DRY pass #2, batch 2, F9 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:24:04 -04:00
bvandeusenandClaude Opus 5.5 c35e7fd589 cargo fmt: three chains rustfmt splits
Formatting only. portable::instant (from F5), and the ffi's link and unlink
(F2/F3), were laid out by hand without a toolchain; rustfmt splits each chain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:23:57 -04:00
bvandeusenandClaude Opus 5.5 0101b05487 Stored timestamps have one writer: local::iso and local::now
CI & Build / Build now, or wait for Android? (push) Successful in 6s
Android / Build, or is the channel already serving this? (push) Successful in 6s
CI & Build / Python tests (push) Successful in 13s
CI & Build / Python lint (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / Web typecheck and unit tests (push) Successful in 13s
CI & Build / integration (push) Successful in 2m6s
CI & Build / Build & push image (push) Skipped
Android / Core and FFI clippy and tests (push) Successful in 1m18s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 3m19s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
Android / Kotlin + Rust (APK) (push) Successful in 9m29s
Android / Build the server image (push) Successful in 2s
The store's time format (RFC 3339, UTC, milliseconds, Z) is what makes lexical
order chronological. It was spelled out ten times as
to_rfc3339_opts(SecondsFormat::Millis, true), with two private now() copies
(store, pull). local::iso(t) and local::now() now hold it; store, pull, engine
and portable call them.

DRY pass #2, batch 2, F5 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:18:33 -04:00
bvandeusenandClaude Opus 5.5 5989ffc1c6 desktop: Import and Export work offline; the menu toggle is reachable; errors say why
CI & Build / Build now, or wait for Android? (push) Successful in 4s
Android / Build, or is the channel already serving this? (push) Successful in 4s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 12s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Python tests (push) Successful in 13s
CI & Build / integration (push) Successful in 48s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 4m26s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m10s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m32s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 12m42s
Export and Import were a link to the server and a reject("needs a server") on the
desktop. Both now run in the core with no server:

- core/src/local/portable.rs builds the same zip the server writes (notes.json,
  a Markdown file per note, each attachment this device holds) and reads either
  export marker or a Google Keep Takeout zip, with the server's decompression
  budget and an all-or-nothing transaction. Export saves to Downloads (no new
  plugin) and the sidebar says where; Import takes the archive as raw IPC bytes.
- core/testdata/portable.json pins the format for both copies: the server runs
  its Keep and native readers against it (test_portable_fixture.py) and checks
  its real export's keys (test_integration.py); the core runs the same cases.
- Found on the way: both importers skipped a Keep note that is only a photo as
  "empty". It now imports, on the server and in the core.
- New dependency, approved: `zip` (deflate only) plus `flate2` on its pure-Rust
  backend, both already in the lockfile.

The AppImage applications-menu toggle moves from Account, which the desktop
never shows, to the Sync page; the first-run prompt now says so.

errorMessage (#5236) replaces the hand-rolled `.error ?? …` / `.message ?? e`
reads at the remaining catch sites, so a desktop failure shows its real reason.

Task #5170.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:36:42 -04:00