feat(KernelRace): add iOS, platform chips, and fix the broken Wasm build - #32
Merged
Merged
Conversation
## iOS support shared/composeApp gain iosArm64/iosSimulatorArm64 targets, mirroring the existing per-platform expect/actual pattern: - LlamaRuntimeBuilder.ios.kt: same shape as the JVM actual, backed by PosixPreadRandomAccessSource (skainet-io-core's native64Main) instead of a JDK file API. - IosModelProvider.kt: same cache-or-download shape as DesktopModelProvider, but talks to Ktor's Darwin engine directly rather than through skainet-data-source's KtorRemoteDataSourceFetcher (that module is JVM-only per its own gradle.properties — skainet.targets=jvm — so it isn't reachable from iosMain at all). - Platform.ios.kt: reports the Apple native-cinterop kernel tier; supportsKernelRace = false (the two-process split-screen race is an Android-only mechanism). - iosApp/: hand-authored Xcode project shell (SwiftUI entry point embedding the KMP framework via embedAndSignAppleFrameworkForXcode). Structurally checked (balanced pbxproj, valid plist/JSON) but NOT built — this environment has no macOS/Xcode, and Kotlin/Native requires a macOS host to compile Apple targets at all. First real build happens on a Mac. Prerequisite (separate repo): SKaiNET-transformers PR #315 fixes kllama's stale iOS/macOS native-kernel install stubs, which were no-op'd and silently left packed-quant matmul on the scalar floor on Apple targets. Until that ships in a release, KernelRace's iOS build runs correctly but without NEON acceleration — noted in the README. ## Platform-support chips New SamplePlatform enum + currentSamplePlatform expect/actual (Platform.kt, alongside the existing kernelTierLabel/supportsKernelRace pattern) and a PlatformChips composable wired into ChatScreen's Scaffold — a highlighted chip for whichever of Android/Desktop/Web/iOS is currently running. ## Wasm build fix The web build compiles but doesn't actually work once deployed: no Cross-Origin-Opener-Policy/Cross-Origin-Embedder-Policy handling anywhere, deployed straight to GitHub Pages (which can't set custom response headers), and Compose's Wasm/Skiko canvas needs cross-origin isolation (SharedArrayBuffer) for its multi-threaded renderer. wasmJsBrowserDevelopmentRun's own dev server sets these headers automatically, which is why this wasn't caught locally — and kernelrace-ci.yml only runs a compile check, never an actual browser. Fix: vendor the well-established coi-serviceworker shim (MIT, gzuidhof/ coi-serviceworker v0.1.7) into composeApp's wasmJs resources, loaded first in app.html. Verified: built :composeApp:wasmJsBrowserDistribution and served the production output with a plain static server (no custom headers, reproducing GitHub Pages) — confirmed neither header is set natively, confirming the shim is necessary; couldn't verify the actual browser-side fix (no browser in this environment). ## Verification - shared/composeApp compile cleanly on every non-Apple target (jvm/android/wasmJs) after each change. - Full existing CI matrix passes: shared:jvmTest, shared:testDebugUnitTest, composeApp:assembleDebug, shared/composeApp:compileKotlinWasmJs — 0 failures, 0 errors across all suites. - iOS/macOS targets are unverifiable here (no Mac) — noted explicitly rather than claimed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same category of bug as the Panama-wrongly-modeled-on-Android fix in the engine repo (KernelSupportMatrixTest) — a label claiming "scalar" when a faster kernel tier is actually active. Platform.jvm.kt's kernelTierLabel() was a hardcoded "JVM (scalar)" string, but composeApp's :run task always passes --add-modules jdk.incubator.vector (skainetSimdJvmArgs), so the normal desktop run actually dispatches through PanamaVectorKernelProvider, not scalar — the label was simply never updated to reflect that. Fixed by probing PanamaVectorKernelProvider.isAvailable() directly, same pattern as Android's JniKernelProvider.isAvailable() — a static capability check, not a KernelRegistry query. That distinction matters here: ChatViewModel evaluates kernelTierLabel() at construction time, before DirectCpuExecutionContext.create() has ever run, and KernelRegistry only gets populated as a side effect of that (via KernelServiceLoader.installAll() inside DefaultCpuOpsJvm's init). A registry-based label would read an empty registry and always report "scalar" regardless of what's about to load. skainet-backend-cpu depends on skainet-backend-api (where KernelProvider is declared) as implementation-scoped, so it isn't reachable transitively — added it directly so PanamaVectorKernelProvider.isAvailable() resolves. Verified: :shared:compileKotlinJvm, full existing CI matrix (jvmTest/testDebugUnitTest/assembleDebug/compileKotlinWasmJs ×2/ compileDebugKotlinAndroid) all pass, 0 failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6 tasks
Contributor
Author
|
Real-hardware validation of the iOS work in this PR (opening the Xcode project, building, running, checking the kernel tier) is tracked separately in #33, since it needs an actual Mac — not blocking this PR. |
Add a concrete "how cheap adding iOS actually was" bullet — ~200 lines across 4 files, and the one that matters (LlamaRuntimeBuilder.ios.kt) is 36 lines, nearly a line-for-line copy of the JVM actual, with zero engine-side changes needed. That's the actual point of this sample: it's meant to demonstrate how easy it is to build apps with SKaiNET, including on iOS, not just to exercise the engine's targets. Also fixed the "three kernel paths" count to four now that iOS's native-cinterop tier exists alongside Android/Desktop/Wasm. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three things, found while auditing iOS support at SKaiNET/SK-TR 0.40.1 (see
SKaiNET-transformers#315):
iOS support
shared/composeAppgainiosArm64/iosSimulatorArm64targets, mirroring theexisting per-platform
expect/actualpattern (Android/Desktop/Wasm alreadyhad one file per concern):
LlamaRuntimeBuilder.ios.kt— same shape as the JVM actual, backed byPosixPreadRandomAccessSourceinstead of a JDK file API.IosModelProvider.kt— same cache-or-download shape asDesktopModelProvider,but talks to Ktor's Darwin engine directly:
skainet-data-source(used bythe other two providers) is JVM-only per its own
gradle.properties(
skainet.targets=jvm), unreachable fromiosMain.Platform.ios.kt— reports the Applenative-cinteropkernel tier;supportsKernelRace = false(the two-process split-screen race isAndroid-only).
iosApp/— hand-authored Xcode project shell. Structurally checked(balanced pbxproj, valid plist/JSON) but not built — this was authored
without access to macOS/Xcode. First real build happens on a Mac.
Prerequisite: SKaiNET-transformers#315 fixes
kllama's stale iOS/macOSnative-kernel install stubs (they were no-op'd, silently leaving packed-quant
matmul on the scalar floor on Apple targets despite the kernels existing).
Until that ships in a release, this iOS build runs correctly but without NEON
acceleration — noted in the README.
Platform-support chips
A small
SamplePlatformenum +currentSamplePlatformexpect/actual and aPlatformChipscomposable inChatScreen'sScaffold, showing all foursupported platforms with the currently-running one highlighted.
Wasm build fix
The web build compiles but doesn't actually work once deployed: no COOP/COEP
handling anywhere, deployed straight to GitHub Pages (which can't set custom
response headers), and Compose's Wasm/Skiko canvas needs cross-origin
isolation (
SharedArrayBuffer) for its multi-threaded renderer.wasmJsBrowserDevelopmentRun's own dev server sets these headersautomatically — which is why this wasn't caught locally — and
kernelrace-ci.ymlonly runs a compile check, never an actual browser.Fix: vendor the well-established
coi-serviceworkershim (MIT,gzuidhof/coi-serviceworker
v0.1.7) into
composeApp's wasmJs resources, loaded first inapp.html.Test plan
shared/composeAppcompile cleanly on every non-Apple target (jvm/android/wasmJs) after each changeshared:jvmTest,shared:testDebugUnitTest,composeApp:assembleDebug,shared/composeApp:compileKotlinWasmJs— 0 failures, 0 errors:composeApp:wasmJsBrowserDistributionand served the production output with a plain static server (no custom headers, reproducing GitHub Pages) — confirmed neither COOP nor COEP is set natively, confirming the shim is necessary