Implements the fit-parsing-hardening change. The shared converter now:
- splits output into <trkseg>s on timer stop/start events, falling back to
record gaps > 5 min, so downstream moving-time never bridges a pause;
- slices records into per-session windows (multisport → one activity, one
segment per session), single-session behavior unchanged;
- validates records: finite/in-range coordinates required, timestamp
required, non-finite altitude dropped (point kept), prefers
enhanced_altitude;
- returns { gpx, sport }, mapping FIT session sport/sub-sport to a Journal
SportType (first session wins), consumed by the Wahoo importer + webhook
and Garmin importer as a fallback when the provider sends no type.
Tests drive the converter via mocked fit-file-parser output (segmentation,
validation, sport mapping, no-GPS) per the chosen fixtures approach.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1.6 KiB
1.6 KiB
1. Fixtures first
- 1.1 Collect fixture FIT files — adapted: per the chosen approach, cases are driven by mocked
fit-file-parseroutput infit.test.ts(pause, multisession, indoor no-GPS, corrupt coords/missing-timestamp) rather than binary files. Real device binaries can be added later without changing the converter. - 1.2 Parser
events/sessionsshapes captured as theFitEvent/FitSessiontypes + code comments infit.ts, and exercised by the mocked-parser tests.
2. Converter
- 2.1 Segmentation: split on timer stop/start event pairs, fallback on record gaps > 5 min (named constants)
- 2.2 Session slicing: records windowed per session, one-or-more segments per session, single-session unchanged
- 2.3 Validation gates: finite/in-range coordinates, timestamp required, non-finite altitude → undefined; prefer
enhanced_altitude(speed isn't emitted to GPX so its preference is moot) - 2.4 Return
{ gpx, sport }with the FIT→SportType mapping table; update call sites (Wahoo importer + webhook, Garmin importer) — provider-explicit type wins, FIT sport is fallback - 2.5 Unit tests over the fixtures: segment counts (pause becomes a segment boundary, which is what keeps moving time honest), corrupt-record drops, enhanced-altitude preference, sport mapping, no-GPS returns null gpx
3. Verification
- 3.1 Re-run the Wahoo importer test suite; confirm existing single-session imports produce identical stats (14 pass; mock updated to the
{gpx, sport}shape) - 3.2 Run
pnpm typecheck && pnpm lint && pnpm test— all green