- Dirty-flag render: dataVersion counter in RealtimeChartState, skip Canvas draw when no new data since last frame (zero GPU work when sensor idle) - targetFps=30 default in ChartConfig (pass null for max display refresh rate) - iOS targets: iosX64, iosArm64, iosSimulatorArm64 + Platform.ios.kt actual - KDoc: RealtimeChart params, dataVersion, ChartConfig.targetFps, LodMode entries, AxisLabelMode entries - README: fixed Maven coords, added LoD/AxisLabels/Material3 sections, updated feature list and performance notes - Tests: RealtimeChartStateTest (17 tests, dataVersion + signal lifecycle) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.2 KiB
8.2 KiB
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | duration | started | completed | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| v0.2.0-polish | v0.2.0 | chart-realtime |
|
|
|
|
|
|
|
|
~8h (multi-session) | 2026-05-20T00:00:00Z | 2026-05-21T00:00:00Z |
v0.2.0 Plan Summary
chart-realtime KMP library rebuilt from scratch: TieredBuffer (1h/20-signal), LTTB+MIN_MAX LoD, axis labels with INSIDE/BESIDE/HIDDEN modes, Material3 dynamic theming, Clean Architecture sensor domain — shipped as v0.5.0-SNAPSHOT.
Performance
| Metric | Value |
|---|---|
| Duration | ~8h multi-session |
| Started | 2026-05-20 |
| Completed | 2026-05-21 |
| Versions shipped | 0.2.0→0.3.0→0.4.0→0.4.1→0.5.0-SNAPSHOT |
| Git commits | 3 (initial + 2 incremental) |
| Files modified | 20+ |
Acceptance Criteria Results
| Criterion | Status | Notes |
|---|---|---|
| Axis text labels visible | Pass | AxisRenderer TextMeasurer, INSIDE/BESIDE/HIDDEN modes |
| Dynamic X-window from UI | Pass | Slider 2–3600s, StateFlow, MAX_BUFFER_SECONDS=3600 |
| Material3 theme compliance | Pass | rememberMaterialChartTheme(), dynamic color API 31+ |
| User-decided signal colors | Pass | SignalConfig.color, ChartTheme separate |
| Camera cutout / edge-to-edge | Pass | enableEdgeToEdge() + Scaffold innerPadding |
| 1h data support without OOM | Pass | TieredBuffer ~18MB for 6 signals |
| No tier boundary visual artifact | Pass | MIN_MAX composable + tier0 lower-bound fix |
| LodDecimator zero-alloc | Pass | Class with pre-alloc scratch arrays |
| Negative X-axis values | Pass | formatTimeSec handles negative elapsed time |
| Sensor rate cap 200Hz | Pass | SensorRepositoryImpl 5_000μs |
| Package renamed dev.dtrentin | Pass | eu.henesis → dev.dtrentin everywhere |
| Remote git repository | Pass | ssh://3nt-git.duckdns.org:222/davide.trentin/KMPCharts.git |
Accomplishments
- TieredBuffer: 3-tier ring buffer (tier0=5min@200Hz, tier1=10min@10Hz MIN_MAX, tier2=45min@1Hz MIN_MAX). ~18MB for 6 signals vs 259MB naive flat at 1000Hz assumption
- MIN_MAX composability: tier boundary artifacts eliminated. MIN(tier_mins)=global_MIN mathematically proven. MEAN removed as inherently dishonest for raw sensor data
- LTTB algorithm: O(n) Largest-Triangle-Three-Buckets in LodDecimator. Preserves peaks, smooth trend line, better than mean without signal distortion
- Axis overhaul: INSIDE/BESIDE/HIDDEN modes, chartLeft/chartBottom insets, T0-relative timestamps (mm:ss/hh:mm:ss), scientific notation for |y|<0.01 or >1e5, negative values, grid toggle
Deviations from v0.2.0 Plan
| Type | Count | Description |
|---|---|---|
| Scope additions | 15+ | All features beyond Material3/axis/xWindow/scratch |
| Auto-fixed bugs | 8 | Tier boundary, LTTB samplePtr, X label sticky, Y label clipping, LoD path unravel, etc. |
| Deferred | 1 | iOS expect/actual — still commonMain only |
Key deviations:
- Phase 4 (scratch optimization): addressed differently — LodDecimator converted from
objecttoclasswith pre-allocated instance fields, not param-passing as planned - CircularBuffer replaced by TieredBuffer at storage level: larger scope than originally planned
- MEAN LodMode added then removed in same milestone after analysis showed it was harmful
Key Decisions
| Decision | Rationale | Impact |
|---|---|---|
| TieredBuffer over flat ring | O(N×constant) memory, scales to 20+ signals at any rate | Core buffer architecture |
| MIN_MAX tier binning | Composable: MIN(mins)=global_MIN, no artifacts | Eliminates tier discontinuity |
| MEAN removed from LodMode | Introduces synthetic values never in raw signal | Cleaner API, honest visualization |
| Sensor cap 200Hz not FASTEST | Thermal/battery optimization, 200Hz exceeds visual need | Reduces CPU interrupts 4-10× |
| dev.dtrentin namespace | Personal project, not company IP | Package identity |
Bugs Fixed
| Bug | Root Cause | Fix |
|---|---|---|
| TieredBuffer tier artifact | tier0 snapshot lacked ts >= tier0BoundaryMs filter → double-inclusion → col-sort broken |
Added tier0Start = maxOf(windowStart, tier0BoundaryMs) |
| LoD path unravel | LodDecimator mapped out-of-window samples (tRelMs<0) to x=0 | Added in-window filter before binning |
| X label sticky at axis | coerceAtLeast(chartLeft) clamped all early labels to axis line |
Replaced with if (labelX >= chartLeft) skip |
| Y labels clipped bottom | Used raw 14f px instead of density-aware sp |
with(this) { 12.sp.toPx() } |
| Signal line outside chart | No clipRect on drawPath | Added clipRect(left=chartLeft…) |
| Negative X shows "0s" | coerceAtLeast(0L) |
abs() + - prefix for negative |
| OOM at MAX_X_WINDOW=3600 | MAX_SAMPLE_RATE=1000Hz assumed, 259MB pre-alloc | Reduced to 200Hz, TieredBuffer replaces flat ring |
Next Phase Readiness
Ready:
- Library stable at v0.5.0-SNAPSHOT, published to mavenLocal
- Remote git:
ssh://3nt-git.duckdns.org:222/davide.trentin/KMPCharts.git - AndroidChartsApp consuming library, builds clean
- Clean Architecture sensor domain in place
Potential next work:
- Dirty flag render (skip frame if no new data) — thermal/battery improvement
- targetFps=30 default — thermal improvement
- iOS expect/actual for currentTimeMs (currently Android only)
- Publish to Maven Central or GitHub Packages
- KDoc on public API surface
- README with integration example
Deferred:
- iOS support (expect/actual beyond currentTimeMs)
- Adaptive sensor rate based on xWindowSeconds
Phase: v0.2.0-polish, completed 2026-05-21