<feed xmlns='http://www.w3.org/2005/Atom'>
<title>nav.git/test-runner/src/main, branch main</title>
<subtitle>nav — android navigation app
</subtitle>
<id>https://git.terst.org/nav.git/atom?h=main</id>
<link rel='self' href='https://git.terst.org/nav.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/'/>
<updated>2026-05-28T07:09:43+00:00</updated>
<entry>
<title>Tech debt: delete com.example.androidapp ghost package, symlink TackDetector, fix forecast current hour</title>
<updated>2026-05-28T07:09:43+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-28T07:09:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=c498b33300d260bbe64bec49de9ef78d9a322a6d'/>
<id>urn:sha1:c498b33300d260bbe64bec49de9ef78d9a322a6d</id>
<content type='text'>
- Deleted all 18 stale source files in com.example.androidapp (main + test)
  that duplicated org.terst.nav implementations from an earlier namespace
- Fixed the 3 tide model files (TidePrediction/Station/Constituent) whose
  package declarations read com.example.androidapp.data.model despite living
  in org.terst.nav.data.model directories
- Fixed HarmonicTideCalculator.kt imports to match the corrected package
- Fixed TideModelTest.kt package declaration
- Migrated HarmonicTideCalculatorTest to org.terst.nav.tide with correct imports
- Replaced test-runner's TackDetector.kt copy with a symlink to the android-app
  canonical source so the two can never diverge again
- Fixed addGpsPoint to pick the current wall-clock hour's forecast slot instead
  of always using the app-start hour (first item in forecast list)

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Fix ANR, false tack detections, and empty-state flash on track load</title>
<updated>2026-05-26T07:46:09+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T07:46:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=3673ed0ef79d776c6da3bfa0db9de8b08326fd32'/>
<id>urn:sha1:3673ed0ef79d776c6da3bfa0db9de8b08326fd32</id>
<content type='text'>
ANR: getSavedTracks() had no IO dispatcher — TackDetector ran on main
thread at O(n²) cost (~77M ops for a 2.5h track). Added withContext(IO).

TackDetector: replaced O(n) list.filter with O(log n) binary-search
subList for before/after windows; O(n²) → O(n log n). Raised MIN_DELTA
60°→75° to stop detecting ordinary course corrections as maneuvers.
Removed MAX_DELTA cap entirely — 180° crash-tacks are valid; the
circularMAD stability windows are the real quality gate.

TrackDetailSheet: dropped the arbitrary abs(delta)&gt;70 Tack/Jibe
heuristic. Now uses true wind angle when available for classification;
falls back to "Maneuver" when TWD is absent.

SavedTracksFragment: added isLoadingTracks StateFlow (MainViewModel);
combine() suppresses the empty-state layout while the initial IO load
runs so it no longer flashes "No saved tracks yet" before data arrives.

16/16 TackDetector tests pass.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Redesign tack detection: time-based windows + circularMAD stability</title>
<updated>2026-05-26T06:39:05+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T06:39:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=8dbf3f883274fc0ddd16e5507f732629c85e3c91'/>
<id>urn:sha1:8dbf3f883274fc0ddd16e5507f732629c85e3c91</id>
<content type='text'>
Replace the point-count window (HALF_WIN=2) with 30s time-based settle
windows that give consistent reliability regardless of GPS update rate
(1 Hz FULL vs 0.2 Hz ECONOMY). Key changes:

- Before/after windows are time-based (T_SETTLE=30s) around a guard
  zone (T_MANEUVER=30s), not point counts.
- Stability uses circularMAD (&lt;20°) across all fixes in each window,
  replacing the single-pair spread check. This correctly handles
  0°/360° wrap and suppresses random anchor-watch COG noise (MAD≈90°).
- No SOG gate: averaging 30 fixes over 30s reduces noise by √30
  regardless of boat speed. A boat at anchor has MAD≈90° and is
  rejected by the stability check.
- MAX_DELTA raised to 160° (covers deep jibes the old 140° missed).
- START_SKIP reduced to 60s (stability check handles cold-start noise).
- De-duplication uses adjacent-candidate comparison so a long stream
  of raw candidates from one maneuver stays in a single group even if
  it spans &gt;MIN_GAP_MS in total.
- Position refined to max instantaneous heading rate within the
  maneuver zone.
- Mode: CRUISING (conservative). Race mode noted as future backlog.

16/16 unit tests pass at 1 Hz (FULL mode GPS rate).

https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
</content>
</entry>
<entry>
<title>Fix Long overflow in TackDetector: var lastTackMs = Long.MIN_VALUE caused subtraction overflow, filtering every tack</title>
<updated>2026-05-20T22:18:38+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-20T22:18:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=62cc93086498d57ef7298eddb40cc382dfc10c6d'/>
<id>urn:sha1:62cc93086498d57ef7298eddb40cc382dfc10c6d</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Add saved tracks browser, tack detection, and map zoom-to-bounds</title>
<updated>2026-05-12T23:13:55+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-05-12T23:13:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=f881a1f91f4e9f832ab987fce2b5220e100cee68'/>
<id>urn:sha1:f881a1f91f4e9f832ab987fce2b5220e100cee68</id>
<content type='text'>
- TackDetector: sliding-window COG algorithm (60-140deg delta = tack/jibe)
  with stability check to prevent mixed-window false positives; 13 tests green
- TackEvent, SavedTrack: new models wrapping points + summary + detected tacks
- TrackRepository.getSavedTracks(): returns List&lt;SavedTrack&gt; with lazy load
- MapHandler: zoomToTrackBounds (LatLngBounds fit with padding),
  panToPoint (log step-through), updateTackLayer (yellow circle markers)
- MainViewModel: savedTracks + selectedTrack StateFlows, panToPosition SharedFlow
- SavedTracksFragment: RecyclerView list with date/distance/duration/tack count
- TrackDetailSheet: bottom sheet with stats + event log (tacks, speed changes,
  start/end); tapping an entry pans the map to that position
- MainActivity: zoom map on track complete, wire Saved Tracks button in
  instrument sheet, observe panToPosition to drive map, show tack markers
  when a saved track is selected

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Merge origin/main — unite all work onto one branch</title>
<updated>2026-04-23T23:10:11+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-23T23:10:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=e1db9200e9d44c10450361cc8984a45b2eda87b7'/>
<id>urn:sha1:e1db9200e9d44c10450361cc8984a45b2eda87b7</id>
<content type='text'>
Brings in dev log (NavLogger), UnitPrefs, MapLayerManager, HUD views,
conditions throttling, track save/load pipeline, improved ParticleWindView
(antimeridian-aware, dynamic particle count), Snackbar error surfacing,
and all other main-branch work from the prior session.

Combined with master's hardware source flags, vessel registry, crew
management, thermal alarm, CPA collision alerts, and track stats.

Also documents primary branch policy in CLAUDE.md and .agent/config.md:
all work merges to main, never master.

https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
</content>
</entry>
<entry>
<title>fix+feat: CI build fixes and hardware source feature flags</title>
<updated>2026-04-22T09:02:46+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-22T09:02:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=e141e1ef46ebb2a61f452122201a77527a5a1c9e'/>
<id>urn:sha1:e141e1ef46ebb2a61f452122201a77527a5a1c9e</id>
<content type='text'>
CI fixes:
- ParticleWindView: bounds.lonEast → bounds.northEast.longitude
  (MapLibre 13.x API; lonEast not available as property)
- VesselRegistryFragment: Vessel(id="") and CrewMember(id="") →
  include required name="" so copy() compiles

Hardware source feature flags:
- HardwareSource enum: AIS_RECEIVER, NMEA_INSTRUMENTS
- FeatureFlags: SharedPreferences-backed; all sources default OFF
  (app works phone-only out of the box)
- NavApplication: exposes featureFlags singleton
- SafetyFragment: "HARDWARE DATA SOURCES" card with two MaterialSwitch
  toggles; reads initial state from FeatureFlags; calls
  SafetyListener.onHardwareSourceChanged on change
- AIS_RECEIVER flag:
  - MainViewModel.processAisSentence() / refreshAisFromInternet() skip
    when disabled; onHardwareSourceChanged() clears targets + cpaAlerts
- NMEA_INSTRUMENTS flag:
  - LocationService skips nmeaStreamManager.start() on service launch
    when disabled
  - New ACTION_START_NMEA / ACTION_STOP_NMEA intents allow live toggle
  - MainActivity.onHardwareSourceChanged() sends the appropriate intent

Tests: 102 total, all GREEN (+7 FeatureFlagsTest)

https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
</content>
</entry>
<entry>
<title>feat: CPA/TCPA collision alerts and live track stats</title>
<updated>2026-04-22T08:45:55+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-22T08:45:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=87f9cb753da3325d13fdbc442d526567e056d6e1'/>
<id>urn:sha1:87f9cb753da3325d13fdbc442d526567e056d6e1</id>
<content type='text'>
CPA/TCPA alerts:
- CpaAlert data class with severity (CAUTION/WARNING/DANGER) and label()
- CpaThresholds: 0.5/1.0/2.0 nm, max TCPA 30 min
- MainViewModel.updateCpaAlerts() runs on every GPS update and AIS
  sentence; skips stationary contacts; filters TCPA ≤ 0 or &gt; 30 min;
  sorts by TCPA ascending
- SafetyFragment: new COLLISION AVOIDANCE card shows live alert list,
  color-coded by severity; clears to "No traffic alerts" when safe
- MainActivity: observes cpaAlerts → safetyFragment.updateCpaAlerts()

Track stats:
- TrackStats data class: distanceNm, durationMs, avgSogKnots,
  durationFormatted (m:ss / h:mm:ss)
- TrackRepository.haversineNm() + computeStats() using point timestamps
- MainViewModel exposes trackStats StateFlow, cleared on stopTrack()
- activity_main: dark pill overlay bar (tv_track_stats) above map
- MainActivity: shows "● REC  0.00nm  m:ss  x.xkt avg" while recording

Tests: 95 total, all GREEN (+16 new — 9 TrackStats, 7 CpaAlert)

https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
</content>
</entry>
<entry>
<title>feat: vessel registry, crew management, and thermal alarm</title>
<updated>2026-04-22T05:35:49+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-22T05:35:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=eeafe2f0f3a3718bd52e9c333894e1abbc0611ab'/>
<id>urn:sha1:eeafe2f0f3a3718bd52e9c333894e1abbc0611ab</id>
<content type='text'>
- Vessel/CrewMember data classes with full profile fields
  (MMSI, callsign, flag, home port, hull type, dimensions, roles)
- VesselRepository: in-memory CRUD for own vessel, fleet, and crew;
  getOwnVessel(), getSkipper(), getCrewByRole() helpers
- VesselRegistryFragment: own-vessel card + crew list + known-vessels
  list; AlertDialog editors for add/edit; long-press to delete
- ic_vessel.xml sailboat icon; 5th bottom-nav tab "Vessel"
- ThermalMonitor: thermalFlow() using Intent.ACTION_BATTERY_CHANGED
  (battery °C) + PowerManager.OnThermalStatusChangedListener (API 29+);
  ThermalState OK/WARM/HOT/CRITICAL with distinct-until-changed filter
- MainActivity: startThermalMonitoring() sounds mob_alarm + Toast on
  HOT (≥45°C) and CRITICAL (≥50°C); auto-silences on OK/WARM
- MainViewModel: thermalState and thermalReading StateFlows
- 18 VesselRepositoryTest cases — all GREEN (test-runner)
- design.md: updated competitive matrix + feature implementation status

https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
</content>
</entry>
<entry>
<title>feat(ui): surface trip planning and reports in instrument sheet</title>
<updated>2026-04-04T07:10:41+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-04-04T07:10:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=9f01ddfba17dda7fb386e83f007c671fec6d5b8e'/>
<id>urn:sha1:9f01ddfba17dda7fb386e83f007c671fec6d5b8e</id>
<content type='text'>
</content>
</entry>
</feed>
