summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-26 07:12:44 +0000
committerClaude <noreply@anthropic.com>2026-05-26 07:12:44 +0000
commit8c1d1605f529e32876ba4cb325a019a311c5011d (patch)
treed983e88e63dd26a099143a5e71e6f356c7faeec5
parent8dbf3f883274fc0ddd16e5507f732629c85e3c91 (diff)
Update worklog: tack detection complete, storage complete, session prep
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
-rw-r--r--.agent/worklog.md202
1 files changed, 65 insertions, 137 deletions
diff --git a/.agent/worklog.md b/.agent/worklog.md
index 2d62bdb..6187ae5 100644
--- a/.agent/worklog.md
+++ b/.agent/worklog.md
@@ -1,152 +1,80 @@
# SESSION_STATE.md
-## Backlog (fix later)
+## Backlog
-- **Pirate mode** — Re-introduce as an Easter egg / toggle, not the default voice. Long-press the trip report header (or a hidden gesture) flips the narrative into pirate dialect. Keep the seamanlike default; pirate is opt-in fun.
+- **Pirate mode** — Easter egg / opt-in toggle, not the default voice. Long-press the trip report header flips the narrative into pirate dialect. Seamanlike voice stays default.
+- **Race mode tack detection** — Tighter windows (T_SETTLE ~10–15 s), wider STAB_MAX (~30°), shorter MIN_GAP_MS (~20 s) for quick successive tacks at race starts and mark roundings. Current mode is CRUISING (conservative). See `TackDetector.kt` constants.
+- **Persist tracks to Room** — Replace in-memory `_pastTracks` with a Room database. SAF write path is solid; the in-memory list is still the source of truth at runtime.
+- **AnchorWatchHandler UI** — Re-integrate into `activity_main.xml` and wire to the Safety Dashboard.
+- **Unit tests for trip generators** — `TripReportGenerator` and `PreTripReportGenerator` have no JVM tests yet.
-- **Tack detection is buggy, especially at low speed** — False positives at low SOG (GPS heading noise looks like tacks). Need minimum-SOG gate (e.g. skip detection when SOG < 1.5 kt) and review the stability window / MIN_DELTA thresholds against real tracks.
+---
+
+## Paused Task: Instrument Sheet Visual Redesign
+
+**Started:** 2026-04-06 · **Status:** Tasks 1–2 done; Tasks 3–7 pending
-## Current Task Goal
-Logbook + Trip Report Improvements — COMPLETE (2026-05-26)
+### What's being built
+Full visual redesign of the instrument bottom sheet:
+- `WaveView`: animated canvas divider (swell + wind waves + whitecaps), sky-blue above / ocean-blue below
+- `DirectionArrowView`: 14dp inline chevron in two palettes (SKY grey / OCEAN blue)
+- Direction arrows inline with all numeric values
+- `°` baked into HDG/COG (no separate unit label)
+- Forecast cells: value line 1, [arrow] bearing line 2 (swell adds period)
+- Imperial units throughout (ft for depth, wave height, swell)
+- Forecast labels: "Current" / "Waves" (no section header)
+- Reports section removed; touch-through prevented
-Delivered:
-- **Add notes/photos to finished track** — `+ Add note` button in `TrackDetailSheet` opens a dialog with text entry, camera, and gallery. Notes are saved with `timestampMs = track.endMs` so they fall within the track window and appear in `buildLogEvents()` automatically. The map is re-built via `logEventAdapter.update()` after save.
-- **Trip report single Nav voice** — Removed `NarrativeStyle` enum and the 4-style ChipGroup. `generateNarrative(summary)` now emits a concise `PASSAGE` header with date/time range, stats, conditions, and a timestamped deck log. `fragment_trip_report.xml` no longer has the style picker.
-- **Speed coloring fixed** — Replaced the broken `Expression.get("color")` (reads a string feature property, silently fails for `lineColor` on `LineLayer` in MapLibre Android 11.x) with `Expression.step(Expression.get("speed"), ...)` which maps the numeric `"speed"` property directly to color literals. `speedSegments()` no longer writes the unused `"color"` string property.
+### Progress
+- [x] Task 1: Remove report buttons, fix touch-through — commit `2d86c0b`
+- [x] Task 2: Update typography styles — commit `e79b678`
+- [ ] Task 3: Create `DirectionArrowView.kt`
+- [ ] Task 4: Create `WaveView.kt`
+- [ ] Task 5: Restructure `layout_instruments_sheet.xml`
+- [ ] Task 6: Refactor `InstrumentHandler.kt`
+- [ ] Task 7: Wire new views in `MainActivity.kt`, fix units
---
-## Previous Task Goal
-Instrument Sheet Visual Redesign — IN PROGRESS (2026-04-06)
+## Recently Completed
-**Plan:** `docs/superpowers/plans/2026-04-04-instrument-sheet-visual-redesign.md`
-**Spec:** `docs/superpowers/specs/2026-04-04-instrument-sheet-visual-redesign.md`
+### Tack Detection Redesign — 2026-05-26
+Full rewrite of `TackDetector.kt` (both `android-app` and `test-runner` mirrors).
-### Progress
-- [x] Task 1: Remove report buttons + fix touch-through — **DONE** (commit `2d86c0b`)
-- [x] Task 2: Update typography styles — **DONE** (commit `e79b678`)
-- [ ] Task 3: Create `DirectionArrowView` — pending
-- [ ] Task 4: Create `WaveView` — pending
-- [ ] Task 5: Restructure `layout_instruments_sheet.xml` — pending
-- [ ] Task 6: Refactor `InstrumentHandler` — pending
-- [ ] Task 7: Update `MainActivity` — wire new views and fix units — pending
+**Root causes fixed:**
+- Point-count window (HALF_WIN=2) gave wildly different reliability at 1 Hz vs 0.2 Hz
+- Only 2 points used for heading estimate — one noisy fix contaminated the result
+- Single-pair spread check fired on individual noisy fixes
+- No protection against GPS COG noise at low/zero SOG
-### What's being built
-A visual redesign of the instrument bottom sheet:
-- Animated wave canvas divider (swell height/period + wind waves + whitecaps) replacing the plain divider between instruments and forecast
-- Sky-blue gradient above wave, ocean blue below
-- `DirectionArrowView`: 14dp inline chevron compass indicator in two palettes (SKY grey / OCEAN blue)
-- Direction arrows inline with numeric values in all relevant cells
-- `°` baked into HDG/COG values (not a separate unit label)
-- Forecast cells: value on line 1, [arrow] bearing on line 2 (swell adds period)
-- Imperial units: feet for depth, wave height, swell height (all converted from metres)
-- Forecast labels: "Current" (not "Curr"), "Waves" (not "Wave"), no section header
-- Touch-through prevention: clickable/focusable on root layout
-- Reports section removed
-
-### Key files
-| File | Status |
-|---|---|
-| `layout_instruments_sheet.xml` | Partially done (Task 1 applied; full restructure in Task 5) |
-| `DirectionArrowView.kt` | Not created yet |
-| `WaveView.kt` | Not created yet |
-| `InstrumentHandler.kt` | Not refactored yet |
-| `MainActivity.kt` | Task 1 applied; Task 7 changes pending |
-| `themes.xml` / `dimens.xml` | Done |
+**New algorithm (CRUISING mode — conservative):**
+- Time-based 30 s settle windows before/after each candidate apex, with a 30 s guard zone
+- `circularMAD` stability check: rejects any window where heading spread > 20°. Handles anchor noise (MAD ≈ 90°) without any SOG gate — the stability check is sufficient.
+- `circularMean` via unit-vector averaging — correct 0°/360° wrap
+- `MAX_DELTA` raised to 160° (covers deep jibes the old 140° missed)
+- `START_SKIP_MS` reduced to 60 s
+- De-duplication uses adjacent-candidate comparison (not group-start), so a long raw-candidate stream from one maneuver stays as one group even if it spans > MIN_GAP_MS
+- Position pin refined to max instantaneous heading rate within the maneuver zone
+
+**Key constants:** `T_SETTLE=30s, T_MANEUVER=30s, STAB_MAX=20°, MIN_DELTA=60°, MAX_DELTA=160°, MIN_GAP_MS=60s, START_SKIP_MS=60s`
+
+**Tests:** 16/16 passing at 1 Hz (FULL mode). Covers: straight course, port↔stbd tack, jibe, 0/360 wrap, below/above delta limits, noisy anchor (rejected), unstable before-window (rejected), gradual course change (rejected), two tacks with sufficient gap, two tacks within MIN_GAP_MS (deduplicated), cold-start suppression, too few points.
+
+### GPX / Storage — completed prior session
+- `AndroidManifest.xml`: fixed `application/octet-stream` VIEW filter (no `pathSuffix`); added full SEND filter set for all five MIME types
+- `TrackStorage.kt`: SAF primary path (`saveViaSaf`, `loadViaSaf`, `safState`, `initSafDirectory`) with MediaStore fallback; survives reinstall with one re-auth tap
+- `SavedTracksFragment.kt` + `fragment_saved_tracks.xml`: "Set up track storage" / "Restore track access" button observing `safState` flow
+- `MainActivity.kt`: `safPickerLauncher` + `launchSafPicker()` via `ACTION_OPEN_DOCUMENT_TREE`
+
+### Logbook + Trip Report Improvements — 2026-05-26
+- **Notes/photos on finished tracks** — `+ Add note` button in `TrackDetailSheet`; dialog with text, camera, gallery. Saved with `timestampMs = track.endMs` so they fall within track window and appear in `buildLogEvents()` automatically.
+- **Single Nav voice** — Removed `NarrativeStyle` enum and 4-style ChipGroup. `generateNarrative(summary)` emits a concise PASSAGE header (date/time range, stats, conditions, timestamped deck log).
+- **Speed coloring fixed** — Replaced broken `Expression.get("color")` (MapLibre Android 11.x silently fails for `lineColor` on `LineLayer`) with `Expression.step(Expression.get("speed"), ...)` mapping the numeric `"speed"` property to color literals.
---
-## Previous Task Goal
-Section 7.4 Trip Reporting & Enhanced Tracks — COMPLETE (2026-04-04)
-
-## Verified (2026-04-04)
-- Build Successful: `android-app/gradlew assembleDebug` passed.
-- UI Layout: `activity_main.xml` refactored to LinearLayout to prevent BottomNav overlap.
-- Track Differentiation: Active (solid) vs Past (dotted) tracks verified in `MapHandler.kt`.
-- Pre-Trip Logic: Sail suggestions reefing logic verified in `PreTripReportGenerator.kt`.
-
-## Completed Items
-
-### [APPROVED] Trip Narrative Generator + Multi-Style AI (2026-04-04)
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/TripReportGenerator.kt`: Logic for distance, speed, and stylized narratives (Professional, Adventurous, Journal, Pirate).
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/TripReportViewModel.kt`: State management for narrative generation.
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/TripReportFragment.kt`: UI for viewing and selecting narrative styles.
-
-### [APPROVED] Pre-Trip Planning & Sail Suggestions (2026-04-04)
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/PreTripReportGenerator.kt`: Routing and reefing suggestions based on wind/waves.
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/PreTripModels.kt`: Domain models for boat profiles and suggestions.
-- `android-app/app/src/main/kotlin/org/terst/nav/tripreport/PreTripReportFragment.kt`: UI for generating and viewing pre-trip plans.
-
-### [APPROVED] Enhanced Map & Track Visualization (2026-04-04)
-- `android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt`: `updateTrackLayer` now supports active and past tracks with distinct styles.
-- `android-app/app/src/main/res/layout/activity_main.xml`: Refactored to vertical LinearLayout root to stabilize BottomNav and FAB placement.
-- `android-app/app/src/main/res/layout/layout_instruments_sheet.xml`: Added "TRIP REPORTS & PLANNING" section for direct access from main view.
-- `android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt`: Wired Pre-Trip and Trip Report buttons from instrument sheet; added `showReport` navigation helper.
-- `android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt`: Added `pastTracks` storage.
-- `test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt`: Synchronized with main app implementation.
-
-### [APPROVED] GpsPosition data class (2026-03-15)
-- File: `app/src/main/kotlin/org/terst/nav/gps/GpsPosition.kt`
-- Fields: latitude, longitude, sog (knots), cog (degrees true), timestampMs
-
-### [APPROVED] DeviceGpsProvider (2026-03-15)
-- Wraps `LocationManager` with `GPS_PROVIDER`
-- Fix-lost timer: fires `onFixLost()` after 10s with no update
-
-### [APPROVED] NmeaParser — RMC parser (2026-03-15)
-- Parses any `*RMC` sentence (GP, GN, etc.)
-- HHMMSS + DDMMYY → Unix epoch millis UTC
-
-### [APPROVED] AIS Integration (2026-03-15)
-- `AisVdmParser.kt`: Parses !AIVDM/!AIVDO (Types 1, 2, 3, 5).
-- `AisRepository.kt`: Upserts vessels and merges static data.
-- `AisHubSource.kt`: Integration with AISHub REST API.
-- `MapFragment`: GeoJSON layer for AIS vessels with rotation and labels.
-
-### [APPROVED] Track Recording (2026-03-25)
-- `MainViewModel`: TrackRepository wired; `addGpsPoint` enriches with environmental data.
-- `MainActivity`: FAB for toggling recording; MapHandler for rendering.
-
-### [APPROVED] TrackRepository (2026-03-25)
-- `android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt`
-- `test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt`
-- `isRecording` flag; `startTrack()` clears + starts; `stopTrack()`; `addPoint()` guards on isRecording; `getPoints()` returns snapshot
-- 8 tests — all GREEN (`TrackRepositoryTest`)
-
-### [APPROVED] Track ViewModel + Map overlay + Record FAB (2026-03-25)
-- `MainViewModel`: TrackRepository wired in; exposes `isRecording: StateFlow<Boolean>`, `trackPoints: StateFlow<List<TrackPoint>>`; `startTrack()`, `stopTrack()`, `addGpsPoint(lat, lon, sogKnots, cogDeg)`
-- `MapHandler.updateTrackLayer(style, points)`: lazy LineLayer init; red (#E53935) 3dp polyline from List<TrackPoint>
-- `MainActivity`: stores `loadedStyle`; GPS flow feeds `viewModel.addGpsPoint()` (m/s→knots); observes `trackPoints` → `mapHandler.updateTrackLayer()`; observes `isRecording` → FAB icon toggle (ic_track_record / ic_close)
-- `activity_main.xml`: `fab_record_track` FAB anchored top|end of bottom nav
-- `drawable/ic_track_record.xml`: red dot record icon
-
-### [APPROVED] Vessel Registry + Crew Management (2026-04-22)
-- `android-app/app/src/main/kotlin/org/terst/nav/vessel/Vessel.kt` — data class: name, MMSI, callsign, flag, homePort, hullType, LOA, beam, draft, displacement, engineHp, notes, isOwnVessel
-- `android-app/app/src/main/kotlin/org/terst/nav/vessel/CrewMember.kt` — data class: name, role (SKIPPER/FIRST_MATE/WATCH_CAPTAIN/CREW/GUEST), emergencyContact, emergencyPhone, certifications, notes
-- `android-app/app/src/main/kotlin/org/terst/nav/vessel/VesselRepository.kt` — in-memory CRUD for vessels and crew; addVessel, updateVessel, removeVessel, getOwnVessel, addCrewMember, updateCrewMember, removeCrewMember, getSkipper, getCrewByRole
-- `android-app/app/src/main/res/layout/fragment_vessel_registry.xml` — NestedScrollView with own vessel card, crew list, and known vessels list; + ADD buttons for crew and fleet
-- `android-app/app/src/main/kotlin/org/terst/nav/ui/vessel/VesselRegistryFragment.kt` — fragment with AlertDialog editors for vessels and crew; long-press to delete
-- `android-app/app/src/main/res/menu/bottom_nav_menu.xml` — added `nav_vessel` 5th tab with `ic_vessel` icon
-- `android-app/app/src/main/res/drawable/ic_vessel.xml` — sailboat silhouette vector icon
-- `MainViewModel.kt` — added `vesselRepository` property (public, for fragment access)
-- `MainActivity.kt` — `R.id.nav_vessel` case loads `VesselRegistryFragment`
-- Mirror classes in `test-runner/src/main/kotlin/org/terst/nav/vessel/`
-- 18 tests in `test-runner/src/test/kotlin/org/terst/nav/vessel/VesselRepositoryTest.kt` — all GREEN
-
-### [APPROVED] Thermal Alarm (2026-04-22)
-- `android-app/app/src/main/kotlin/org/terst/nav/thermal/ThermalMonitor.kt` — `thermalFlow(context)` as Kotlin Flow using `Intent.ACTION_BATTERY_CHANGED` for battery temperature; `PowerManager.addThermalStatusListener` on API 29+ for supplemental state; emits distinct `ThermalReading` only on state change
-- `ThermalState` enum: OK (<40°C), WARM (40–45°C), HOT (45–50°C), CRITICAL (>50°C)
-- `MainViewModel.kt` — `thermalState: StateFlow<ThermalState>`, `thermalReading: StateFlow<ThermalReading?>`, `onThermalReading()` entry point
-- `MainActivity.kt` — `startThermalMonitoring()` called from `observeDataSources()`; HOT triggers Toast + alarm sound (reuses `R.raw.mob_alarm`); CRITICAL triggers urgent Toast + alarm; OK/WARM stops alarm; alarm released in `onDestroy()`
-
-## Next 3 Specific Steps
-1. **Unit Tests for Trip Generators** — Add JVM tests in `test-runner` for `TripReportGenerator` and `PreTripReportGenerator`.
-2. **Persist track to Room** — Replace in-memory `pastTracks` with a Room database for persistence across sessions.
-3. **AnchorWatchHandler UI** — Re-integrate `AnchorWatchHandler` UI into `activity_main.xml` and wire it to the Safety Dashboard.
-
-## Scripts Added
-- `test-runner/` — standalone Kotlin/JVM Gradle project for fast test cycles.
-
-## Process Improvements
-- Stabilized UI layout by moving navigation out of the `CoordinatorLayout`.
-- Duplicated core logic into `test-runner` to bypass Android SDK requirements for logic testing.
+## Infrastructure
+
+- **`test-runner/`** — standalone Kotlin/JVM Gradle project for logic tests without Android SDK. Run: `cd test-runner && ./gradlew test`
+- **Branch policy** — all work merges to `main`. Current feature branch: `claude/optimize-nav-location-tracking-Vac5Z`
+- **Build note** — `./gradlew assembleDebug` requires network access to Google plugin repo (unavailable in cloud sandbox). Use `test-runner` for logic tests; build verification requires a local dev environment.