Repository · workstreams
Workstream: Kotlin Multiplatform Migration
Status: Planned · Component: Maximize developer productivity
Goal
Make the foundational community.kotlin.* libraries Kotlin Multiplatform —
published with a commonMain plus JVM / JS / Wasm / Android targets — so that
cross-platform consumers share the same types and contracts, not merely a JVM
build. Today the libraries that hold the platform's core value types are compiled
JVM-only, which forces any cross-platform (commonMain) contract that wants to
reference them to fall back to stringly-typed or duplicated stand-ins. Migrating
them unblocks typed, shared contracts across every Kotlin target. This is a
multi-library effort — one workstream covering several libraries and steps.
Why it matters (the motivating example)
The trigger is concrete. The Observables read contract throws
RemoteObservableDataUnavailable, which must report the freshness constraint the
caller required and the watermark the projection reached. Those are a
ClockPad / HierarchicalTimestamp — but
RemoteObservableDataUnavailable lives in observable-core's commonMain (so
the planned Kotlin/JS Proxy and Kotlin/Wasm proxies can throw and catch the one
data-access contract), while
community.kotlin.clocks.hierarchical is built JVM-only.
A commonMain type cannot reference JVM-only types, so the fields are forced to
String? (the rendered pad) instead of typed ClockPad?. Nothing about the
code is JVM-bound — the clock library's ClockId / HierarchicalTimestamp /
ClockPad are plain data classes; only the build is JVM-only. This is one
instance of a general pattern: every shared contract that wants a foundational type
is blocked until that type is multiplatform.
Current state
observable-coreandobservable-composeare already Gradle Kotlin Multiplatform (jvm / js / wasmJs / android).- The foundational libraries they depend on are built JVM-only via kompile
(
build-kotlin-jvm, a flatsrc/):community.kotlin.clocks.hierarchical, and — to confirm in discovery —community.kotlin.clocks.simple,community.kotlin.eventlog, and peers. Their source is largely pure Kotlin, so the blocker is the build and publishing, not the code.
Plan / roadmap
- [ ] Discovery: enumerate the migration set and order. Identify which
community.kotlin.*libraries must go multiplatform, and sequence them leaf-first (value-type libraries before the libraries and services that consume them). Candidate leaves:clocks.hierarchical,clocks.simple; theneventlog; then consumers. - [ ] Per-library build migration. Move each library from kompile
build-kotlin-jvmto multiplatform publishing (Gradle KMP, asobservable-corealready does — or a kompile multiplatform path if/when one exists). Split sources: pure value types intocommonMain; genuinely JVM-bound pieces (e.g. a clock implementation that relies on JVM concurrency) behindexpect/actualor kept injvmMain. Publish jvm / js / wasmJs / android variants. - [ ] Portable JSON value facade. Create a small common
JsonObject/JsonArrayfacade (e.g.community.kotlin.json) covering the org.json surface that thetoJson(): JSONObject/fromJson(JSONObject)value-serialization convention uses — the JVM actual delegates to org.json so existing value objects keep working, with pure-Kotlin actuals for JS/Wasm — and migrate the convention's signatures to it. This is the "remaining dependency" named in REMOTE_OBSERVABLES.md §14.1: it lets Observables value objects cross the projection wire to Kotlin/JS and Kotlin/Wasm consumers, and that workstream's web-materialization milestone depends on it. - [ ] Downstream rewiring. Move each dependency from
jvmMaintocommonMainin its consumers and replace stringly-typed stand-ins with the now-shared types. First beneficiary: typeRemoteObservableDataUnavailable.requiredConstraint/currentWatermarkasClockPad?instead ofString?(see the Observables workstream and REMOTE_OBSERVABLES.md §3). - [ ] Verify on every target. Each migrated library and its consumers compile and pass on jvm / js / wasmJs / android, per the testing standards.
Prerequisites
This migration is sequenced after a set of foundational fixes that must land first — it will happen, but not before those are addressed.
TODO (needs enumeration): list the specific items that must be fixed before the migration begins. Captured as a placeholder pending that detail.
Graduation
When the foundational community.kotlin.* value-type libraries publish multiplatform
artifacts consumed from commonMain across JS and Wasm, and the typed cross-platform
contracts they unblock — starting with RemoteObservableDataUnavailable's ClockPad?
fields — compile and pass on every target, this graduates: update the affected project
pages.