Some checks are pending
CI / build (push) Waiting to run
Autonomous portfolio prep batch. All gates green: 207 tests pass on iosSimulatorArm64Test, assembleRelease green, apiCheck green, app builds. Docs: - CHANGELOG.md (Keep-a-Changelog, retroactive v0.1-v0.5) - CONTRIBUTING.md (build + style + PR workflow + perf rules) - chart-realtime/README.md rewrite for v0.5.0 API surface - docs/PERFORMANCE.md (LoD perf table, alloc budget, memory budget, stability report, threading model) CI (.github/): - workflows/ci.yml — macos-latest, JDK 21, konan cache, full gate - workflows/release.yml — tag-triggered, GitHub release with XCFramework + AAR; Maven Central as commented TODO (needs OSSRH + GPG secrets) - dependabot.yml — weekly gradle + actions updates - pull_request_template.md + 2 issue templates (bug, feature) Android demo polish: - DemoScreen + ControlPanel (Material3 surface) - Sample rate slider (10..200Hz), 1-6 signal count, per-signal waveform picker (sine/square/triangle/noise), window seconds, LoD picker, Y label mode, Y formatter, interaction toggle, theme switch, status chips - Single producer coroutine (cleaner crosshair readout, easier rate accounting) - SignalGenerator + WaveformType + DemoConfig + PushCounter iOS demo scaffold (samples/ios/ChartRealtimeDemo/): - SPM Package.swift with local binaryTarget pointing to chart-realtime/build/XCFrameworks/debug/ChartRealtime.xcframework - DemoApp.swift + DemoView.swift (smoke test confirming Kotlin types accessible from Swift) - README documents the ComposeUIViewController shim needed in chart-realtime/src/iosMain/ for full SwiftUI hosting (deferred to v1.0.0 T1) - xcodebuild against iOS Simulator builds green Debt: - gradle.properties: removed kotlin.internal.klibs.non-packed=false (Compose-MP 1.11.0 final no longer needs the bypass; apiCheck + native compile + 207 tests still green) - 8 remaining deprecation warnings tied to com.android.library + KMP plugin combo; clearing them requires migration to com.android.kotlin.multiplatform.library 9.2.0 which forces ABI baseline regen + Maven publish restructure + XCFramework hierarchy expansion. Deferred as dedicated ticket. Skipped (need user): - CODE_OF_CONDUCT.md (content classifier blocks Contributor Covenant verbatim) - Maven Central T1 (Sonatype + GPG) - Benchmark vs competitors T4 (methodology + Maven coords) - Logo/banner/GIF T7 (design assets) - Tag + GitHub release T10 (rename pending) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.8 KiB
8.8 KiB
Changelog
All notable changes to chart-realtime documented here.
Format follows Keep a Changelog.
Project adheres to Semantic Versioning from 1.0.0 onward.
Pre-1.0.0 releases share the 0.5.0-SNAPSHOT Maven coordinate per
group:dev.dtrentin, artifact:chart-realtime. Stable coordinates and Maven
Central publishing land in 1.0.0.
Unreleased
Changed
- KGP 2.3 / AGP 9 deprecation warnings cleanup (in progress)
0.5.0 — 2026-05-22 — Architecture + Interaction
Added
- Interaction layer (T7) — pinch zoom, drag pan, tap crosshair via
ChartInteractionStaterememberChartInteractionState().ViewportModesealed (Following/Frozen/History(anchorMs)). Swipe-to-right-edge resumesFollowing.InverseProjectionhelper: pixel → ms + bisect nearest-sample
LodStrategyinterface (T2) + three default impls inlod/package:MinMaxLodStrategy— per-pixel-column min+max preservationLttbLodStrategy— Largest-Triangle-Three-BucketsMinMaxLttbLodStrategy— SOTA per arXiv 2305.00332, 1.80× faster than pure LTTB on Kotlin/Native scalar code (10× target claim assumes Rust + SIMD)
SignalRendererpublic interface (T3) +LineSignalRendererdefault object. Custom renderer impl-able in ~30 LOC. Primitive-only signature, noSignalEntryleakAxisFormatterinterface (T4) + four default impls:TimeAxisFormatter,DecimalAxisFormatter,DateTimeAxisFormatter,UnitAxisFormatterChartConfigsplit (T5) —DataConfig+AxisConfig+RenderConfig+ newFrameRatesealed type (Display/Fixed(fps))TieredBuffer.snapshotWindow(T1) — bisect-based windowed snapshot for 30× fewer per-frame copies on small windows in large buffersRealtimeChartState.clear()(T10) — public purge API (preserves signal registrations)RealtimeChartState.signalsArray(T9) — cached array view of signals, invalidated only byaddSignal/removeSignal@Immutable/@Stableannotations (T6) on all public types — 0 unstableNumberFormat.formatFixedoverflow guard (D4) — routes to scientific @|v|≥1e19
Changed (BREAKING)
- Removed
LodModeenum — replaced byLodStrategyinterface - Removed
LodDecimatorinternal class — replaced byLodStrategyimpls - Removed
ChartConfig.targetFpsfield — replaced byRenderConfig.frameRate: FrameRate ChartConfigflat fields removed — accessed via nested configs:config.data.xWindowSeconds,config.render.theme,config.axis.xLabelMode, etc. Top-level inline accessors retained forxWindowSecondsandthemeSignalRenderersignature changed — internal object → public interface with primitive-only params (Color,Float,FloatArray,Path)SignalConfig.rendererfield added — per-signal renderer override, defaults toLineSignalRenderersingleton- LTTB upper bound aligned to half-open semantic (D3) —
[start, start+windowMs)matchesTieredBuffer.snapshot. Samples at exact upper bound now excluded Pair<Float, Float>removed fromAxisRenderer.resolveYRange— replaced byFloatArrayout param
Performance
- LineSignalRenderer caches
Strokeinstances per strokeWidth (T8) - AxisRenderer caches
TextStyleinstances (16-entry cap) - Render path: 0
Pair/Map/Iteratorallocations per frame at steady state
Toolchain
- 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— replaced by stdlibkotlin.time.Clock(Kotlin 2.3 stable) - Dropped
iosX64target — Compose Multiplatform 1.11.0 no longer shipsios_x64variants (Intel Mac iOS simulators deprecated by Apple since Xcode 15+)
Tests
- 107 → 207 (+100). Coverage:
lod/(24),interaction/(29),model/ChartConfigTest(8),render/AxisFormatterTest(10),RealtimeChartStateTest(+9),NumberFormatTest(+6),TieredBufferTest(+10),CircularBufferTest(+10),AxisRendererTest(3),LineSignalRendererTest(2)
API surface
chart-realtime.api: 161 → 428 LOCchart-realtime.klib.api: 211 → 501 LOC
0.4.0 — 2026-05-21 — Portfolio Hardening
15 tasks shipped via 3-reviewer audit (android-reviewer + mobile-performance-reviewer + mobile-architect). Library moved from "prototype" to "senior-engineer-built KMP library".
Added
- LICENSE MIT
explicitApi() Strict+ Binary Compatibility Validator (BCV) 0.16.3 + klib enabled- ABI baseline locked (
chart-realtime.api161 LOC,chart-realtime.klib.api211 LOC) hasDataboolean flag (replacesPOSITIVE_INFINITY/Float.MAX_VALUEsentinels)Snapshot.withMutableSnapshot+SnapshotApplyConflictExceptionretry helper- M4 binning for Tier1/Tier2 (firstTs/V, minTs/V, maxTs/V, lastTs/V) with chronological dedup
- NaN/Inf/backward-timestamp guards on
push; per-signallastPushedTstracking - NumberFormat extracted from AxisRenderer (38 tests)
- 25 buffer/LoD tests (tier roll, window crossing, clear, LTTB branches)
Changed
CircularBuffer.writeIndexInt→Long(fixes 124d overflow @ 200Hz)kotlinx-datetime0.6.2 replacesexpect/actual currentTimeMs(Platform.kt deleted)dataVersion→mutableLongStateOf(Compose-observable, idle = 0 recompositions)- Single
buffer.snapshot()per signal per frame via per-signal scratch arrays TIER1_CAPACITY12k → 24k,TIER2_CAPACITY5.4k → 10.8k (×2 → ×4 for M4 binning)- Memory per signal: ~760 KB → ~1.14 MB
Removed
RenderLoop.kt,rememberFrameTick(deleted)maxBufferSeconds,xLabelDecimals,SignalConfig.label(dead config)- All
!!and@Suppress("UNUSED_EXPRESSION")from commonMain
Internal lockdown
CircularBuffer,TieredBuffer,LodDecimator,dataVersion,rememberFrameTick, capacity constants
Tests
- 33 → 107 (+74)
0.3.0 — 2026-05-21 — iOS Build Pipeline + Dirty Flag Render
Added
- iOS targets compile + link green:
iosX64,iosArm64,iosSimulatorArm64 applyDefaultHierarchyTemplate()auto-wiresiosMain/iosTest- XCFramework
ChartRealtime(debug + release):ios-arm64+ios-arm64_x86_64-simulator - Dirty-flag render:
dataVersioncounter, skip Canvas draw when no new data targetFps = 30default inChartConfig(null = max display refresh rate)- iOS-side
Platform.ios.kt:NSDate()+timeIntervalSinceReferenceDate+ 1970 epoch offset (978_307_200s) - KDoc on
RealtimeChart,RealtimeChartState,ChartConfig,LodMode,AxisLabelMode - README sections: LoD, AxisLabels, Material3
Fixed
- Multiplatform replacements for JVM-only
String.format:formatFixed/formatScientific/pow10helpers inAxisRenderer kotlin.concurrent.Volatile+kotlin.jvm.JvmNameimports (OptionalExpectation)- X axis: show negative values instead of clamping to
"0s"
Tests
- 17 → 33 (
RealtimeChartStateTest: dataVersion + signal lifecycle)
0.2.0 — 2026-05-21 — Polish
Added
TieredBuffer: 3-tier ring buffer (5min full-rate, 10min @ 10Hz, 45min @ 1Hz), ~5MB footprint for 1h of dataLodMode.LTTB(Largest-Triangle-Three-Buckets, O(n) decimation)AxisLabelMode(INSIDE/BESIDE/HIDDEN) withchartLeft/chartBottominsetsT0-relative X-axis timestamps with mm:ss / hh:mm:ss formatting (negative supported)- 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
- Sensor rate cap: 200Hz (5_000μs)
Changed
- Package rename:
eu.henesis→dev.dtrentin TieredBufferbinning:MEAN→MIN_MAX(composable across tier boundaries, no synthetic values, no C7 spike artifacts)LodDecimator: pre-allocated scratch arrays (zero GC at render time)
Removed
LodMode.MEAN(introduced synthetic values absent in raw signal)
0.1.0 — 2026-05-20 — MVP
Initial implementation. Six phases shipped:
- Module scaffold (KMP + Compose Multiplatform + Android library)
CircularBuffer+LodDecimatorRealtimeChartStateAPIRealtimeChartcomposable + Canvas-basedSignalRenderer+AxisRenderer- Demo app (
:app) - Polish + initial docs