sync/mod.rs listed 5 of its 9 modules; migrate's doc sat above the v9 SQL;
client.rs had items after its test module; the ffi's sync_now doc had fused
into client_update's; complete_reminder (ffi and EditorAction) still said
recurrence advancement was to come, though the core does it; NoteQuery.view
listed views the core never matched and claimed it validated. Test scratch
dirs drop the old ts-/iw- prefixes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
"application/octet-stream" was written out in the blob server, its test, the
store's normalize_mime and the wire default. All four now read OPAQUE_MIME; the
schema's SQL column default names the same string and says so.
DRY pass #2, batch 2, F7 (#5372).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the audit (#5178). Each was unreachable from every client:
- Checklist add-item and delete-item: REST POST /items and DELETE /items/<id>,
the Tauri commands, the store, rest and local adapters, the core's
add_item/delete_item, set_item_text and remove_item, and the FFI exports.
Adding, rewording and removing an item are body edits in every editor. The
checked toggle stays, and its rewriter is simpler without the drop branch.
- Manual unfurl: POST /unfurl and its adapters. Previews arrive in the
background after a save (unfurl_queue).
- The /api/config `android_client` key, android_release() and the
APK_NAME/MANIFEST_NAME aliases. Phones poll /api/client/android.
- users.email_verified and users.avatar_path (migration 0037). Nothing set
the first or read the second; the SMTP reset never checked verification.
- derive::extract_tags (only tests used it; the shared fixture now runs
through extract_tag_spans), the unused check and link icons, and the
unused editor_add_item string.
- The blob scheme is renamed tsblob -> inkblob. URLs are built as notes are
read, so nothing stored carries the old one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desktop could not create an attachment at all, and a removed attachment or
dismissed preview came back on the next pull. Now:
- core: add_attachment keeps the bytes in the blob store and queues the row
(schema v10: attachments.uploaded / upload_error). Push uploads it once its
note has landed. A refusal that retrying won't fix (too large, id clash, hash
mismatch) is recorded on the file and not re-sent every cycle; the editor
shows it.
- core: removing a synced attachment or dismissing a preview leaves a tombstone
in pending_deletes; push sends it as an `attachment`/`preview` delete, and a
pull while it waits doesn't put the row back. A pull also keeps files still
waiting to upload instead of replacing them wholesale.
- server: PUT /api/sync/attachments/<id> (raw body, sha256-checked, idempotent,
size-capped) and child deletes in push, which apply regardless of LWW and
answer noop for rows the caller can't see. One store_attachment helper for
the upload route, the importer and sync. Protocol 5, feature attachment_sync;
the client sends neither to a server without it.
- server: migration 0031 makes a link preview's insert/delete bump its note, so
background-fetched previews and web dismissals reach linked devices.
- desktop: Attach and paste-image work offline (raw-bytes IPC command).
- SVG is served as a download by the desktop blob scheme too (as #1981 did for
the web), and drawn as a file chip on both.
- autosync: drop the catch_unwind; release builds abort on panic, so it only
ever worked in debug builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Android becomes a native Kotlin client over this same code (Scribe note 2730), so
the local store and sync engine stop being modules of the desktop app and become
`thoughtsync-core`, a crate with no UI framework in it at all.
This is a move, not a rewrite, and the measurement is why: every file in local/
and sync/ already carried ZERO Tauri references — 4,980 of 6,372 lines. The
coupling was 473 lines of command shim, which stays behind in the desktop crate
as src/commands/. Kept as git renames so history follows the files.
The desktop imports them under their old names (`use thoughtsync_core::{local,
sync}`) so every call site reads exactly as before. What moved is where they
live, not what they are.
Two things a workspace changes that are easy to miss, both caught before pushing:
[profile.release] now lives at the workspace ROOT. Cargo silently ignores
profiles declared by a non-root member — leaving it in the desktop crate would
have dropped lto/strip/opt-level from every release build with only a warning.
And a workspace shares ONE target dir, so the bundles moved from
desktop/src-tauri/target to target/. Thirteen references across publish-release,
debundle-graphics, verify.sh, package-prebuilt and the workflow now point there.
Pinning target-dir back would have been the smaller diff, but the Android lane
also produces Rust artifacts and they do not belong under desktop/.
Also retires the Tauri Android lane in the same push rather than leaving a path
that is being replaced: gen/android, android.yml and docs/android-dev.md are
gone, the mobile_entry_point attribute with them, and the lib drops to rlib —
staticlib/cdylib existed for Tauri mobile, and the .so Android loads will be
built from the core crate instead. Rule 22, no parallel path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>