Skip to content

Add per-session bay calibration as a read-time layer - #6

Merged
chayuto merged 1 commit into
mainfrom
bay-calibration-layer
Aug 1, 2026
Merged

Add per-session bay calibration as a read-time layer#6
chayuto merged 1 commit into
mainfrom
bay-calibration-layer

Conversation

@chayuto

@chayuto chayuto commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Why

A session recorded in a bay whose target line is misaimed reads every direction metric wrong by a constant: face angle, club path, and launch direction shift together while face-to-path stays put (it is a difference of two directions, so the offset cancels). The 2026-08-01 SIM bay session read 2.8 degrees left of the range bay baseline this way.

What

Stored telemetry stays exactly as TrackMan reported it. The correction is a calculation layer applied at read time, scoped per session.

  • training_sessions.calibration_offset_deg (float, nullable, -15..15). Degrees added to bay-reported direction metrics. Positive when the bay read left of true.
  • PATCH /api/v1/sessions/:id sets or clears the offset. Requires telemetry:write, audited via paper_trail, and it is the only mutable session field.
  • GET /api/v1/stats/clubs?calibrated=1 returns corrected aggregates, computed in SQL: face and path get the offset added, lateral carry spread rotates by it. face_to_path is never corrected.
  • Dashboard: a Bay cal. toggle in the filter bar corrects charts client-side (pure math, no shot refetch; only club aggregates refetch). Selecting a session reveals an offset editor.
  • Ball trajectories stay raw; at chart scale the side error is within line width.

Tests

  • Request specs: offset update (happy path, clear, validation, scope, cross-user, audit attribution, telemetry-fact immutability), calibrated vs raw stats (offset applied, f2p and SD invariant, no-offset no-op).
  • Full local CI: rspec (86 examples), rubocop, brakeman, bundler-audit, web lint and build all green.

Direction metrics are measured against the bay target line. When a bay
is misaimed, face angle, club path, and launch direction all shift by
the same constant while face-to-path stays put. Store that constant per
session (calibration_offset_deg) and apply it only at read time:
telemetry rows keep the exact TrackMan values.

- PATCH /api/v1/sessions/:id sets or clears the offset (telemetry:write,
  paper_trail audited). It is the only mutable session field.
- GET /api/v1/stats/clubs?calibrated=1 corrects face, path, and lateral
  spread in SQL. face_to_path is never corrected: the offset cancels.
- Dashboard gains a Bay cal. toggle and a per-session offset editor.
  Shot-level correction is client-side math; only club aggregates
  refetch.
@chayuto
chayuto merged commit da2ed07 into main Aug 1, 2026
4 checks passed
@chayuto
chayuto deleted the bay-calibration-layer branch August 1, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant