Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/banner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 9 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,17 @@ is strong but not confirmation. Both files are deliberately absent from the
`TRUTH` table in `auto-lengths.test.mjs`, and the disagreement reaches the user
as an `uncertain-lengths` finding carrying both readings.

## Before this repository goes public
## This repository is public

It is private today, and a few things are deliberately parked until it is not:
It has been since the Pages deploy was turned on, and both items that used to
be parked here are done: the `workflow_run` trigger in
`.github/workflows/pages.yml` is live, and `tools/needles.local.json` is
untracked. What is left is the standing consequence.

1. **Turn on the Pages deploy.** Uncomment the `workflow_run` trigger in
`.github/workflows/pages.yml` and set Settings → Pages → Source to
"GitHub Actions". Pages needs a public repo on free plans.
2. **Check `tools/needles.local.json` is still untracked.** It holds a name, a
watch serial and sensor ids.
**Everything you add is published the moment it is pushed**, including the
parts that do not look like data. A filename is data — see the fourth
guardrail above. So is a commit message, a test fixture name and an error
string. There is no staging period in which to notice.

`web/legal.html` carries a name and an email and no postal address — a
deliberate call for a private, non-commercial page that collects nothing. If
Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# 🌊 phantomturn
![phantomturn — fixes phantom turns in Garmin pool-swim FIT files, in your browser](.github/banner.svg)

[![CI](https://github.com/MaxWinterstein/phantomturn/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/MaxWinterstein/phantomturn/actions/workflows/ci.yml)
[![site](https://img.shields.io/github/deployments/MaxWinterstein/phantomturn/github-pages?label=site)](https://maxwinterstein.github.io/phantomturn/)
[![runtime dependencies: 0](https://img.shields.io/badge/runtime%20dependencies-0-047857)](#why-it-patches-bytes-instead-of-decoding)
[![licence: MIT](https://img.shields.io/github/license/MaxWinterstein/phantomturn?label=licence)](LICENSE)

### → [maxwinterstein.github.io/phantomturn](https://maxwinterstein.github.io/phantomturn/)

Expand Down Expand Up @@ -31,7 +36,7 @@ length. The length gets split in two, and you are credited with distance you
never swam. The same laps usually come back with the wrong stroke, because the
watch switches stroke at the turn it imagined. Two symptoms, one cause.

Three real sessions, all Forerunner 265 in a 50 m pool:
Six real sessions, all Forerunner 265, in a 50 m pool unless noted:

| Watch said | Actually swum | What went wrong |
| ----------------- | --------------- | ------------------------------------- |
Expand Down Expand Up @@ -153,18 +158,20 @@ scrubbing step that is not optional.
- **Lengths per lap is inferred from the file**, per lap, by measuring each lap
against how long one length takes you in that swim. That handles a session
you lapped inconsistently, which no single number can. It is still a
heuristic tuned on four files — check the before/after numbers, and put a
heuristic tuned on seven files — check the before/after numbers, and put a
number in if you disagree.
- **It only ever merges, never splits.** If the watch *missed* a turn and
recorded two lengths as one, nothing here will recover it.
- The freestyle/breaststroke split is **40 strokes per length**, calibrated in a
50 m pool. A 25 m pool would need roughly half that. It should be derived from
the session instead of hard-coded.
- The freestyle/breaststroke split defaults to `auto`, which scales it from the
pool length — 40 strokes per length at 50 m, proportionally fewer in a short
pool. The constant behind it was still fitted on one swimmer, so a fixed
`--stroke-split` is there if your stroke count runs differently.
- Freestyle and breaststroke only. No backstroke, butterfly, IM or drill — a
watch that labels a length backstroke gets it silently reclassified as one of
the two the classifier does know.
- Multisport files are rejected. The guard is implemented but untested.
- Tested against a Forerunner 265, 50 m pool, four sessions from one swimmer.
- Tested against a Forerunner 265 only: seven sessions from one swimmer, in a
50 m and an 18 m pool.

## Licence

Expand Down
Loading