Release v3.3.0 - #373
Merged
Merged
Conversation
A user-reported .vbo rendered as a straight line: its data rows start with time (no leading satellite count), so the whole column mapping sat one slot right of the data — sats read packed HHMMSS time (shown as a 113457 "satellite count"), time read latitude (near-constant, collapsing the session duration), lat read longitude, lon read velocity (the straight speed-driven streak), and velocity read heading (~350 km/h phantom top speed). Verify the resolved mapping against the data shape before parsing: a genuine sats column is a small integer and never a packed HHMMSS.SS token, so when the sats column carries packed time and the time column does not, drop the phantom sats mapping and pull everything one slot left. Covers both a [column names] line that over-declares sats and the positional fallback's sats-first assumption. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpnVWWkfwqypBMzvVs1qbs
…eed filtering A Solo2 user's poor-signal .xrk session (95-99% packet loss) rendered a 134-mile race line and a 735 mph top speed: errant fixes survived parsing and corrupted every downstream feature, and interpolated quality channels showed impossible values (-1597 satellites) in tooltips. Why filtering lives in one place: a new post-parse filterGpsQuality() runs in the datalog router after normalizeChannels(), so every format is covered at the single point all features draw from. - Always-on quality gate: drops provably-invalid fixes (negative satellites/ accuracy, DOP <= 0) and weak fixes (sats < 4, accuracy > 20 m, DOP > 10), per-signal opt-in so files without quality channels are untouched, with a fallback tier so an all-weak (marginal, not corrupt) session still loads. - "Hardcore data filtering" setting (default off, kart-tuned, car users exist): poison-proof teleport gate + speed *repair* - errant reported speeds are recomputed from neighboring positions instead of dropping otherwise-healthy packets. Toggling reparses the open session. - XRK quality channels now forward-fill instead of interpolating (the source of the fabricated tooltip values, and a mask over garbage fixes). - AiM CSV: ad-hoc 100 m/s teleport filter migrated into the hardcore pass; PosAccuracy (as H Accuracy, meters) and pDOP/HDOP now exported as channels. - New lowQuality rejection category + repairedSpeeds surfaced on the existing map badge; i18n keys seeded manually (no ANTHROPIC_API_KEY in this env). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…ad rows only Maintainer review: the first cut over-reached into reprocessing (weak-fix thresholds, a hardcore setting with teleport gating, neighbor-based speed repair). Step 1 is just: as rows load, drop the provably-garbage ones and rebuild a clean dataset - decide about further filtering after the spikes are gone. - filterGpsQuality is now a single pass: drop rows with negative satellite counts / accuracy / DOP (those can never go negative) or DOP > 10; files without quality channels untouched; if every row would be condemned the file is shown raw instead of refused. - Reverted: hardcoreGpsFiltering setting + SettingsModal section + reparse effect, speed repair (repairedSpeeds), createTeleportGate, weak-fix thresholds, the settings-read fallback in the router. - Restored: the AiM CSV always-on 100 m/s implied-speed teleport filter. - Kept: XRK quality channels forward-fill (interpolation smeared the negative blips this cleanup looks for), AiM quality-channel exports, the bad-fix badge counter, per-signal channel key lists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…umps The rebuilt dataset still contained the Solo2 spike: its garbage rows carried NO recorded quality data, and the resampler was filling those rows with the last healthy packet's readings - so a corrupt fix showed "15 sats / pDOP 1.2" and sailed through the cleanup. Two fixes: - xrkResample: quality channels resample by exact timecode match only (+-5ms). A row shows a satellites/DOP/accuracy value ONLY when the logger recorded one at that row's timestamp; otherwise it is absent. No interpolation (which invented "-1597 satellites"), no fill (which dressed garbage rows up as healthy). - gpsQualityFilter: a row whose position implies moving faster than MAX_SPEED_MPS (150 m/s - the app-wide GPS-glitch bound, no ground vehicle reaches it) from the last kept row is skipped during the rebuild, counted as teleportation. This is the only proof available for corrupt fixes that carry no quality data at all. The reference advances only on kept rows and re-anchors after 50 consecutive rejections so a garbage first row can't condemn the file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
With the reported file in hand, the "bad GPS data" theory collapsed: every native GPS sample is healthy (all positions on track, 8-16 sats, pDOP <= 2.1, accuracy <= 0.77m, speed <= 110mph). The corruption is the CLOCK: the wasm decoder mis-unwraps a 16-bit ms counter across interleaved sample blocks, stamping rows with spurious +-k*65536ms offsets, out-of-order blocks, and duplicated timestamps - a 16-minute race spanning "64 hours". Resampling against that non-monotonic clock EXTRAPOLATED other channels (unclamped interpolation fraction), fabricating positions miles off track, 735mph speeds, and the impossible quality values. The "99.4% pkts dropped" banner was the same artifact. - xrkResample: detect the fault per channel (time running backwards, or >=3 deltas within 1s of an exact 65536 multiple - a real pit gap is nowhere near one), unfold the spurious multiples, stable-sort rows by true time, skip rows that don't advance the clock. Values never altered or invented. - interpolateOnto: clamp the interpolation fraction to [0,1] - resampling must never extrapolate, whatever the input ordering. Verified against the reported file: duration 64h -> 20min, zero samples off track, zero jumps > 500m, max speed 110.2mph (= native max), monotonic time. Healthy fixtures untouched (repair gate never fires). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…ork) Root fix for the corrupt-clock decode, replacing reliance on the TS-side mitigation (which stays as a dormant safety net). The libxrk fork (fix/solo2-gps-timecode-corruption, rev 16b7fc8) now: - phase-unwraps logger timecodes with half-range hysteresis so block-seam jitter is no longer misread as thousands of 16-bit rollovers, and - when timecodes run backwards, rebuilds the GPS timeline from the receiver's own clock (NAV-SOL itow, immune to the logger bug), keeping one record per epoch - affected files write every epoch twice (two solutions ~4m apart; mixing them wove a ~4m square-wave through the race line). Pin xrk-wasm at the fork rev + rebuild committed wasm artifacts. Verified with the reported Buttonwillow file end-to-end: 24,309 epochs / 972s / 18.96mi (7 laps), best lap 127.780s matching RaceStudio's 2:07.800, zero off-track samples, 17 rows dropped total (was: "64 hours", 95mi, 735mph, thousands dropped). Healthy fixtures decode byte-identically; all 2,387 tests green with the new wasm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
The map's direction arrow pointed in random directions on .xrk sessions: no heading channel was exported, so mapMarker fell back to a bearing derived from adjacent (noisy) positions - pure noise at low speed. The receiver's own course over ground (from its velocity vector) was already computed inside libxrk but never exposed. Bump the libxrk fork rev (a8426db: heading field on GpsDecodeResult), export "GPS Heading" from the wasm wrapper, rebuild the artifacts. The existing GPS_ROLES mapping picks it up into GpsSample.heading with no app-side changes. Verified on the reported Solo2 file: heading present on every sample, mean deviation from direction of travel at race pace 0.95 degrees. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…ring-sxjirh plan 0014: repair broken Solo2 .xrk timecodes + GPS row cleanup (all formats)
…ng-5atcp5 Fix VBO parsing for files whose data rows lack the sats column
Coach plugin already on the production npm package on BETA (@perchwerks/eye-in-the-sky 0.5.0) — no flip needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
lapwing | a06962b | Commit Preview URL Branch Preview URL |
Jul 31 2026, 04:59 AM |
Coverage SummaryLines: 57.08% (7059/12366) · Statements: 56.22% · Functions: 53.48% · Branches: 53.59% Per-file coverage
|
Racelogic VBO, Alfano 6, and AiM CSV get a purple "Validated" badge in Supported Files (Alfano + AiM CSV shed "Experimental"), backed by full real user-shared sessions committed as fixtures with end-to-end tests: - racebox-lignano.vbo: RaceBox export whose data rows lack the sats column - the #368 column-realignment bug, proven fixed on the real file - vbox-modena.vbo: classic layout, sats column first - alfano6-ada-martensville.csv: Alfano 6 ADA "classic Excel" export - locale grouping separators, Absolute Time, Lat./Lon. layout (this is an Alfano 6 file, not MyChron CSV; AiM CSV validation rests on the existing real racestudio3-aim.csv fixture) - solo2-buttonwillow.xrk: the corrupt-timecode Solo 2 session behind the v3.3.0 GPS fix, now asserting RaceStudio-identical decode (24,309 epochs / 971.7s / all positions on track / max 110mph / heading on every sample) All fixtures shared by their owners for validation use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…all tested formats - Remove the Dove CSV entry from the Supported Files dialog (legacy first-party format; still imports, just not advertised) - component ids and all seven locales. - The Validated badge now marks automated parser test coverage and applies to every listed format (primary cards included), so its absence isn't read as a warning. A future format stays unbadged until its Vitest suite lands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
…y featured Every listed format now has automated parser test coverage, so per-format status badges (Experimental / Validated) say nothing and are gone. VBO swaps into NMEA's featured slot and MoTeC binary moves up under iRacing; NMEA drops to the secondary group. Card copy relocated across all seven locales to match the new primary/secondary key paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gFSnXfjV4g1kcjAQGbjd6
Release prep v3.3.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v3.3.0 — 2026-07-31
This one started with a bug report that looked unbelievable: an AiM Solo 2 rider sent us a session showing a 735 mph top speed and a 134-mile race line shooting off into the desert — from a 16-minute club race. The GPS looked destroyed. It wasn't.
Digging into the raw file, every single GPS fix turned out to be healthy — centimeter-level accuracy, 8–16 satellites, all of it right on track. What was broken was the clock: newer Solo 2 firmware writes its GPS records in a way that confused the decoder into misreading thousands of tiny timestamp wiggles as 16-bit clock rollovers, stretching a 16-minute race into a "64-hour" timeline. Every downstream step then resampled real data against that scrambled clock and hallucinated the rest — the teleporting race line, the impossible speeds, even a fake "99% packets dropped" warning.
The fix goes all the way down. The decoder now rebuilds the timeline from the GPS receiver's own clock (a field the logger firmware can't corrupt), and the affected session decodes identically to AiM's RaceStudio — same lap times, to the millisecond. On top of that, LapWing now sanity-checks every file format's GPS rows on load, so provable garbage never reaches your data again. And because our users are the best: the riders and drivers who reported these bugs shared their real session files with us, so those full sessions now live in our test suite and every release is checked against them.
Fixed
.xrklogs with corrupt GPS timecodes now decode correctly. Newer Solo 2 firmware writes GPS records with jittered logger timestamps and every epoch duplicated (two position solutions ~4 m apart); the bundled libxrk decoder misread the jitter as thousands of 16-bit clock rollovers, stretching a 16-minute race into "64 hours", weaving a ~4 m square-wave through the track line, and fabricating positions miles off track, 735 mph speeds, and a false "99% packets dropped" reading — while the file's actual GPS data is healthy and centimeter-smooth. The decoder now rebuilds the GPS timeline from the receiver's own clock and matches RaceStudio's output exactly (verified: same lap times; 19 mi session distance vs the previous 95). Healthy files decode byte-identically..vbowhose data rows start withtime(no leading satellite count) had every channel read one column off — latitude got the longitude column, longitude got velocity — producing a straight speed-driven streak. The parser now verifies the column mapping against the data shape and realigns before parsing.Added
bad-fix/teleport)..xrkimports. The decoder now exports the receiver's course over ground (derived from its velocity vector), so the map's direction arrow no longer falls back to noisy position-difference bearings that pointed in random directions at low speed.H Accuracy(converted to meters) and pDOP/HDOP as channels, matching what.xrkimports already carried..vbo, an Alfano 6 ADA export, a RaceStudio 3 CSV, and the corrupt-timecode Solo 2.xrk) — so the "Experimental" labels are gone. Racelogic VBO and MoTeC binary move up into the featured group, and the legacy Dove CSV entry is retired from the list (the format still imports fine — it just doesn't need advertising).Changed
.xrkquality channels are never fabricated. Satellite counts, position/speed accuracy, and DOP now appear on a row only when the logger actually recorded them at that row's timestamp — no interpolation (which invented impossible values like "-1597 satellites" in tooltips) and no filling (which dressed garbage rows up with a neighbor's healthy readings).Full changelog: v3.2.0...main