diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-04-03 08:05:24 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-04-03 08:05:24 +0000 |
| commit | 5d358cd570075d36a61f9a37bb80c64f8a0a7e2a (patch) | |
| tree | fa03f40d3c6a96da726b591d269c152adbdf7210 /scripts/.claude/ct-wind-wiring.txt | |
| parent | 9417a7c6b08da362ad97e85973b7570e05d4f0b5 (diff) | |
chore(stories): add claudomator stories for unused results and faked data
6 stories covering findings from codebase audit:
- ct-remove-mock-tidal: remove random fake tidal currents near Solent
- ct-wire-tidal-to-map: wire tidalCurrentState to MapHandler (never called)
- ct-wire-anchor-to-map: wire anchorWatchState to map overlay (text-only)
- ct-show-wind-direction: display TWD fetched but not shown in sheet
- ct-show-swell-direction: display swell dir fetched but not shown
- ct-fix-weather-fallback: remove silent SF fallback in WeatherActivity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'scripts/.claude/ct-wind-wiring.txt')
| -rw-r--r-- | scripts/.claude/ct-wind-wiring.txt | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/scripts/.claude/ct-wind-wiring.txt b/scripts/.claude/ct-wind-wiring.txt new file mode 100644 index 0000000..09768ab --- /dev/null +++ b/scripts/.claude/ct-wind-wiring.txt @@ -0,0 +1,156 @@ +Context +------- +MainViewModel.addGpsPoint() (android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt, +line 67) builds TrackPoint with hardcoded wind zeroes: + + windSpeedKnots = 0.0, windAngleDeg = 0.0, isTrueWind = false + +LocationService already exposes live NMEA wind data: + LocationService.nmeaWindDataFlow: SharedFlow<WindData> (companion object, line 362) + +WindData (android-app/app/src/main/kotlin/org/terst/nav/sensors/WindData.kt): + windAngle: Double // degrees, relative or true + windSpeed: Double // knots + isTrueWind: Boolean + timestampMs: Long + +TrackPoint (android-app/app/src/main/kotlin/org/terst/nav/track/TrackPoint.kt) already has +windSpeedKnots, windAngleDeg, isTrueWind fields — they just aren't populated. + +Goal +---- +Cache the latest WindData in MainViewModel and use it when building TrackPoints. +Default to zero wind if no NMEA wind sentence has arrived yet. + +Step 1 — Red: write failing tests +---------------------------------- +Create android-app/app/src/test/kotlin/org/terst/nav/ui/MainViewModelWindTest.kt + +Setup boilerplate needed (Dispatchers.setMain / resetMain with UnconfinedTestDispatcher): + + import androidx.arch.core.executor.testing.InstantTaskExecutorRule + import kotlinx.coroutines.Dispatchers + import kotlinx.coroutines.ExperimentalCoroutinesApi + import kotlinx.coroutines.test.UnconfinedTestDispatcher + import kotlinx.coroutines.test.resetMain + import kotlinx.coroutines.test.runTest + import kotlinx.coroutines.test.setMain + import org.junit.After + import org.junit.Assert.assertEquals + import org.junit.Before + import org.junit.Rule + import org.junit.Test + import org.terst.nav.sensors.WindData + import org.terst.nav.ui.MainViewModel + + @OptIn(ExperimentalCoroutinesApi::class) + class MainViewModelWindTest { + + @get:Rule val instantTask = InstantTaskExecutorRule() + private val dispatcher = UnconfinedTestDispatcher() + + @Before fun setUp() { Dispatchers.setMain(dispatcher) } + @After fun tearDown() { Dispatchers.resetMain() } + + @Test fun `addGpsPoint uses zero wind when no wind update received`() = runTest { + val vm = MainViewModel() + vm.startTrack() + vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) + val pt = vm.trackPoints.value.first() + assertEquals(0.0, pt.windSpeedKnots, 0.001) + assertEquals(0.0, pt.windAngleDeg, 0.001) + assertEquals(false, pt.isTrueWind) + } + + @Test fun `addGpsPoint uses latest wind data after updateWind`() = runTest { + val vm = MainViewModel() + vm.updateWind(WindData(windAngle = 45.0, windSpeed = 15.5, isTrueWind = true, timestampMs = 1000L)) + vm.startTrack() + vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) + val pt = vm.trackPoints.value.first() + assertEquals(15.5, pt.windSpeedKnots, 0.001) + assertEquals(45.0, pt.windAngleDeg, 0.001) + assertEquals(true, pt.isTrueWind) + } + + @Test fun `addGpsPoint reflects wind update between fixes`() = runTest { + val vm = MainViewModel() + vm.startTrack() + vm.addGpsPoint(37.0, -122.0, 5.0, 90.0) + vm.updateWind(WindData(windAngle = 180.0, windSpeed = 8.0, isTrueWind = false, timestampMs = 2000L)) + vm.addGpsPoint(37.1, -122.0, 5.0, 90.0) + val pts = vm.trackPoints.value + assertEquals(0.0, pts[0].windSpeedKnots, 0.001) + assertEquals(8.0, pts[1].windSpeedKnots, 0.001) + } + } + +Run and confirm RED: + cd android-app && ./gradlew :app:testDebugUnitTest --tests "*MainViewModelWind*" + +Step 2 — Green: implement +-------------------------- +In android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt: + +1. Add import: + import org.terst.nav.sensors.WindData + +2. Add field after trackRepository: + private var latestWind: WindData? = null + +3. Add method: + fun updateWind(wind: WindData) { + latestWind = wind + } + +4. Update addGpsPoint() to use latestWind: + fun addGpsPoint(lat: Double, lon: Double, sogKnots: Double, cogDeg: Double) { + val wind = latestWind + val point = TrackPoint( + lat = lat, lon = lon, + sogKnots = sogKnots, cogDeg = cogDeg, + windSpeedKnots = wind?.windSpeed ?: 0.0, + windAngleDeg = wind?.windAngle ?: 0.0, + isTrueWind = wind?.isTrueWind ?: false, + timestampMs = System.currentTimeMillis() + ) + if (trackRepository.addPoint(point)) { + _trackPoints.value = trackRepository.getPoints() + } + } + +Run and confirm GREEN: + cd android-app && ./gradlew :app:testDebugUnitTest --tests "*MainViewModelWind*" + +Step 3 — Wire: feed wind updates from LocationService +------------------------------------------------------ +In android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt, +inside observeDataSources(), add after the anchorWatchState collector: + + lifecycleScope.launch { + LocationService.nmeaWindDataFlow.collect { wind -> + viewModel.updateWind(wind) + } + } + +No additional imports needed (LocationService is already imported). + +Step 4 — Verify all tests pass +------------------------------- +cd android-app && ./gradlew :app:testDebugUnitTest + +Confirm all existing tests still pass alongside the 3 new wind tests. + +Step 5 — Commit and push +------------------------- +git add -A && git commit -m "feat(track): wire NMEA wind data into GPS track points + +MainViewModel caches the latest WindData from LocationService.nmeaWindDataFlow +via updateWind(). addGpsPoint() populates TrackPoint wind fields from the cache, +defaulting to zero if no NMEA wind sentence has arrived yet. + +MainActivity.observeDataSources() feeds LocationService.nmeaWindDataFlow +into viewModel.updateWind() alongside the existing GPS and anchor observers. + +3 new unit tests in MainViewModelWindTest verify zero-default, wind capture, +and mid-track wind update behaviour." && git push origin main |
