# Roadmap: chart-realtime ## Overview KMP real-time chart library. Six phases v0.1.0 MVP shipped; v0.2.0 polish shipped. ## Milestones | Milestone | Version | Status | Completed | |-----------|---------|--------|-----------| | v0.1.0 MVP | 0.1.0 | ✓ Shipped | 2026-05-20 | | v0.2.0 Polish | 0.5.0-SNAPSHOT | ✓ Shipped | 2026-05-21 | | v0.3.0 iOS Build Pipeline | 0.5.0-SNAPSHOT | ✓ Shipped | 2026-05-21 | | v0.4.0 Portfolio Hardening | 0.5.0-SNAPSHOT | ✓ Shipped | 2026-05-21 | | v0.5.0 Architecture + Interaction | 0.5.0-SNAPSHOT | ✓ Shipped | 2026-05-21 | | v1.0.0 Public Release | - | Planned | - | --- ## v0.1.0 — MVP (SHIPPED) Status: ✓ Complete Phases: 6 of 6 complete ### Phases | Phase | Name | Status | Completed | |-------|------|--------|-----------| | 1 | Module Scaffold | ✓ Done | 2026-05-20 | | 2 | Buffer + LoD | ✓ Done | 2026-05-20 | | 3 | State API | ✓ Done | 2026-05-20 | | 4 | Render Engine | ✓ Done | 2026-05-20 | | 5 | Demo App | ✓ Done | 2026-05-20 | | 6 | Polish + Docs | ✓ Done | 2026-05-20 | Delivered: CircularBuffer, LodDecimator, RealtimeChart composable, basic AxisRenderer. --- ## v0.2.0 — Polish (SHIPPED as v0.5.0-SNAPSHOT) Status: ✓ Complete Summary: .paul/phases/v0.2.0-plan-SUMMARY.md ### Delivered - TieredBuffer (3-tier 1h ring buffer, MIN_MAX binning, zero-alloc) - LodMode enum (MIN_MAX, LTTB) — MEAN removed - LTTB render-time decimation (O(n) Largest-Triangle-Three-Buckets) - AxisLabelMode (INSIDE/BESIDE/HIDDEN) with chartLeft/chartBottom insets - T0-relative X-axis timestamps with mm:ss/hh:mm:ss formatting, negative support - Material3 dynamic theming (light/dark, wallpaper-based, API 31+) - Camera cutout / edge-to-edge support - Sensor domain layer (Clean Architecture) - Koin 4.0.0 DI wiring - Package rename: eu.henesis → dev.dtrentin - Git remote: ssh://git@3nt-git.duckdns.org:222/davide.trentin/KMPCharts.git - Sensor rate cap: 200Hz (5_000μs) --- ## v0.3.0 — iOS Build Pipeline (SHIPPED) Status: ✓ Complete Plan: .paul/phases/v0.3.0-ios-build-plan.md ### Delivered - 3 iOS targets compile green (iosX64, iosArm64, iosSimulatorArm64) — iosX64 dropped in v0.5.0 D1 (Compose-MP 1.11.0 no ios_x64 variant) - `applyDefaultHierarchyTemplate()` wires iosMain/iosTest across targets - `linkDebugFrameworkIosSimulatorArm64` green - `iosSimulatorArm64Test` green — 33 tests, 0 failures - XCFramework `ChartRealtime` produced (debug + release): ios-arm64 + ios-arm64_x86_64-simulator slices - Pre-existing compile bugs fixed: - `@Volatile` → `kotlin.concurrent.Volatile` import - `@JvmName` → `kotlin.jvm.JvmName` import (OptionalExpectation) - `String.format` in AxisRenderer → manual `formatFixed`/`formatScientific`/`pow10` helpers - `NSDate.date()` → `NSDate()` + `timeIntervalSinceReferenceDate` + 1970 epoch offset - Android non-regression confirmed (`assembleRelease`, `publishToMavenLocal --dry-run`) - Local Mac config: removed Linux JDK pin from `gradle.properties`, added `local.properties` for Android SDK --- ## v0.4.0 — Portfolio Hardening (SHIPPED) Plan: .paul/phases/v0.4.0-portfolio-hardening-plan.md Source: 3-reviewer audit 2026-05-21 Executed via: kmp-manager group-by-group flow, 8 P-groups, ~15 agent calls Completed: 2026-05-21 ### Delivered **Critical fixes:** - LICENSE MIT (T1) - explicitApi() Strict + BCV 0.16.3 + klib enabled (T2) — ABI baseline 161/211 LOC - Internal lockdown of CircularBuffer / TieredBuffer / LodDecimator / dataVersion / rememberFrameTick (T3) - kotlinx-datetime 0.6.2 replaces expect/actual currentTimeMs (T4) — Platform.* 3 files deleted - CircularBuffer.writeIndex Int→Long (T5) — overflow 124d @ 200Hz fixed - @Suppress + !! removed from commonMain (T6) - Dead config removed: maxBufferSeconds, xLabelDecimals, SignalConfig.label (T7) **Correctness:** - POSITIVE_INFINITY/Float.MAX_VALUE sentinels → hasData boolean flag (T8) - Snapshot.withMutableSnapshot + SnapshotApplyConflictException retry in push/addSignal/removeSignal (T9) - dataVersion mutableLongStateOf — Compose-observable, idle = 0 recompositions (T10) - RenderLoop.kt deleted; targetFps @Deprecated (T6/T10) - Single snapshot per signal per frame via per-signal scratch arrays in SignalEntry (T11) - M4 binning Tier1/Tier2: firstTs/V, minTs/V, maxTs/V, lastTs/V with chronological dedup (T12) — no C7 spikes - NaN/Inf/backward-timestamp guards on push, KDoc contract, per-signal lastPushedTs (T13) **Test gap fill:** - NumberFormat extracted from AxisRenderer to internal object (T14) — 38 tests - TieredBufferTest +15 tests (tier roll, window crossing, clear, edge cases) (T15) - LodDecimatorTest +10 LTTB-specific tests (T15) - iosSimulatorArm64Test: **33 → 107 tests** (target was ≥60) **Capacity changes:** - TIER1_CAPACITY 12k → 24k (×2 → ×4) - TIER2_CAPACITY 5.4k → 10.8k (×2 → ×4) - TOTAL_CAPACITY 77.4k → 94.8k - Memory per signal: ~1.14 MB (was ~760 KB pre-bump) **Deviations / deferred to v0.5.0:** - kotlinx-datetime 0.6.2 (not 0.7.x) — Kotlin 2.1.0 compat - ChartConfig.targetFps @Deprecated but kept for ABI stability - NumberFormat Long overflow @ 1e19 (safe via current routing) - LTTB upper-bound inclusive vs snapshot half-open semantic mismatch --- ## v0.5.0 — Architecture + Interaction (SHIPPED) Plan: .paul/phases/v0.5.0-architecture-plan.md (v2 deltas) Executed via: kmp-manager 6-phase flow, 6 P-groups, ~14 agent calls Completed: 2026-05-21 ### Delivered **Toolchain (D1):** - Kotlin 2.1.0 → 2.3.21 - Compose-Multiplatform 1.8.0 → 1.11.0 - Android Gradle Plugin 8.7.3 → 9.2.0 - Gradle 8.11.1 → 9.5.1 - coroutines 1.9.0 → 1.11.0, kotlin-test → 2.3.21 - Dropped `kotlinx-datetime`; swapped to stdlib `kotlin.time.Clock` (Kotlin 2.3 stable) - Dropped `iosX64` target (Compose-MP 1.11.0 incompat — Intel Mac sims deprecated) **Architecture (T1-T6, T10):** - T1: Bisect tier snapshot (`TieredBuffer.snapshotWindow`) — 26 new tests - T2: `LodStrategy` interface + `MinMaxLodStrategy` + `LttbLodStrategy` + `MinMaxLttbLodStrategy` (SOTA, 1.80× faster than pure LTTB on iOS sim; arXiv 2305.00332 ratio=4) - T3: `SignalRenderer` interface (public) + `LineSignalRenderer` default impl - T4: `AxisFormatter` interface + `TimeAxisFormatter` + `DecimalAxisFormatter` + `DateTimeAxisFormatter` + `UnitAxisFormatter` - T5: **HARD BREAK** — deleted `LodMode` enum + `LodDecimator` + `ChartConfig.targetFps`. Split `ChartConfig` → `DataConfig` + `AxisConfig` + `RenderConfig` + `FrameRate` sealed - T6: `@Immutable`/`@Stable` annotations — 0 unstable public types - T10: `RealtimeChartState.clear()` API **Interaction layer (T7):** - `ChartInteractionState` + `rememberChartInteractionState()` hoistable state - `ViewportMode` sealed: `Following` / `Frozen` / `History(anchorMs)` - `CrosshairState` + `SignalValueAt` (List, not Map — zero boxing) - `InteractionConfig` (zoomEnabled/panEnabled/tapCrosshairEnabled + clamps) - Pinch zoom + drag pan + tap crosshair + swipe-to-edge-resumes-Following - `InverseProjection`: pixel→ms + bisect-based nearest-sample **Perf finishing (T8, T9, D3):** - T8: `LineSignalRenderer.Stroke` cache + `AxisRenderer.TextStyle` cache (16-entry cap, single-thread UI) - T9: `Pair` removed (FloatArray out-param) + `signalsArray` cached on `RealtimeChartState` (invalidated by addSignal/removeSignal only) - D3: LTTB upper-bound aligned to half-open `[start, start+windowMs)` snapshot semantic **Correctness (D4):** - D4: `NumberFormat.formatFixed` Long overflow guard @ |v|≥1e19 → routes to scientific **Test gap fill:** - 107 → **207 tests** (+100) - New suites: lod/ (24 tests), interaction/ (29 tests), model/ChartConfigTest (8), render/AxisFormatterTest (10), render/AxisRendererTest (3), render/LineSignalRendererTest (2) **ABI:** - Baseline regenerated; apiCheck GREEN - `chart-realtime.api`: 161 → 428 LOC - `chart-realtime.klib.api`: 211 → 501 LOC **Deviations from plan:** - `iosX64` target dropped (Compose-MP 1.11.0 dropped Intel iOS sim variant) - `MinMaxLttb` perf 1.80× (paper claims 10× — gap = scalar Kotlin/Native vs Rust+SIMD; ≥1× acceptance met) - `signalsArray` cache NOT invalidated by `clear()` (entries preserved per T10 contract) **Highlights vs plan goals:** - Interaction layer S0 shipped (was "fatale senza") - HARD BREAK on T2/T5 per intake decision (no deprecated bridges) - All v0.4.0 deferred items (D1/D3/D4) absorbed --- ## v1.0.0 — Public Release (PLANNED) Plan: .paul/phases/v1.0.0-public-release-plan.md Effort: 2-3 giorni full-time + manual ops, ~10 agent calls Prereq: v0.4.0 + v0.5.0 shipped ### Highlights - Maven Central publishing (`dev.dtrentin:chart-realtime:1.0.0`) - GitHub Actions CI (Android + iOS) - SwiftUI iOS demo app consuming XCFramework - Benchmark vs Vico/KoalaPlot/MPAndroidChart con numeri reali - README professionale: GIF + badge + benchmark + onesta comparison table - CHANGELOG.md + CONTRIBUTING.md + CODE_OF_CONDUCT.md - Performance budget docs (frame time, memory, battery) - Logo + banner + demo GIF - Tag v1.0.0 + GitHub release con artifact --- ## Backlog (post v1.0.0) - Multi-Y axis / log scale - Annotations / threshold lines / regions - Headless data export (PNG/CSV) - CocoaPods publication - Swift Package Manager (SPM) - Wasm + desktop (jvm) targets - ScatterRenderer / AreaRenderer / BarRenderer (sfrutta SignalRenderer interface) - Legend composable --- *Roadmap updated: 2026-05-21 — post 3-reviewer audit*