diff --git a/.github/banner.svg b/.github/banner.svg new file mode 100644 index 0000000..5e70ed3 --- /dev/null +++ b/.github/banner.svg @@ -0,0 +1,68 @@ + + + phantomturn + Fixes phantom turns in Garmin pool-swim FIT files. Runs in your browser; nothing is uploaded. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + phantomturn + Your watch counted turns that never happened. + Garmin pool-swim FIT repair · runs in your browser · nothing uploaded + + + + diff --git a/AGENTS.md b/AGENTS.md index 55eec2d..be31a0e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 diff --git a/README.md b/README.md index 3db6ae7..6dd05bc 100644 --- a/README.md +++ b/README.md @@ -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/) @@ -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 | | ----------------- | --------------- | ------------------------------------- | @@ -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