# KSLog Kotlin Toolchain migration report Date: 2026-11-02 Base commit: `0b9fb30862c7319bb228039ee33eef9a0ddef95c` Kotlin Toolchain: `v0.13.0` source commit `abc7a5f7579e9ef267107782048c76777f0bf932` ## Result KSLog now has a checked-in, release-pinned Kotlin Toolchain project that loads, builds every platform supported by Toolchain 0.13.0, runs real JVM tests, generates both documentation formats, can publish signed KMP artifacts through the configured `mavenLocal` destination, and is consumable by Gradle KMP and Android projects. Migration validation redirects Maven Local to a temporary repository; the destination itself is not inherently isolated. Toolchain Nexus credentials/repository configuration is absent and resolved Maven Central publishing is disabled. This is **not yet a publication-compatible full cutover**. Toolchain 0.13.0 cannot represent `linuxArm32Hfp` and hard-codes the WasmJS artifact suffix as `-wasmjs` instead of KSLog's released `-wasm-js`. The Gradle build is therefore retained, mapped to the moved sources, and validated as the complete target and publication fallback. No remote artifact, documentation, tag, or release was published during this migration. ## Implemented layout - `kotlin` and `kotlin.bat` preserve the official 0.13.0 wrapper content. Git attributes enforce LF for `kotlin`/Kotlin sources and CRLF for `kotlin.bat`. The wrappers select CLI `0.13.0-dev-4444` with the official pinned distribution SHA-256. - `project.yaml` registers the stable `kslog` library module and two local build plugin modules. The stable directory name prevents compiler module identity from depending on the checkout/worktree directory name. - `kslog/module.yaml` declares Android, JS, JVM, WasmJS, Linux x64/ARM64, and MinGW x64, plus Android/JDK/Kotlin settings and full publication metadata. - The 20 production files moved byte-for-byte into `kslog/src*` Toolchain source roots. `build.gradle` maps the retained Gradle source sets to those roots, including Linux ARM32. - Compiler module identities are pinned to the existing published identities: JVM/Android `META-INF/dev.inmo_kslog.kotlin_module`, leaf KLIB `unique_name=dev.inmo:kslog`, common metadata `kslog_commonMain`, and native metadata `dev.inmo:kslog_nativeMain`/`kslog_nativeMain`. - `kslog/test@jvm/CallbackKSLogTest.kt` adds two focused tests covering exact callback forwarding and rejected lazy-message evaluation. - `plugins/dokka` adapts the official Apache-2.0 Toolchain Dokka plugin for KSLog's KMP graph and Dokka 2.2.0 HTML/GFM output. Each adapted Apache source carries a prominent KSLog modification/provenance notice, and cleanup rejects symbolic-link ancestors and requires real-path containment. Platform analysis receives JVM/common, JS, and WasmJS standard-library classpaths. Because the plugin API only exposes the JVM module classpath, the documented JS/WasmJS prebuild materializes the transformed Common and matching platform KLIBs for deterministic discovery. Generation fails before deployment if unresolved-type placeholders remain. - `plugins/github-release` provides an explicit `gh release create` command and a non-network dry-run mode. It runs the committed version consistency preflight first; no workflow invokes it. - `DEVELOPMENT.md` documents Toolchain use, the Gradle fallback, isolated local publication, disabled Toolchain remotes, the retained Gradle release path, and release gating. - `verification/` contains portable release/parser/wrapper checks plus the baseline/current Gradle publication, source-identity, public-signature, and consumer verifier used by CI. ## Target and test matrix | Target | Toolchain result | Runtime/test result | Contract notes | |---|---|---|---| | JVM | PASS | 2 tests found, 2 started, 2 passed | Bytecode major 52; 25-class list and public JVM method/field signatures from `javap -public -s -constants` match Gradle | | Android | PASS | No device tests in the project; Android consumer compilation PASS | Bytecode major 61; 24-class list and public JVM method/field signatures match Gradle; minSdk 21, compileSdk/build tools 37 | | JS | PASS | No test sources; Toolchain 0.13.0 exposes no browser/Node runner selection for a library | Gradle fallback keeps browser + Node declarations | | WasmJS | PASS | No test sources; Toolchain 0.13.0 exposes no Node/d8 selection and only has browser test support | Gradle fallback keeps browser + Node + d8 declarations | | linuxX64 | PASS | No test sources | Host-compilable KLIB | | linuxArm64 | PASS | Cross-compiled; not runnable on this x64 host | KLIB publication produced | | mingwX64 | PASS | Cross-compiled; not runnable on this Linux host | KLIB publication produced | | linuxArm32Hfp | **UNSUPPORTED** | Gradle clean build compiles it; no tests | Absent from Toolchain 0.13.0 `Platform`; minimal model probe fails | `./kotlin check` did not mistake empty platform suites for passing tests: the report only claims the two JVM tests. Gradle reports JS, WasmJS, Android, and native tests as `NO-SOURCE` or skipped, while still compiling all declared targets, including Linux ARM32. ## Verification evidence The commands below are reproducible from the repository root. Temporary build logs and repositories are intentionally not part of the published report. ### Model, build, checks, and compatibility | Command | Result | |---|---| | `./kotlin show modules` | PASS; modules `dokka`, `github-release`, `kslog` | | `./kotlin show settings -m kslog` plus `./kotlin show tasks` | PASS; `mavenCentral.enabled: false`, only local publish repository configured, no Nexus/Central task references | | `./kotlin show commands` / `show checks` | PASS; Dokka/release commands and builtin tests enumerated | | `./kotlin clean && ./kotlin build` | PASS; all seven Toolchain platforms plus both plugin modules | | `./kotlin check` | PASS; KSLog JVM tests 2/2 plus Dokka guard/classpath tests 4/4 | | `./kotlin test -m dokka -p jvm` | PASS 4/4; transformed/platform classpath mapping, unresolved-output rejection, symlink containment, and scoped cleanup | | `./gradlew --no-daemon clean build` | PASS; complete legacy build, including Linux ARM32 | | `bash verification/verify_gradle_fallback.sh` | PASS; isolated baseline/current Gradle publication and committed consumer probe | | `python3 verification/check_release_consistency.py` and parser/wrapper checks | PASS; four version copies, literal changelog heading, LF/CRLF attributes | | Linux ARM32 minimal model probe | Expected failure: `Product platforms list should not be empty` at `linuxArm32Hfp` | | GitHub YAML, actionlint 1.7.7, shell syntax, `git diff --check` | PASS | | `ast-index rebuild` | PASS after final edits | The Toolchain emits the existing insignificant inline warning. It also warns that `-module-name`/`-Xshort-module-name` are passed more than once because the built-in checkout-derived names are intentionally overridden; inspection of the output JAR/KLIB manifests proves the last values match the released Gradle module identities. ### Source and ABI preservation - All 20 production source files match the base commit byte-for-byte after their moves. - The JVM 25-class and Android 24-class lists match; public JVM method/field signature dumps from `javap -public -s -constants` have zero differences. - Gradle/Toolchain bytecode majors are JVM 52/52 and Android 61/61. - Published JVM, common/native metadata, and supported leaf KLIB module identities match Gradle. These checks are deliberately narrow. Source identity, consumer compilation, JVM class/signature comparison, and inspected module names are not a complete Kotlin metadata or KLIB ABI proof. Full cutover remains blocked and requires a dedicated metadata/KLIB compatibility review in addition to resolving the two upstream capability gaps. ### Documentation and release command | Command | Result | |---|---| | `./kotlin build -m kslog -p js -p wasmJs` | PASS; materializes the Common/JS/WasmJS analysis KLIBs required by the pinned plugin API | | `./kotlin do dokkaHtml` | PASS; 156 files at `build/dokka/html`, zero unresolved-type placeholders | | `./kotlin do dokkaGfm` | PASS; 101 files at `build/dokka/gfm`, zero unresolved-type placeholders | | Output/link/platform inspection | PASS; canonical source links and Common/JVM/Android/JS/WasmJS/Native tabs | | `KSLOG_GITHUB_RELEASE_DRY_RUN=true ./kotlin do githubRelease` | PASS; consistency preflight and `v2.1.0` payload, no network mutation | The legacy `DOKKA_PATH` override is intentionally not ported. It remains available only through Gradle because Toolchain cleanup is restricted to direct children of `build/dokka`. ### Isolated publication and consumers Toolchain publication used a temporary Maven repository selected with the JVM `maven.repo.local` override, `-m kslog`, and a generated throwaway signing key. The configured destination is named `mavenLocal` and would use the normal Maven Local repository without that override. The temporary private key was deleted after verification, and the normal Maven Local repository was not written. | Check | Result | |---|---| | `./kotlin publish -m kslog mavenLocal` | PASS in an isolated repository | | Toolchain artifact/signature inventory | 40 primary files and 40 detached signatures; 40/40 signatures verified with the throwaway public key | | Toolchain required POM metadata comparison | PASS for root and every supported platform artifact | | Gradle KMP consumer compile | PASS for JVM, JS, WasmJS, linuxX64, linuxArm64, mingwX64 | | Gradle Android KMP consumer compile | PASS | | `bash verification/verify_gradle_fallback.sh` | PASS; untouched-base and post-move Gradle outputs each contain the same 46 primary files, nine source JARs, and nine required-metadata POMs; no signing task/key/config is used | Produced IDs are `kslog`, `kslog-android`, `kslog-js`, `kslog-jvm`, `kslog-linuxarm64`, `kslog-linuxx64`, `kslog-mingwx64`, and `kslog-wasmjs`. Root Gradle module metadata, Kotlin Tooling metadata, and sources are present. Platform Toolchain publications contain placeholder Javadoc JARs, while the root Toolchain Javadoc JAR is absent. The committed Gradle verifier uses a fresh Gradle user home with only optional `caches`/`wrapper` links, an empty GnuPG home, sanitized credential/signing environment variables, and separate Maven repositories; it neither reads user Gradle signing configuration nor writes to the normal Maven local repository. ## Exact parity blockers and differences 1. **Linux ARM32:** `linuxArm32Hfp` is absent from the pinned 0.13.0 `Platform` enum and schema. Adding it to `product.platforms` is rejected at model load, before compilation or publication can be customized. 2. **Wasm artifact coordinate:** built-in KMP publication maps `wasmJs` to `kslog-wasmjs`; there is no per-platform artifact-suffix override. KSLog's released coordinate is `kslog-wasm-js`. 3. **Runtime declarations:** JS browser/Node and WasmJS browser/Node/d8 runner selection are not exposed for this Toolchain library model. Compilation and publication work; those execution contracts stay in Gradle. 4. **POM shape:** required name/description/URL/developers/license/SCM URL and developer connection are preserved. Toolchain additionally generates the SCM `connection`. Its root KMP POM uses `pom` and a `kslog-jvm` compile dependency, while Gradle's root POM carries a Kotlin stdlib runtime dependency. The Toolchain Android POM additionally declares `kotlin-stdlib-jdk7` and `kotlin-stdlib-jdk8`; its JS POM omits Gradle's `kotlin-dom-api-compat`; and its Linux ARM64, Linux x64, and MinGW POMs move the Kotlin stdlib dependency from compile to runtime scope. Gradle module metadata consumer selection and the committed consumers passed, but direct POM consumers can observe these dependency/scope changes, so this is not publication-shape parity and requires review before full cutover. 5. **Root Javadoc artifact:** the 46-file Gradle publication has `kslog-2.1.0-javadoc.jar`; the 40-file Toolchain publication omits it. This is the sixth missing primary file in addition to the five Linux ARM32 files. Toolchain platform Javadoc JARs contain a manifest plus a 78-byte `README.md` placeholder, while Gradle's Javadoc JARs contain only the manifest. 6. **Android manifest and AAR layout:** Gradle's manifest declares only `minSdkVersion=21`; Toolchain additionally emits `targetSdkVersion=37`. Gradle uses `classes.jar`; Toolchain uses `libs/kslog-jvm.jar`. Both are valid AAR layouts, the bytecode level and compared public JVM method/field signatures match, and an Android KMP consumer compiles successfully. 7. **JS manifest detail:** public KLIB identity matches `unique_name=dev.inmo:kslog`, but Toolchain's JS/Wasm KLIB does not include Gradle's `jsOutputName=kslog` manifest entry. 8. **Android resource exclusions:** `resourcePackaging` is not accepted for a Toolchain `kmp/lib`. The produced AAR contains only the manifest and library JAR, so none of the three legacy serialization metadata exclusions are currently present. Gradle keeps the exclusions for the fallback. 9. **Per-platform JVM release:** Toolchain 0.13.0 does not allow `jvm.release` to differ by platform. The module uses target-specific `-jvm-target=1.8` and `-jvm-target=17`; inspected bytecode proves majors 52 and 61. 10. **Documentation output override:** Gradle honors `DOKKA_PATH`; Toolchain intentionally does not because arbitrary external cleanup would weaken the generated-output containment guarantee. Because items 1 and 2 change released target/coordinate contracts, remote Toolchain publication must remain blocked until Toolchain gains the required capabilities or an explicitly reviewed compatibility implementation is added. ## CI behavior - `.github/workflows/build.yml` replaces the stale workflow that attempted nonexistent Gitea/GitHub-Packages Gradle tasks on every push. Pushes and pull requests now run release/parser/wrapper preflights, Toolchain build/check, the complete retained Gradle build, and the isolated publication/API/consumer verifier. Checkout fetches full history so the verifier's pinned migration base commit is available. It has read-only repository permissions and no secrets or remote publication commands. - `.github/workflows/kdocs.yml` remains `master`-only. Its read-only generation job checks out with `persist-credentials: false`, materializes the platform analysis KLIBs, runs Toolchain/Dokka, and uploads the generated artifact. A separate write-enabled job downloads only that artifact and deploys it to `kdocs`; project/plugin code never runs with a write credential. - All workflow actions are pinned to resolved commit SHAs. - Remote CI execution is intentionally unverified until the branch is pushed. ## Remote-only checks not performed - GitHub Actions on an actual hosted runner. - Inmo Nexus upload. - Maven Central bundle upload/validation/release. - GitHub release creation. - Documentation deployment to the `kdocs` branch. - Android device tests and browser/Node/d8 tests (there are currently no such test sources); Linux ARM64 and MinGW runtime execution on matching hosts. ## Recommended pull request Suggested title: > build: add Kotlin Toolchain migration with compatibility fallback Suggested body: > ## Summary > - add the pinned Kotlin Toolchain 0.13.0 wrappers and a stable `kslog` KMP module > - migrate source roots byte-for-byte and retain a validated Gradle fallback > - add real JVM tests, KMP-capable Dokka HTML/GFM tasks, and an explicit GitHub release command > - replace stale package-publishing CI with non-publishing Toolchain and full Gradle validation > - document isolated publication, release gating, and full verification evidence > > ## Validation > - all Toolchain-supported targets build > - JVM tests: 2/2 pass > - retained Gradle clean build passes, including linuxArm32Hfp > - JVM/Android class lists and public JVM method/field signature diffs are empty; bytecode remains 8/17 > - signed isolated KMP publication verified and consumed by Gradle KMP + Android projects > - Dokka HTML/GFM and GitHub release dry-run pass > > ## Known blockers > Toolchain 0.13.0 has no linuxArm32Hfp platform and publishes `-wasmjs` instead > of the released `-wasm-js` coordinate. Therefore Gradle remains the publication > fallback and remote Toolchain publication is not enabled. See > `MIGRATION_REPORT.md` for the complete matrix and artifact differences. This migration is ready only for a **draft PR**. Full Gradle removal is not review-ready and remains blocked by Toolchain 0.13.0's missing Linux ARM32 platform and incompatible Wasm artifact ID; the narrow checks above do not waive those requirements.