core: extract the store and sync engine into a shared crate (M12 step 1)
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>
This commit is contained in:
+11
-46
@@ -159,49 +159,14 @@ backend/frontend push.
|
||||
- No Postgres lane (unchanged): the desktop app's local store + sync behavior is
|
||||
verified on the operator's machine, not in CI.
|
||||
|
||||
## Android (Tauri mobile) lane — `android.yml`, third image
|
||||
## Android lane — REMOVED 2026-08-17
|
||||
|
||||
Android is a peer surface, not a desktop variant, so it gets its own workflow.
|
||||
|
||||
- **Image:** `git.fabledsword.com/bvandeusen/ci-tauri-android:1.97` (Rust + the
|
||||
four Android ABIs + Android SDK/NDK + JDK 17 + Node + tauri-cli). Pins held in
|
||||
lockstep with `ci-tauri` and `ci-tauri-win` — all three compile the same crate.
|
||||
- **Why a third image.** `ci-android` says in its own header that it excludes the
|
||||
NDK ("No Flutter, no NDK, no CMake") and carries no Rust; `ci-tauri` has Rust
|
||||
but no SDK, plus a WebKitGTK stack Android never touches. Tauri needs the NDK
|
||||
precisely because the core is Rust compiled to Android ABIs.
|
||||
- **JDK 17, not the 25 `ci-android`/`ci-flutter` ship.** `tauri android init`
|
||||
GENERATES the Gradle project, so its version isn't ours to choose — it produced
|
||||
Gradle **8.14.3** + AGP **8.11.0** here. `CI-android/versions.env` records that
|
||||
JDK 25 needs Gradle 9.1.0+ and that anything older fails with an opaque
|
||||
`"25.0.3"` message. Bumping this JDK without checking what Tauri templates will
|
||||
break the build with an error that names nothing useful.
|
||||
- **`gen/android/` is COMMITTED.** `tauri android init` generates it, and the only
|
||||
ignores are its own (build outputs, `local.properties`, `key.properties`,
|
||||
`keystore.properties`). CI must not have to regenerate it, and manifest or
|
||||
Gradle edits have to survive.
|
||||
- **Debug APK only, arm64 only, today.** A release APK must be signed, and the
|
||||
keystore has to be generated by the operator and never pass through CI logs or
|
||||
an agent session — the same constraint recorded for the updater key (task 2136).
|
||||
Gradle's throwaway debug keystore needs nothing from anyone, so this lane proves
|
||||
the app compiles and packages. arm64 is every real device; the image carries the
|
||||
other three ABIs, so widening is a one-word change.
|
||||
- **Green means it BUILT.** Like the Windows lane, a Linux runner cannot execute
|
||||
the artifact. Nothing here proves the app runs, renders, or is usable by finger.
|
||||
- **TLS: OpenSSL is vendored on Android.** `reqwest` is pinned to `native-tls`,
|
||||
which is deliberate for the Windows lane (it resolves to `schannel`, keeping
|
||||
C/asm out of the cross-compile). On Android it resolves to **OpenSSL**, and the
|
||||
first build duly failed with `openssl-sys`: *"Could not find directory of
|
||||
OpenSSL installation"* — there is no Android OpenSSL to link against.
|
||||
`Cargo.toml` now carries a `cfg(target_os = "android")` block enabling
|
||||
`openssl-sys`'s `vendored` feature, which compiles OpenSSL from source with the
|
||||
NDK toolchain. That is why the image ships `perl` + `make`.
|
||||
- **Why not `rustls` on Android.** It builds faster and was the obvious fix, but
|
||||
rustls ships its own root store — the phone would trust a DIFFERENT set of
|
||||
certificates than the desktop. A self-hosted server behind a private or
|
||||
enterprise CA would then work on one surface and fail on another. One TLS stack
|
||||
across all surfaces is worth more than the build minutes. Revisit only if
|
||||
vendored OpenSSL becomes the thing that breaks this lane repeatedly.
|
||||
The Tauri-mobile Android lane is gone. Android is a native Kotlin/Compose client
|
||||
over the shared `thoughtsync-core` crate instead — see Scribe note 2730 for the
|
||||
decision and milestone M12 for the arc. Its CI lane and image will be rebuilt on
|
||||
that basis; `ci-tauri-android` is being repurposed (drop `tauri-cli`, add
|
||||
`cargo-ndk`) rather than deleted, because its NDK binutils symlinks and PATH fix
|
||||
are load-bearing for any Rust-on-Android cross-compile.
|
||||
|
||||
## Formatting the Rust lane before pushing
|
||||
|
||||
@@ -212,8 +177,8 @@ a formatter is neither a test run nor a local stack:
|
||||
|
||||
```
|
||||
docker run --rm --user "$(id -u):$(id -g)" -e CARGO_HOME=/tmp/cargo \
|
||||
-v "$PWD/desktop/src-tauri:/w" -w /w \
|
||||
git.fabledsword.com/bvandeusen/ci-tauri:1.97 cargo fmt --check
|
||||
-v "$PWD:/w" -w /w \
|
||||
git.fabledsword.com/bvandeusen/ci-tauri:1.97 cargo fmt --all --check
|
||||
```
|
||||
|
||||
Drop `--check` to apply. `--user` keeps the container from leaving root-owned
|
||||
@@ -225,7 +190,7 @@ literal — copying that shape caused one of the four failures.
|
||||
|
||||
## The desktop lockfile
|
||||
|
||||
`desktop/src-tauri/Cargo.lock` is **committed**, per Cargo's own guidance for
|
||||
`Cargo.lock` is **committed** at the workspace root, per Cargo's own guidance for
|
||||
binary crates. Without it every CI run re-resolved the graph, which meant a
|
||||
released `.deb`/`.AppImage`/`.exe` couldn't be rebuilt from its tag, a build
|
||||
could break with no repo change, and Renovate had nothing to bump (issue 2102).
|
||||
@@ -244,7 +209,7 @@ above, and resolution is neither a test run nor a build:
|
||||
|
||||
```
|
||||
docker run --rm --user "$(id -u):$(id -g)" -e CARGO_HOME=/tmp/cargo \
|
||||
-v "$PWD/desktop/src-tauri:/w" -w /w \
|
||||
-v "$PWD:/w" -w /w \
|
||||
git.fabledsword.com/bvandeusen/ci-tauri:1.97 cargo generate-lockfile
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user