Skip to content

Wire the committed TrackMan captures into CI so carry accuracy is measured on every PR #218

Description

@cvrt-jh

Description

While reading the ballistics code I noticed the repo already has almost everything needed to guard carry accuracy — session_logs/OpenFlight-Test.Normalized.csv is committed, and scripts/analysis/validate_ballistics.py scores the model against it properly (including the 1.184 kg/m³ air-density match for TrackMan's "Flat" normalization, which is a nice detail). The one missing piece is that nothing in tests/ or .github/workflows/ calls it, so the check is manual-only and carry accuracy isn't measured on PRs.

grep -rn "OpenFlight-Test\|comparison_2026" tests/ .github/ returns nothing.

The existing carry tests are deliberately broad ranges — tests/test_ballistics.py:87 asserts 250 <= carry <= 300 — so they catch gross breakage but not a systematic offset. Running your validator on the committed capture, with TrackMan's own launch conditions fed in:

OVERALL  n=24  bias=-5.05 yd  rmse=24.52 yd  mae=20.36 yd  max|d|=52.29 yd
  club              n     bias    rmse     mae   max|d|
  7-iron            9   +11.00   11.64   11.00    16.25
  driver            8   -37.18   38.60   37.18    52.29
  pitching wedge    7   +11.02   13.56   13.16    16.54

The per-club spread is interesting on its own (the driver column looks like a low-spin-parameter Cl fit issue — CL_HALF_SP = 0.15 sits above the driver's whole realistic Sp range). I'd rather not conflate that with this issue though; happy to file it separately if useful.

What did you expect to happen?

A change that moves carry accuracy in the wrong direction should show up in CI.

Proposed solution

I have a PR ready — one new test file, no source changes — that replays the committed capture through the production resolve_launch/simulate path and asserts per-club RMSE against a budget seeded at the current measured error rather than at zero, so it blocks new error immediately without blocking anyone on the existing offset. It imports your load_trackman/validate_tm_inputs/_stats rather than reimplementing them, so the test and the tool can't drift apart, and skips cleanly if the capture file is absent.

I checked it catches things the current tests don't. CL_SATURATION 0.32→0.34 with CL_HALF_SP 0.15→0.14 passes all 21 existing ballistics tests, but fails here — overall RMSE actually improves (24.5→21.2) while 7-iron (11.6→16.0) and wedge (13.6→15.5) get worse. That's the case per-club budgets are for.

Full suite with it added: 1326 passed, 8 skipped. Pylint 9.70, ruff clean.

Two things I'd rather have your call on than guess at:

  • budgets inline in the test module, or a committed JSON alongside the capture?
  • gate on RMSE (what I did), or on bias, or both?

Happy to adjust either way, or to drop it if you'd rather solve this differently.

Area

Ballistics / physics model, CI

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions