Changelog¶
Changelog¶
0.4.1 — 2026-08-19¶
- Verified on Python 3.14 (full suite, strict typing, byte-identical
corpus output); classifiers and CI matrix now cover 3.11–3.14.
requires-python >=3.11is unchanged — newer Pythons were never blocked, the metadata just lagged.
0.4.0 — 2026-08-18 (M2.7: analytics layer)¶
chiptime.metrics grows from a module into the analytics package (ADR-0008):
optional, zero-dep, never imported by the core, deterministic, trademark-safe
names, thresholds only ever from the user or the file.
- Sport profiles + pacing (F23): profiles-as-data registry (running /
cycling / pool & OW swim / rowing / hiking / XC / generic), primary-signal
resolution, labeled per-leg cadence doubling; inverse-safe pace math
("4:20/km", "1:52.5/500m"), Concept2 watts↔split, boundary-interpolated
distance splits, moving→timer→elapsed pace ladder with basis strings;
AthleteSettings+ zone ladder (settings > in-file zone messages > omitted). - Interval & structure detection (F24): evidence ladder — workout steps
(
wkt_step_index+ step intensity) → manual laps (≥2,lap_trigger) → swim sets (wall-rest grouping × pool length) → deterministic band detection (rolling median, quantile-midpoint reference, hysteresis, spike guard, rep-count + duration-CV honesty gates) →nonewith a reason. Repeats in athlete notation: "6 x 0:30 @ 300 W", "4 x 100m @ 1:44/100m rest 0:20". - Insights + load + CLI (F25): per-session
WorkoutReport(pace/speed with basis, weighted_avg_power, variability ratio, work kJ, power curve, SWOLF, splits, structure, zone time, load) + machine-readable insight codes (PACING_NEGATIVE/POSITIVE_SPLIT, HR_DRIFT_HIGH, COASTING_HIGH, WORKOUT_STRUCTURE) with numeric evidence; load ladder power+ftp → hr-trimp (Banister, sex-labeled coefficient, ≥50% HR-coverage guard — sparse swim HR can no longer silently understate) → honest omission; fitness/fatigue/form EWMA (42 d/7 d);chiptime analyze FILE [--json] [--ftp …]. - Verified names against USPTO/vendor records: exactly TSS/NP/IF are trademarked; fitness/fatigue/form + weighted-average-power are the OSS convention (research doc §12).
- Repo-wide
ruff formatadopted and enforced in the pre-push hook + CI.
0.3.0 — 2026-08-18 (M2.5: real-world hardening)¶
Validated against 66 real device files (Wahoo ROAM, pool/OW swims, a 5-session IRONMAN, courses, workouts, monitoring) — zero contract violations throughout.
- Real-file soak fixes: FIT_NO_CONTENT for valid-but-empty shells (#16, found in the wild); repair drops impossible local_timestamp (GC-invalid repairs 4→0); sport-aware + run-length-based DISTANCE_FROZEN (false positives → 0, dead-sensor detection intact).
- Full profile: generated from the FIT SDK — 119 messages / 1,382 fields / 176 enums, every field verified against an independent implementation; high-unknown files 9 → 0.
- Real-file corpus tier (ADR-0007): git-ignored private cases with promotion tooling; six real files pinned locally; PII policy set.
- Performance: 1.72× (1.04 MB in 599 ms; bit-identical output), CRC-256, decode plans, fast ISO; next multiple BACKLOG'd as architecture.
- HRV + analytics foundation: Activity.hrv_intervals_s (#72);
chiptime.metrics(mean-max curves, dt-capped zone time, SWOLF — null-honest by construction);Records.to_pandas()viachiptime[pandas].
0.2.0 — 2026-08-18 (M2: the repair release)¶
- Encoder (ADR-0006): canonical FIT writer — lossless re-emit of anything decoded (unknown messages, developer fields, big-endian sources) + profile synthesis; re-encoded files pass strict mode.
chiptime repair: salvage → synthesize missing file_id/events/lap/ session/activity → valid .fit, with REPAIR_* provenance and honest refusal when nothing is salvageable. The Zwift-crash class repairs to a Garmin-Connect-valid file.chiptime validate --platform strict-spec|garmin-connect|strava: platform acceptance as named heuristic checks (#99/#102).- CRC triage: mismatches diagnosed (unterminated write / storage damage / in-place corruption).
- Tier-2 depth: compressed_speed_distance expansion (12-bit rollover), accumulator unwrap, event subfields (timer_trigger), HR/power/distance/ pool/lap plausibility flags — flagged, never edited.
- Robustness gate: every corpus case — including deliberately corrupt, truncated, and wrapped files — decodes without a crash (3279 messages across 63 cases).
0.1.0 — 2026-08-18 (M1)¶
First release. Python, zero runtime dependencies.
- Decode: crash-proof frame reader (defects-as-values), all base types, both endiannesses, compressed timestamps with rollover + anchor recovery, developer fields incl. every malformed variant, unknown-everything preserved.
- Recovery (OSS-first): mid-file resynchronization, preamble-garbage skip, truncation salvage with estimates — every skipped byte accounted.
- Intake: gzip/zip unwrap, chained files, content sniffing with named formats.
- Semantics: Activity/Session model, columnar streams (0 ≠ null, per-stream sparsity), enhanced-pair reconciliation, timer state machine, classified gaps, declared-vs-derived discrepancies, session rebuild, multisport, GPS plausibility gates with virtual-world exemption.
- Modes: strict / lenient / forensic (forensic never drops).
- Output: RFC 8785 canonical JSON, byte-identical across runs/processes/OSes; typed errors with suggestions; provenance for every repair.
- Conformance corpus: 56 golden cases covering all 18 Tier-1 taxonomy items.
- CLI:
chiptime parse|inspect|codeswith agent exit codes (0/2/3/4/64).