Ship 15-task plan via kmp-manager group-by-group flow. Library moves
from "prototype" to "senior-engineer-built KMP library" per 3-reviewer
audit (android-reviewer + mobile-performance-reviewer + mobile-architect).
Critical fixes:
- LICENSE MIT (T1) — legal blocker resolved
- explicitApi() Strict + BCV 0.16.3 + klib enabled (T2) — ABI locked
baseline: chart-realtime.api 161 LOC + chart-realtime.klib.api 211 LOC
- Internal lockdown: CircularBuffer, TieredBuffer, LodDecimator,
dataVersion, rememberFrameTick (T3)
- kotlinx-datetime 0.6.2 replaces expect/actual currentTimeMs (T4)
Platform.kt + .android.kt + .ios.kt deleted
- CircularBuffer.writeIndex Int -> Long (T5) — fix 124d overflow @ 200Hz
- Remove !! and @Suppress("UNUSED_EXPRESSION") from commonMain (T6)
- Remove dead config: maxBufferSeconds, xLabelDecimals,
SignalConfig.label (T7)
Correctness:
- POSITIVE_INFINITY/Float.MAX_VALUE sentinels -> hasData flag (T8)
- Snapshot.withMutableSnapshot + SnapshotApplyConflictException retry
in push/addSignal/removeSignal (T9)
- dataVersion mutableLongStateOf — Compose-observable, idle = 0
recompositions (T10) — RenderLoop.kt deleted, targetFps @Deprecated
- Single buffer.snapshot() per signal per frame via SignalEntry
per-signal scratch arrays (T11) — render-time snapshot cost halved
- M4 binning Tier1/Tier2: firstTs/V + minTs/V + maxTs/V + lastTs/V
with chronological dedup (T12) — no C7 vertical spike artifacts.
TIER1/TIER2 CAPACITY x2 -> x4 (TOTAL 77.4k -> 94.8k)
- NaN/Inf/backward-timestamp guards on push (T13) — silent drop,
per-signal lastPushedTs tracking, KDoc contract
Test gap fill:
- NumberFormat extracted from AxisRenderer to internal object (T14)
+38 tests pinning rounding/scientific/time-format behavior
- TieredBufferTest +15 tests: tier roll, window-crossing, clear,
edge cases (T15)
- LodDecimatorTest +10 LTTB-specific branch coverage tests (T15)
Test count: 33 -> 107 (+74).
ABI: 211/272 -> 161/211 LOC (locked, baseline committed).
Deferred to v0.5.0:
- Bump kotlinx-datetime 0.6.2 -> 0.7.x (needs Kotlin 2.1.20+)
- Remove ChartConfig.targetFps (currently @Deprecated, ignored)
- NumberFormat Long overflow @ 1e19 (safe via current routing)
- LTTB upper-bound inclusive vs snapshot half-open semantic mismatch
- Macrobench setup for -30% frame-time verification
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.8 KiB
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 | - | Planned | - |
| 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)
applyDefaultHierarchyTemplate()wires iosMain/iosTest across targetslinkDebugFrameworkIosSimulatorArm64greeniosSimulatorArm64Testgreen — 33 tests, 0 failures- XCFramework
ChartRealtimeproduced (debug + release): ios-arm64 + ios-arm64_x86_64-simulator slices - Pre-existing compile bugs fixed:
@Volatile→kotlin.concurrent.Volatileimport@JvmName→kotlin.jvm.JvmNameimport (OptionalExpectation)String.formatin AxisRenderer → manualformatFixed/formatScientific/pow10helpersNSDate.date()→NSDate()+timeIntervalSinceReferenceDate+ 1970 epoch offset
- Android non-regression confirmed (
assembleRelease,publishToMavenLocal --dry-run) - Local Mac config: removed Linux JDK pin from
gradle.properties, addedlocal.propertiesfor 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 (PLANNED)
Plan: .paul/phases/v0.5.0-architecture-plan.md Effort: 5-7 giorni full-time, ~12 agent calls Prereq: v0.4.0 shipped
Highlights
- Interaction layer S0 (pinch zoom + drag pan + crosshair tap) — fatale senza
- LodStrategy/SignalRenderer/AxisFormatter interfaces (apri estensibilità)
- MinMaxLTTB SOTA algorithm (10x faster than LTTB puro, arXiv 2305.00332)
- Bisect tier snapshot per timestamp window (30x perf win)
- ChartConfig split DataConfig/AxisConfig/RenderConfig
- FrameRate sealed (replace
targetFps: Int?nullable-as-sentinel) - Compose @Stable/@Immutable annotations
- Cache Stroke + TextStyle + TextLayoutResult (zero-alloc render reale)
- Replace Pair<Float,Float> return + Map iter alloc
- RealtimeChartState.clear() API
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