summaryrefslogtreecommitdiff
path: root/test-runner/src/test/kotlin/org
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-27 05:38:24 +0000
committerClaude <noreply@anthropic.com>2026-05-27 05:38:24 +0000
commit4f87ae6cda6131012447a8b2ddde088bb8844b04 (patch)
tree22f21f730783b5401caeb05799b3653de473d1ae /test-runner/src/test/kotlin/org
parent1f9f0ec3f7ce986134ed75836fc42e43582aa34f (diff)
Add RACE mode to TackDetector for rapid mark-rounding detection
Introduces TackMode enum (CRUISING/RACE) and per-mode Config, replacing the previous single set of hardcoded constants. RACE config: T_SETTLE=12s, T_MANEUVER=20s, STAB_MAX=30°, MIN_GAP=20s, START_SKIP=20s — tighter windows for quick successive tacks at race starts and mark roundings. CRUISING remains the default. Two new tests demonstrate the behavioral difference: RACE fires earlier (past 20s cold-start vs 60s) and keeps separate events for a 50s gap that CRUISING deduplicates (50s < 60s MIN_GAP). 18/18 passing. https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
Diffstat (limited to 'test-runner/src/test/kotlin/org')
-rw-r--r--test-runner/src/test/kotlin/org/terst/nav/track/TackDetectorTest.kt22
1 files changed, 22 insertions, 0 deletions
diff --git a/test-runner/src/test/kotlin/org/terst/nav/track/TackDetectorTest.kt b/test-runner/src/test/kotlin/org/terst/nav/track/TackDetectorTest.kt
index 265ba76..e3bca9f 100644
--- a/test-runner/src/test/kotlin/org/terst/nav/track/TackDetectorTest.kt
+++ b/test-runner/src/test/kotlin/org/terst/nav/track/TackDetectorTest.kt
@@ -124,4 +124,26 @@ class TackDetectorTest {
val tacks = TackDetector.detectTacks(leg1 + leg2 + leg3)
assertEquals(1, tacks.size)
}
+
+ // ── Race mode ─────────────────────────────────────────────────────────────
+
+ // RACE config: T_SETTLE=12s, T_MANEUVER=20s, START_SKIP=20s, MIN_GAP=20s, STAB_MAX=30°
+ // Min apex time in RACE at 1 Hz: START_SKIP(20) + T_SETTLE(12) + T_MANEUVER/2(10) = 42s from t0
+ // So leg1=30s (cog A), leg2=30s (cog B): apex candidates fire around t=30s in leg2.
+ // For t=42 in leg2 (t0=0): before=[42-22..42-10]=[20,32]→in leg1 ✓; after=[52..64]→in leg2 ✓
+
+ @Test fun `race mode detects tack that falls inside cruising cold-start window`() {
+ // Tack at t=30s is inside CRUISING START_SKIP=60s but past RACE START_SKIP=20s
+ val pts = leg(330.0, 30, 0L) + leg(70.0, 30, 30_000L)
+ assertEquals(1, TackDetector.detectTacks(pts, TackMode.RACE).size)
+ assertEquals(0, TackDetector.detectTacks(pts, TackMode.CRUISING).size)
+ }
+
+ @Test fun `race mode yields two events for gap that cruising deduplicates`() {
+ // Intermediate leg of 50s: gap > RACE MIN_GAP=20s → 2 events
+ // gap < CRUISING MIN_GAP=60s → 1 event (deduped)
+ val pts = leg(330.0, 60, 0L) + leg(70.0, 50, 60_000L) + leg(330.0, 60, 110_000L)
+ assertEquals(2, TackDetector.detectTacks(pts, TackMode.RACE).size)
+ assertEquals(1, TackDetector.detectTacks(pts, TackMode.CRUISING).size)
+ }
}