Commit Graph

2 Commits

Author SHA1 Message Date
Kgothatso Ngako
2aaa7b99a6 build: phase 0 of the jvm target -- clear the ground, correct the plan
First phase of docs/jvm-target.md. Nothing here turns the target on; it
removes what would break the moment it is turned on, and stages the two
catalog entries that cannot be derived automatically. Two of the four
steps as written in the doc turned out to be wrong, and implementing them
is how that surfaced -- both are corrected in the doc in this commit.

**Deleted the stale jvmMain tree.** Six files under
composeApp/src/jvmMain/kotlin/ac/cord/auxiliary/ survived from the Aux
project this codebase grew out of. They have gone unnoticed because
`jvmMain` is currently an orphan source set -- the accessor creates it,
no target compiles it -- so the wrong package, the Room 2 imports
(androidx.room, not androidx.room3), and the references to a long-gone
AuxDatabase and AuxGlobal have never had to resolve. They would all become
compile errors in phase 4.

They are not lost: they are the closest thing to a skeleton for five of
the six platform actuals phase 4 needs, and main.kt is a reasonable
starting shape for the phase 5 desktop entry point. `git show HEAD~1` has
them.

**Added two catalog entries, not four.** sqlite-bundled-jvm and
sqldelight-sqlite-driver. Both earn their place by being unreachable
otherwise: sqlite-bundled-jvm has to be named explicitly because
variant-aware resolution hands the *android* artifact to anything running
on the host, and sqldelight-sqlite-driver is the jvm counterpart to the
android-driver and native-driver entries already there.

The doc also listed room3-runtime-jvm and sqldelight-jdbc-driver. Neither
is right. Once jvm() exists, commonMain's existing androidx-room3-runtime
resolves to the -jvm variant on its own, so an explicit entry is
redundant and would drift. And the SQLDelight drivers phase 2 needs are
for DbFactory, which lives in lightning-kmp-app -- a separate gradle build
with its own version catalog, where an entry here is simply not visible.

**kspJvm cannot be wired yet, and the build file already said so.** The
doc's phase 0 told you to uncomment
composeApp/build.gradle.kts:194. It contradicted its own phase 4, which is
where jvm() gets turned on. The comment three lines above it states the
rule:

    These configurations only exist when the ios targets are declared,
    which the kotlin block above does only on a mac.

The same holds for kspJvm -- `dependencies { add("kspJvm", ...) }` throws
UnknownConfigurationException until a jvm() target creates the
configuration. So it moves into phase 4, into the same edit that declares
the target. composeApp/build.gradle.kts is deliberately untouched by this
commit.

**Also documented: gradle does not run in a worktree here at all** until
the submodule is checked out, which worktrees do not do automatically.
`lightning-kmp-app/` is empty and configuration fails with "Project with
path ':library' not found in build ':lightning-kmp-app'". Recorded in the
phase 0 verification section along with the caveat that a linked worktree
shares .git/modules/ with the main checkout, so both trees end up on one
submodule git dir.

**Not verified by a build.** For that reason. The deletion is an orphan
source set and the additions are unreferenced catalog lines, so neither
can change a build's outcome -- but that is an argument, not a green
check, and it is the second commit in a row on this branch that has not
compiled anything. Phase 4 is the first phase that genuinely cannot be
done without a working gradle invocation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 00:44:10 +02:00
Kgothatso Ngako
5abc37e463 docs: scope the jvm target, and separate it from testing the daos
Two questions arrived together -- whether Room's own testing guidance
applies to this project, and what desktop support would cost -- and they
turned out to have opposite answers. Both are now in docs/jvm-target.md,
phased, with the blocking work separated from the mechanical work.

**The expensive part is already done.** The four-deep native chain --
secp256k1 -> bitcoin-kmp -> lightning-kmp -> lightning-kmp-app -- already
builds for JVM, on every android build we do. The comment at
composeApp/build.gradle.kts:50 records the mechanism without drawing the
conclusion: lightning-kmp-core publishes no android variant, so our
android target resolves it to the *jvm* one, which pulls
secp256k1-kmp-jni-jvm desktop natives, which is exactly why the build has
to name the android artifact by hand. Read the other way round, every JVM
artifact in the chain is already compiled from source by the composite
build. A jvm target adds no cinterop, no C compilation and no new native
constraints. That was the part worth being afraid of, and it is finished.

**The blocker is one level down, and smaller than it looks.**
lightning-kmp-app/library declares 25 expects and implements them across
35 androidMain files. Its jvmMain holds exactly one: fibiprops.jvm.kt, the
Kotlin multiplatform library template's Fibonacci boilerplate, satisfying
two of the 25 -- both of them the template's own. So 23 actuals are
missing, which is why jvm() is commented out there
(library/build.gradle.kts:18), which is why it is commented out here
(composeApp/build.gradle.kts:46). Mantra cannot declare the target until
the fork does.

Six phases, ordered by that dependency. 0 build config; 1 the fourteen
mechanical phoenix actuals; 2 the three SQLDelight JDBC drivers and
NetworkMonitor; 3 key storage; 4 mantra's own sixteen expects; 5 the
desktop entry point. 1-3 are independent and parallelisable, 4 is where
the compiler finally checks the whole thing. Roughly a week to a
launchable build.

**Phase 3 has no day estimate, deliberately.** keyStoreEncryption /
keyStoreDecryption and their two graceful* wrappers delegate on android to
KeystoreHelper.kt -- 116 lines against AndroidKeyStore, StrongBox
attempted first and fallen back from, key material never leaving hardware.
Desktop JVM has no equivalent, so this is a decision rather than a port,
and the doc gives the three real options against what each actually
protects. A fixed-key JCEKS file is named there as a liability rather than
a stopgap: this is wallet seed material, and it lands on top of the
plaintext-key finding already open against this codebase. Recommended
sequencing is a passphrase-derived KEK with the desktop build marked
unsuitable for real funds, so phases 4 and 5 can proceed without the
security question being quietly treated as answered.

Two inherited mistakes are called out rather than carried forward. The old
Aux jvmMain put the database in java.io.tmpdir behind a TODO -- the doc
says not to inherit that in either phase that touches it. And
schedulePlatformLogic goes through WorkManager on android with no desktop
counterpart, so the doc asks for an explicit choice between a no-op and an
in-process coroutine, written down.

**The DAO answer is an appendix, because it is the opposite answer.** None
of the above is needed to test the DAOs, and burying that would have been
misleading. room3-runtime-android:3.0.1 already exposes the no-Context
inMemoryDatabaseBuilder(Function0<T>) overload, and
MantraDatabaseConstructor already supplies what it needs, so Room's
recommended host-machine form compiles in commonTest and runs under
testDebugUnitTest today. The one trap is native and is the secp256k1
problem mirrored: sqlite-bundled-android ships only android-ABI .so under
jni/, so a local unit test's JVM cannot load it and BundledSQLiteDriver
fails at construction; sqlite-bundled-jvm on the androidUnitTest classpath
is the fix. Robolectric neither helps nor is needed -- it cannot load
android .so on the host either.

Everything structural here was checked against the artifacts rather than
recalled: the Room builder overloads by javap on room3-runtime-android,
the two sqlite-bundled native layouts by unzipping both, and the
availability of room3-runtime-jvm, room3-testing, quartz-jvm and the two
SQLDelight drivers by request against the repositories this build actually
resolves from. The absence of android.* and java.* imports in commonMain,
and of any NFC reference from it, was likewise grepped rather than
assumed.

**Not verified: anything that requires compiling.** No jvm target was
turned on, nothing was built, and the day estimates are estimates. Phase 4
is where dependency-substitution surprises would surface if there are any,
and it is precisely the phase nothing here exercises.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 00:38:11 +02:00