Conversation
:core:math, :core:astronomy, :core:catalog, :core:events and :render:api
move from kotlin("jvm") to Kotlin Multiplatform under a new skymap.pure-kmp
convention: a jvm target, which the Android modules and :data:generator
consume exactly as they consumed the old jar, plus iosArm64,
iosSimulatorArm64 and (for simulators on Intel Macs) iosX64. Sources move
to src/commonMain; history is preserved by git mv.
The architecture's bet held. Main code needed one expect/actual — the NFD
step of NameNormalizer (java.text.Normalizer on the JVM, Foundation's
decomposedStringWithCanonicalMapping on Apple) — and two imports
(kotlin.concurrent.Volatile, kotlin.jvm.JvmInline). All five modules
compile for every iOS target.
The tests move to commonTest so the goldens run on iOS too, which is the
point of sharing the core. Truth is JVM-only, so a new :core:testing module
provides Truth's names and semantics for exactly the subset in use; each
suite changed only its imports, plus assertThrows -> assertFailsWith and a
few JDK calls (Math.toRadians, Comparator.reverseOrder, ConcurrentHashMap).
The shim's own tests pin that every assertion can fail. Kotlin/Native
rejects commas in backtick names, so ten test names swap ", " for " - ".
All 326 existing tests pass on the JVM with unchanged per-module counts.
Linking and running iOS test binaries needs a full Xcode, not just the
Command Line Tools. On a Mac without it, check now skips the iOS link/test
tasks with a warning rather than failing, so an Android-only setup can
still run check.
Konsist: closes the known :core:events gap, admits :core:testing, and adds
a rule that shared modules' non-jvm source sets import no java.*/javax.*
(verified with a probe file in commonMain, which fails, and in jvmMain,
which passes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Linux check job cannot build Apple targets, so the multiplatform modules' commonTest suites would otherwise only ever run on the JVM. A macos-15 (Apple silicon) job runs iosSimulatorArm64Test and caches ~/.konan, since the Kotlin/Native toolchain and its LLVM download on first use. Not yet exercised: this commit is the first time the job runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build-and-tooling.md gains a Kotlin Multiplatform section (targets, layout, the one expect/actual, :core:testing, the Xcode rule), updates the module graph and convention-plugin table, closes the :core:events Konsist gap note, and records that D20's deferred "layer 3" turned out structural. The architecture doc, code overview and AGENTS.md point at the new layout so new shared code and tests land in commonMain/commonTest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first run of the shared core's tests on the iOS simulator failed every
NameNormalizer test with FileFailedToInitializeException: Kotlin/Native's
regex engine rejects \p{N} (the Number category) with "No such character
class", although it accepts \p{L}, \p{M} and every subcategory. The
separator pattern now spells N out as \p{Nd}\p{Nl}\p{No}, which is the
same set by Unicode's definition, and a new test pins that letter-numbers
(Nl) and other-numbers (No) still count as word characters.
No change on Android: the generated skymap.db is byte-identical before and
after (sha256 71cc23b8…, 3448 objects, 19686 names).
All 339 tests now pass on both the JVM and the iOS simulator (iosX64,
Xcode 26.6, iOS 26.5 runtime).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR Code Suggestions ✨Explore these optional code suggestions:
|
The catalog DB stores names normalized on the JVM at generation time, but
each platform normalizes search queries with its own Unicode tables (NFD,
Regex, lowercase). A name the two disagree on is one iOS search can never
find, and the \p{N} bug fixed last commit showed the tables really do
differ even where the code is common.
:data:generator gains an exportNameCorpus task (NameCorpusExport) that
writes every distinct catalog name with its JVM-normalized form: 12,516
names across Latin, Cyrillic, Greek, Devanagari, Hangul and more. The new
commonTest NameNormalizerCorpusTest re-normalizes all of them on each
target and reports any disagreement with code points. :core:catalog's test
tasks run the export first and pass its path in SKYMAP_NAME_CORPUS; the
simulator needs SIMCTL_CHILD_SKYMAP_NAME_CORPUS, because xcrun simctl
forwards only prefixed variables. The test fails loudly if the variable is
missing, which is how that was found. :core:testing gains
environmentVariable/readTextFile (JVM and Apple actuals) for this pattern.
All 12,516 names agree on the iOS simulator. The check is not vacuous:
with the Apple NFD step disabled it reports 2,109 mismatches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The FTS entity's comment framed `simple` purely as an Android 10 workaround, which invites "restoring" unicode61 once Android 10 support goes. It shouldn't be restored: unicode61 strips diacritics from Latin script only, and 1,724 of the catalog's 12,516 names carry marks on non-Latin letters (Thai, Greek, Devanagari, Katakana, Arabic, Cyrillic...). Tested against SQLite with remove_diacritics=2: "andromeda*" finds Andrómeda, but "τουκανας*" and "золотоі*" find nothing. Folding in NameNormalizer covers every script, and is identical across SQLite builds and platforms, which NameNormalizerCorpusTest checks. The comment now says so, and catalog-and-schema.md stops describing a "unicode tokenizer with diacritic removal" (and an @FTS5 Room doesn't have). Comment and doc only; no behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the GLES3 branch's ground hemisphere (GlowPrimitive removed, Ground/GroundRamp/MoonShading added to :render:api), the per-frame LabelFader allocation fix, the constant parity guard, and master at 2.1.2:Artemis. Resolutions for the multiplatform layout: - GroundRamp.kt and MoonShading.kt land in :render:api's commonMain, and GroundRampTest in commonTest, where git's directory-rename detection put them. GroundRampTest moves to kotlin.test and :core:testing's assertThat. - PrimitivesTest takes the branch's side (its glow tests go with GlowPrimitive). - Test names with commas (three in GroundRampTest, one new in LabelFaderTest) swap ", " for " - ", which Kotlin/Native requires. All :render:api tests pass on the JVM and the iOS simulator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Linux CI never compiles the iOS targets, so a test named with a comma or parentheses, legal on the JVM, only failed later on macOS: the GLES3 branch's latest merge brought in four. The Konsist gate, which runs in the Linux check, now flags any backtick name in the shared modules' non-jvm source sets using anything but letters, digits, spaces, hyphens and apostrophes. Probed: a test named `a, b` fails it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decision log renumbered the phase-0 entries when it caught up with public work: the name-corpus check is D126 and the simple tokenizer is D127, not D115 and D116 (D115 is now the minSdk 28 decision). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Description
Phase 0 of the iOS port: the pure modules become Kotlin Multiplatform, so an iOS app can share
the math, astronomy, catalog, events and renderer-contract code instead of reimplementing it.
Android is unchanged. The Android modules and
:data:generatorconsume each module'sjvmtarget exactly as they consumed the old
kotlin("jvm")jar, and the generatedskymap.dbisbyte-identical.
Stacked on #1058. The eventual Metal backend follows the GLES3 backend; GLES1 is not ported.
Build
skymap.pure-kmpconvention:jvm+iosArm64+iosSimulatorArm64+iosX64(thelast one for simulators on Intel Macs).
:core:math,:core:astronomy,:core:catalog,:core:eventsand:render:apiuse it.:data:generatorand:konsiststay onskymap.pure-kotlinas JVM tools.src/commonMainwithgit mv, so history is kept.expect/actual:NameNormalizer's NFD step (java.text.Normalizeron the JVM,Foundation on Apple). Plus two imports (
kotlin.concurrent.Volatile,kotlin.jvm.JvmInline).Tests run on every target
commonTest. Truth is JVM-only, so the new:core:testingprovidesTruth's names and semantics for exactly the subset in use. Each suite changed only its
imports, plus
assertThrows→assertFailsWithand a few JDK calls. The shim's own tests pinthat every assertion can fail.
,for-.\p{N}, soNameNormalizercould not even initialise on iOS. It now spells N out as\p{Nd}\p{Nl}\p{No}, which is the same set, and a new test coversNl/No.platform normalizes search queries itself.
NameNormalizerCorpusTestre-normalizes all12,516 catalog names (exported by the new
:data:generator:exportNameCorpus) on every targetand requires the JVM's result. All agree on the iOS simulator. With the Apple NFD step
disabled, it reports 2,109 mismatches, so the check isn't vacuous.
checkskips the iOS link/test tasks with awarning instead of failing, so Android-only setups keep working.
Konsist: closes the
:core:eventsgap, admits:core:testing, and bansjava.*/javax.*in the shared modules' non-
jvmsource sets. (Checked with probe files: the import fails thegate in
commonMainand passes injvmMain.)CI: a new
macos-15job runsiosSimulatorArm64Test.Type of Change
Checklist
./gradlew checkfromstardroid-v2/, or./gradlew :app:testfrom
stardroid-v1/, matching whichever module this PR touches)No need to update CHANGELOG.md - we'll get Claude to do that when we cut a release.
Notes for Reviewers
./gradlew checkis green,and all 340 tests pass on both the JVM and the iOS simulator (
iosX64Test). Per-module JVMcounts match the pre-conversion suites, plus the shim's 12 tests, the new
NameNormalizercase and the corpus test.
master, soit won't run on this stacked PR until it is retargeted after v2: a selectable GL ES 3.0 renderer backend beside GLES1 #1058 merges (or is dispatched by
hand on this branch).
git diff -Mshows almost every file asR09xwith import-onlychanges. The substance is in
build-logic/.../skymap.pure-kmp.gradle.kts,core/testing/,NameNormalizer*.kt,RecordingSkyRenderer.kt(ConcurrentHashMap → a common atomicreference) and
ArchitectureTest.kt.build-and-tooling.mdhas a new Kotlin Multiplatform section;code-overview.md,high-level-architecture.mdandAGENTS.mdare updated for the layout.🤖 Generated with Claude Code