KMPCharts/CONTRIBUTING.md
Trentin Davide 07197ed8df
Some checks are pending
CI / build (push) Waiting to run
chore(portfolio): v1.0.0 prep — docs, CI, demos
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>
2026-05-22 10:54:26 +02:00

5.8 KiB
Raw Blame History

Contributing to chart-realtime

Thanks for considering a contribution. This document covers the build process, project conventions, and the PR workflow.

Project layout

chart-realtime/          Kotlin Multiplatform library module
├── src/commonMain/      Shared code (Android + iOS)
├── src/commonTest/      Shared tests
├── src/androidMain/     Android-only code (currently empty)
├── src/iosMain/         iOS-only code (currently empty post-v0.5.0)
└── api/                 ABI baseline (managed by BCV)

app/                     Android demo app (sandbox)
samples/ios/             SwiftUI iOS demo (planned for v1.0.0)
.paul/                   Project planning state (PAUL workflow)

Prerequisites

  • JDK 21 (Temurin recommended)
  • Xcode (for iOS targets; macOS only)
  • Android SDK with compileSdk 35
  • No global Gradle install needed — wrapper provided

Building

# Library — Android variant
./gradlew :chart-realtime:assembleRelease

# Library — iOS variants
./gradlew :chart-realtime:compileKotlinIosArm64
./gradlew :chart-realtime:compileKotlinIosSimulatorArm64

# XCFramework (consumes the library from Swift)
./gradlew :chart-realtime:assembleChartRealtimeXCFramework

# Android demo app
./gradlew :app:installDebug

# Publish library to local Maven (for consumer testing)
./gradlew :chart-realtime:publishToMavenLocal

Testing

# Shared common tests run on iOS simulator (canonical CI gate)
./gradlew :chart-realtime:iosSimulatorArm64Test

# ABI compatibility check (must stay green; regen via apiDump only on intentional break)
./gradlew :chart-realtime:apiCheck
./gradlew :chart-realtime:apiDump

207 tests on the canonical run as of v0.5.0. Any PR must keep that count from shrinking.

Code style

  • Kotlin official conventions; explicitApi() Strict enforced on chart-realtime
  • 4-space indent, no tabs
  • 120-column soft limit; wrap when readability suffers
  • Avoid !! and @Suppress in commonMain (audit blockers since v0.4.0)
  • @Immutable on data classes participating in @Composable parameter inference; @Stable on mutable state holders observing through MutableState
  • Use kotlin.time.Clock for current time; do not reintroduce kotlinx-datetime

Architecture conventions

  • Buffer layer (buffer/) — zero-alloc data structures. Pre-allocated scratch arrays. No allocations on the render hot path
  • LoD layer (lod/) — pluggable LodStrategy impls. Each constructor takes maxCount + maxPixelWidth to size its scratch arrays once
  • Render layer (render/) — internal object for the Canvas extension funs. Cache Stroke / TextStyle instances; rely on Compose TextMeasurer LRU for text layout
  • Interaction layer (interaction/) — hoistable @Stable state holders. Mutations route through Compose-observable backing state. Pointer-input lambdas read from LongArray cache slots populated inside the draw lambda (1-frame stale is acceptable for gesture handling)

Pull request workflow

  1. Open an issue first for non-trivial changes (new features, API additions, performance work). Bug fixes can skip this
  2. Branch from master. Name: feat/<short>, fix/<short>, refactor/<short>
  3. Write tests. Coverage requirements:
    • Bug fix: regression test reproducing the bug, then the fix
    • New public API: unit tests for happy path + edge cases
    • Performance change: benchmark before/after numbers in PR body
  4. Run the full gate locally before pushing:
    ./gradlew :chart-realtime:iosSimulatorArm64Test \
               :chart-realtime:assembleRelease \
               :chart-realtime:apiCheck \
               :app:assembleDebug
    
  5. ABI changes — if apiCheck fails:
    • If the change is intentional and you accept the break, regenerate the baseline with ./gradlew :chart-realtime:apiDump, commit the diff, and call it out in the PR description
    • If the change is unintentional, fix the code instead
  6. Commit format<scope>: <imperative summary> for the subject. Body lists touched modules and intent. Example:
    feat(interaction): add momentum scrolling to drag pan
    
    Modules: chart-realtime (interaction, RealtimeChart)
    
  7. No --no-verify on commit hooks. Investigate and fix the underlying issue if a hook fails
  8. Squash on merge for small PRs; preserve commits for large feature work

Issue triage

Bug reports must include:

  • Affected version
  • Platform (Android + API level / iOS + sim/device + iOS version)
  • Reproducer (smallest snippet that triggers the issue)
  • Expected vs actual behavior

Feature requests must include:

  • Use case (the underlying problem, not the proposed solution)
  • Why the existing API doesn't already solve it
  • Acceptance criteria (what "done" looks like)

Performance philosophy

Library targets sustained 200Hz × multi-signal sensor data with bounded memory. The hot path is the per-frame Compose recomposition + Canvas draw lambda.

Three rules:

  1. No allocations on the render hot path. All scratch arrays pre-allocated; Stroke / TextStyle cached; Pair and Map iterators replaced with FloatArray out-params and cached arrays
  2. Snapshot once per signal per frame. SignalEntry.scratchTs / scratchV pre-allocated; the Y-range scan and the path generation read the same snapshot
  3. Bounded memory regardless of session length. CircularBuffer.writeIndex is Long; tier ring buffers overwrite oldest first; 1h buffer = ~1.14 MB per signal

Any change that breaks one of these requires explicit justification + benchmark numbers + tests that pin the new behavior.

Reporting security issues

Email davide.trentin@henesis.eu directly. Do not open a public issue.

License

By contributing, you agree your contributions are licensed under the MIT License of this project.