docs: add a validation protocol for scoring changes - #988
Conversation
|
The document is good and I want it in. The PR as it stands cannot be merged, and the reason has nothing to do with its content. The branch is carrying your fork's mainThe body says "Docs only — The other 187 are 100 commits of unrelated work — Oura live-API import with OAuth2 and Keychain token storage, One thing to flag plainly, not as an accusation: It is also The fixRe-cut from this repo's On the document itselfIts repo-specific claims check out — One correction to make before re-cutting. R3 says the benchmark behind the shipped sleep-staging default "exists only as a numeric claim inside a source comment. No dataset loader, no script, and no test in this repository reproduces it." That was true when you wrote it and is not true now — Two smaller notes for the re-cut, neither blocking:
Re-open against current |
…mport fixes (ryanbr#240) * docs: design + implementation plan for Android sleep stage-timeline rows (ryanbr#988 port) * feat: sleep stage-interval reconstruction from hero weight pairs (ryanbr#988 port) * docs: plan uses full-flavor gradle task names (app has product flavors) * feat: port Hypnogram.displaySmoothed to Kotlin for the sleep timeline rows * feat: per-stage row span extraction for the sleep timeline rows * feat: Metrics constants for the sleep stage-timeline rows * feat: StageTimeline row composables for the sleep hero (iOS ryanbr#988 port) * feat: wire StageTimeline into the sleep hero card, drop StageLegend * fix: gate HC sleep import on days covered by the active strap * fix: in-bed figure spans the full night group, not the main fragment * fix: purge HC my-whoop sleep rows shadowing strap-computed nights
…mport fixes (ryanbr#240) * docs: design + implementation plan for Android sleep stage-timeline rows (ryanbr#988 port) * feat: sleep stage-interval reconstruction from hero weight pairs (ryanbr#988 port) * docs: plan uses full-flavor gradle task names (app has product flavors) * feat: port Hypnogram.displaySmoothed to Kotlin for the sleep timeline rows * feat: per-stage row span extraction for the sleep timeline rows * feat: Metrics constants for the sleep stage-timeline rows * feat: StageTimeline row composables for the sleep hero (iOS ryanbr#988 port) * feat: wire StageTimeline into the sleep hero card, drop StageLegend * fix: gate HC sleep import on days covered by the active strap * fix: in-bed figure spans the full night group, not the main fragment * fix: purge HC my-whoop sleep rows shadowing strap-computed nights
Re-cut from current upstream main carrying only the three intended files (docs/VALIDATION_PROTOCOL.md + links from both CONTRIBUTING.md files) — the previous branch accidentally carried the fork's main. R3's example is updated per review: Tools/SleepPSG (#991) has since landed, so the rule now points at that harness as the model to copy instead of asserting the gap it closed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eae9a68 to
fe76ae5
Compare
|
Re-cut as asked. The branch is now a single commit on top of current The R3 correction is in. The paragraph no longer asserts the gap; it points at Re-verified the doc's repo-specific claims against today's On the two non-blocking notes: both deliberately held out of this diff to keep it docs-only — the |
Why
Six accuracy findings about sleep scoring reversed in a single review when a fresh reader re-measured them instead of inheriting them — a contamination count, three agreement statistics, the sign of a bias, and the direction of a stage error. One of them rested on a mechanism that cannot physically occur, because a single transaction writes both of the streams it claimed had diverged.
None were arithmetic mistakes. They were process failures, and the same process produces them again. This adds
docs/VALIDATION_PROTOCOL.md— eight rules and a paste-in PR checklist — so that a scoring change has a defined bar to clear before it is described as an improvement.The rules, in one line each
E.-1every time and use the exclusion list it prints.The numbers in the doc were measured, not assumed
Everything quantitative in it was re-derived against live wearable data while writing it:
sleep_state), same predictor. The only difference was scoring every band epoch versus only epochs inside the detected sleep sessions. That single unstated choice swings kappa further than most effects anyone is trying to measure. Worth knowing:Tools/SleepBenchsection C uses the in-session domain, so its kappa is not comparable to a whole-record figure.Also recorded
The stored hypnogram vocabulary contains both
wakeandawakeas distinct stage strings. Any consumer written asstage == "wake"silently misfiles the other spelling as sleep. Android already has acanonicalStage()normaliser with tests; Swift does not. The protocol calls this out under R7; the harness fix is filed separately rather than bundled here, since changing the harness mid-audit would change the instrument.Scope
Docs only —
docs/VALIDATION_PROTOCOL.mdplus a link from bothCONTRIBUTING.mdfiles. No code, no behaviour change. No health data: the doc carries no dates, no absolute biometric values, and no database.The bar it sets is deliberately narrow — a scoring change with no held-out number can still ship behind a flag; it just cannot be called an improvement in the changelog, a release note, or a source comment.