Android comments describe the code to a stranger (#6223)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Skipped
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Successful in 15s
Android / Core and FFI clippy and tests (push) Successful in 27s
CI & Build / integration (push) Successful in 1m39s
CI & Build / Build & push image (push) Skipped
Android / Kotlin + Rust (APK) (push) Successful in 7m55s
Android / Build the server image (push) Successful in 6s

Milestone 546 "Bring the repo to the comment standard (rule 32) and
compose defaults (rule 198)", step #6223 "Comment standard sweep:
Android client".

KDoc, comments, manifest and resource notes, Gradle and TOML comments
and the ffi crate's docs now state what the code does and the
non-obvious why in the present tense. Issue, Scribe-note, milestone
(M13, M304, M315, M12) and family-idea references are gone, as are
comparisons to Minstrel and the narration of what used to be: the
capture sheet the editor replaced, the per-note colour story, the
operator's device-pass feedback, the bindgen-as-[[bin]] failure, the
0.60 edge alpha before it was re-solved, and the checker bugs behind
check-strings/check-symbols. Hazards stay as facts: the signing key that
can't be rotated, the alias that keeps the earlier name, PKCS12's single
password, unwind over abort, the UTC date-picker read, the
DerivedTint/colors.ts mirror.

One stale claim is gone: DerivedTint said the web had no test runner,
but notes/grammar.test.ts runs the same tint cases. detekt.yml said
"these two places" over a list of five.

49 files, comments only: a comment-stripping diff of every changed file
against HEAD is identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:24:52 -04:00
co-authored by Claude Opus 5.5
parent 715b648b95
commit 0a631219ee
49 changed files with 332 additions and 491 deletions
+25 -35
View File
@@ -10,17 +10,16 @@ plugins {
val workspaceRoot: Directory = layout.projectDirectory.dir("../..")
// The ABIs a release APK carries. arm64 is essentially every real device; armv7
// covers older 32-bit hardware; the two x86 targets are what emulators run on, and
// dropping them would make the app untestable on a desktop emulator (the reason
// x86_64 was added to the old Tauri lane in task 1864).
// covers older 32-bit hardware; the two x86 targets are what emulators run, so the
// app stays testable on a desktop emulator.
val androidAbis = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
/**
* Cross-compile `inkwell-ffi` for each Android ABI and drop the resulting
* `.so` into jniLibs, where AGP packages it.
*
* `ExecOperations` injected rather than `project.exec`: the latter was REMOVED in
* Gradle 9, and reaching for `project` at execution time is also what breaks the
* `ExecOperations` injected rather than `project.exec`: Gradle 9 has no
* `project.exec`, and reaching for `project` at execution time breaks the
* configuration cache this build has enabled.
*/
abstract class CargoNdkBuild : DefaultTask() {
@@ -60,16 +59,15 @@ abstract class CargoNdkBuild : DefaultTask() {
commandLine(listOf("cargo") + args)
workingDir = workspaceDir.get().asFile
if (release) {
// The workspace's release profile with two of its settings put back,
// for this build only. Environment overrides rather than a profile of
// our own, because cargo-ndk copies its `-o` output from the
// `release` directory and nothing says it understands any other one;
// the desktop's binaries are untouched either way.
// The workspace's release profile with two settings put back, for this
// build only. Environment overrides rather than a profile of our own,
// because cargo-ndk copies its `-o` output from the `release`
// directory; the desktop's binaries are untouched either way.
//
// Keep the symbol table: `strip = true` removes the symbols uniffi's
// `--library` mode reads the interface out of, and bindgen then fails
// with "No UniFFI metadata found" (run 4077). There is no debug info
// in a release build to strip, so this keeps symbols and nothing else.
// with "No UniFFI metadata found". A release build has no debug info to
// strip, so this keeps symbols and nothing else.
environment("CARGO_PROFILE_RELEASE_STRIP", "debuginfo")
// Unwind, so a panic in the core reaches Kotlin as an exception the
// board can show rather than ending the app. See the ffi crate's docs.
@@ -141,17 +139,13 @@ val rustInputs =
/**
* Which Cargo profile the `.so` is built with.
*
* A property rather than a debug/release task PAIR, deliberately. This runner has
* no working Gradle or Cargo cache (`reserveCache failed` on every run), so a cold
* cross-compile of four ABIs costs about four minutes — and a lane that both
* type-checks and packages would pay that twice if the two used different
* profiles. `android.yml` picks one profile and uses it for every Gradle call in
* the run.
* A property rather than a debug/release task pair: this runner has no working
* Gradle or Cargo cache, so a cold cross-compile of four ABIs costs about four
* minutes, and a lane that type-checks and packages with different profiles would
* pay it twice. `android.yml` picks one profile for every Gradle call in the run.
*
* CI passes `release` for a signed APK, so a phone runs an optimised store and sync
* engine. Until Scribe #2810 it passed `debug`, because the release profile's
* `strip = true` broke bindgen; `CargoNdkBuild` now keeps the symbols for this
* build alone.
* engine; `CargoNdkBuild` keeps the symbols bindgen needs.
*/
val rustProfile =
(project.findProperty("INKWELL_CARGO_PROFILE") as String?)?.takeIf { it.isNotBlank() }
@@ -187,8 +181,7 @@ android {
defaultConfig {
applicationId = "com.fabledsword.inkwell"
// 26 (Android 8, 2017) matches Minstrel and clears the NDK's floor with
// room to spare.
// 26 (Android 8, 2017) clears the NDK's floor with room to spare.
minSdk = 26
targetSdk = 36
// Injected by CI from the git tag + commit count for a release; "dev"
@@ -212,11 +205,10 @@ android {
}
// The signing key reaches this build only through the environment: CI decodes
// it from a secret into a file and points ANDROID_KEYSTORE_FILE at that path.
// It is never in the repo and never in this file. Generated by the operator
// and never seen by an agent session, because an Android signing key cannot be
// rotated without the original — v3 lineage needs it — so a leaked or lost one
// means every install has to be removed and replaced by hand.
// it from a secret into a file and points ANDROID_KEYSTORE_FILE at that path. It
// is never in the repo. An Android signing key cannot be rotated without the
// original (v3 lineage needs it), so a leaked or lost one means every install
// has to be removed and replaced by hand.
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")?.takeIf { it.isNotBlank() }
val keystorePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")?.takeIf { it.isNotBlank() }
@@ -225,13 +217,11 @@ android {
create("release") {
storeFile = File(keystoreFile)
storePassword = keystorePassword
// Hardcoded, and NOT a secret: the alias is fixed for the life of
// this app and is written into the certificate every install
// already carries. Hiding it would buy nothing and stop this file
// describing its own signing setup. It still says `thoughtsync`
// after the rename to Inkwell, because it names the key inside the
// existing keystore, and renaming it would only stop that key being
// found. Same key, so the signing certificate did not change either.
// Hardcoded, and NOT a secret: the alias is fixed for the life of this
// app and written into the certificate every install carries. It says
// `thoughtsync`, the app's earlier name, because it names the key
// inside the existing keystore; renaming it would stop the key being
// found.
keyAlias = "thoughtsync"
// PKCS12 cannot hold a key password distinct from the store
// password — keytool refuses to set one — so this is the same