Skip to content

Release v2.1.0 - Compose Integration, Persistent Dispatch & Test Hardening#2

Merged
vietnguyentuan2019 merged 5 commits intomainfrom
release/v2.1.0
Mar 16, 2026
Merged

Release v2.1.0 - Compose Integration, Persistent Dispatch & Test Hardening#2
vietnguyentuan2019 merged 5 commits intomainfrom
release/v2.1.0

Conversation

@vietnguyentuan2019
Copy link
Contributor

Summary

  • Compose Multiplatform helpers: KRelayEffect<T> and rememberKRelayImpl<T> built-in composables with auto-unregister on dispose; KRelay.instance public property for cross-module access
  • Scope Token API: scopedToken() / cancelScope(token) for fine-grained queue cleanup per ViewModel
  • Persistent Dispatch: dispatchPersisted<T>() + SharedPreferencesPersistenceAdapter (Android) + NSUserDefaultsPersistenceAdapter (iOS)
  • Test hardening: 237 unit tests + 19 instrumented tests, all passing — JVM, iOS Simulator arm64, real Android device (Pixel 6 Pro, Android 16)
  • Bug fixes: KRelayMetrics wiring, iOS KClass bridging, Voyager 1.1.0-beta03, Android 15+ 16KB page alignment
  • Maven publishing: emptyJavadocJar added to all publications (Maven Central compliance)
  • README: rewritten with pain-first messaging, integration table, collapsible changelog sections

Test plan

  • ./gradlew :krelay:testDebugUnitTest — 237 tests, all pass (JVM)
  • ./gradlew :krelay:iosSimulatorArm64Test — 237 tests, all pass (iOS Simulator)
  • ./gradlew :krelay:connectedDebugAndroidTest — 19 tests, all pass (Pixel 6 Pro, Android 16)
  • ./gradlew :composeApp:compileDebugKotlinAndroid — builds clean
  • Demo app runs on device: all 5 demos functional including Voyager navigation
  • No Claude/AI references in any committed file or commit message

Nguyễn Tuấn Việt added 5 commits March 16, 2026 09:53
Priority 1 - Critical fixes:
- Add dispatchWithPriority() on KRelayInstance - fixes API inconsistency
  where priority dispatch existed only on the singleton, not on instances
- Fix Metrics.enabled flag: record*() methods now correctly no-op when
  metrics are disabled (was always recording regardless of flag)
- Add duplicate registration warning in debug mode - logs when register<T>()
  overwrites an existing alive implementation
- Fix iOS MainThreadExecutor comment: remove misleading "99% accurate" note,
  NSThread.isMainThread is the correct and reliable check
- Add CI/CD via GitHub Actions (.github/workflows/ci.yml) - NOTE: requires
  removing .github from .gitignore to enable tracking
- Add docs/LIFECYCLE.md: comprehensive Android/iOS lifecycle integration guide
  with Activity, Fragment, Compose, UIViewController, SwiftUI examples
- Update CHANGELOG.md with [Unreleased] v2.1.0 entry

Priority 2 - Important:
- Add Dokka 1.9.20 for API doc generation (./gradlew :krelay:dokkaHtml)
- Add version compatibility matrix to README (KRelay vs Kotlin/KMP/AGP/platforms)
- Add KRelayFlowAdapter.kt sample documenting KRelay + coroutines/Flow patterns
  and when to use KRelay vs Flow directly
- Add KRelayInstancePriorityTest: 6 tests verifying dispatchWithPriority
  on instances works correctly (queue, immediate, replay, isolation)
- Update MetricsTest and MetricsIntegrationTest to opt-in enabled=true
…Guides

Priority 3 features:

- Persistent Dispatch: dispatchPersisted<T>() survives process death via
  named actions + ActionFactory pattern (KRelayPersistence.kt,
  PersistedDispatch.kt). Includes SharedPreferencesPersistenceAdapter
  (Android) and NSUserDefaultsPersistenceAdapter (iOS). PersistedCommand
  uses length-prefix serialization to handle all special characters.

- Compose Multiplatform: KRelayEffect<T> composable and rememberKRelayImpl<T>
  helper (KRelayCompose.kt) for lifecycle-safe registration via
  DisposableEffect.

- Integration guides: COMPOSE_INTEGRATION.md and SWIFTUI_INTEGRATION.md
  covering idiomatic patterns for both platforms.

- Test isolation fix in PersistedDispatchTest to prevent state pollution
  across the full JUnit test suite (all 161 tests pass).
New in v2.1.0 stability pass:

- scopeToken field on QueuedAction (optional, null = untagged)
- dispatch<T>(scopeToken, block) — tags queued action with caller identity
- cancelScope(token) on KRelayInstance + KRelay singleton — removes only
  actions tagged with the given token across all feature queues
- scopedToken() utility generates a unique, human-readable token per call
- All APIs are purely additive; existing code unchanged

Use in ViewModel to auto-clean lambda captures:
  private val token = scopedToken()
  relay.dispatch<ToastFeature>(token) { it.show("Done") }
  override fun onCleared() = relay.cancelScope(token)

Also fix DiagnosticDemo test isolation: add @BeforeTest/@AfterTest to
restore KRelay.actionExpiryMs and maxQueueSize to defaults after each
demo test, preventing config leak that caused intermittent failures in
MultiFeatureCoordinationDemo when test execution order placed
DiagnosticDemo.demoScenario6 (actionExpiryMs=0) before it.

171 tests, 0 failures.
…ening

## Core Library (krelay/)
- Add KRelay.instance public property for cross-module access
- Add dispatchWithPriority on KRelayInstance (was singleton-only)
- Add Scope Token API: scopedToken(), cancelScope(token), dispatch(token, block)
- Add resetConfiguration() on KRelayInstance and KRelay
- Add dispatchPersisted + KRelayPersistenceAdapter (SharedPreferences/NSUserDefaults)
- Add enqueueActionUnderLock() helper — eliminates ~50 lines of duplicated logic
- Fix KRelayMetrics wiring (recordDispatch/Queue/Replay now actually fire)
- Fix KRelayMetrics.enabled flag (was always recording regardless of flag)
- Fix iOS KClass bridging (register/dispatch now find correct interface key)
- Fix duplicate registration debug log

## Compose Integration (composeApp/)
- Add KRelayEffect<T> composable (auto-unregisters on dispose)
- Add rememberKRelayImpl<T> composable (register + return impl)
- Fix KRelayCompose.kt: KRelay.defaultInstance -> KRelay.instance (cross-module)
- Fix Voyager demo: upgrade to 1.1.0-beta03, DisposableEffect + rememberCoroutineScope
- Fix Android 15+ 16KB page alignment (android.allow_non_16k_pages)

## Testing
- Add 11 new test files: integration, stress, system, unit, instrumented
- Rewrite LockStressTest and ScopeTokenConcurrentStressTest for iOS GCD safety
- Fix EnqueueBehaviorIntegrationTest expiry timing (delay(5) + actionExpiryMs=0L)
- Fix SharedPreferencesPersistenceAdapterTest: JUnit4 arg order, scope name, waitForIdleSync
- Add CI/CD pipeline (.github/workflows/ci.yml)

## Maven Publishing
- Add emptyJavadocJar to all publications (Maven Central requirement)
- Update POM description to user-facing language
- Version: 2.1.0

## Documentation
- Rewrite README with pain-first messaging and integration table
- Update CHANGELOG.md: finalize [2.1.0] - 2026-03-16
- Add RELEASE_NOTES_2.1.0.md
- Update QUICK_REFERENCE.md, COMPOSE_INTEGRATION.md, ROADMAP.md
@vietnguyentuan2019 vietnguyentuan2019 merged commit ad7d893 into main Mar 16, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant