Skip to content

Count only what was actually served: no HEADs, no 304s, no abandoned downloads - #12

Merged
antoine-debroye merged 1 commit into
mainfrom
ad/audit-tier1-statistics
Oct 9, 2026
Merged

antoine-debroye merged 1 commit into
mainfrom
ad/audit-tier1-statistics

Conversation

@antoine-debroye

Copy link
Copy Markdown
Collaborator

Why

A full audit of SelfPod (report in doc/audit-2026-10-09.md, added here) tested the statistics against a real socket and found four ways the headline numbers overstated what had happened. This is Tier 1 of the audit's fix plan: statistics correctness plus dependency bumps.

What changed

  • HEAD requests are no longer recorded. Fastify runs the GET handler for a HEAD, so one was logged as a completed download carrying the file's full size as bytes sent. Two header checks on a 29 MB episode put 56 MB on the Audio served card.
  • A 304 is a zero-byte row and counts in no total (it used to count as a download).
  • A download the app disconnected from is partial everywhere: not counted, badged Partial in the log, partial in the CSV. A stream the player stopped mid-way is still a stream, because that is how players behave.
  • Range: bytes=0- that delivers the whole file is a download. That is every Apple Podcasts download; they were all streams before.
  • AppleCoreMedia is now "Apple media player" (it is the system player for any iOS app, not only Apple Podcasts).
  • The Audio served delta is formatted in its own unit ("+56.3 MB", not "+58,963,151").
  • A resumed download answered with the whole file keeps the range it asked for in the log.
  • Dependencies: fastify 5.12.5, sharp 0.35.5, music-metadata 11.16.1 and transitive fixes. npm audit --omit=dev is clean (was 1 high, 7 fastify advisories, 8 others).

How it was verified

  • npm test: 1313 pass (9 new tests cover HEAD, 304, bytes=0-, the abandoned path, the stopped stream, and the stale-address resume).
  • ./test/acceptance/run.sh selfpod:tier1 against a built image: 63 passed, 0 failed. Six new checks prove HEAD, 304, bytes=0- and an abandoned 29 MB transfer over a real socket, which fastify.inject cannot.
  • Driven live against the dev server with curl and confirmed in the browser: the rows and totals match the rules above.

Stacked PRs for the other tiers (security, performance, UI/UX) follow.

🤖 Generated with Claude Code

…downloads

A full audit of the statistics against a real socket found four ways the
numbers overstated what had happened:

- A HEAD ran the GET handler and was recorded as a download carrying the
  file's whole size as bytes sent; two header checks on a 29 MB episode put
  56 MB on the Audio served card. HEADs are no longer recorded.
- A 304 on an episode counted as a download. It is now a zero-byte row in
  the log and in no total.
- A download the app disconnected from was flagged in its own row and still
  counted, badged 200, exported as "ok". It is now partial everywhere and
  counted nowhere; a stream the player stopped is still a stream.
- Apple Podcasts fetches with `Range: bytes=0-` and was always a stream, so
  the most common iPhone app never registered a download. A range from byte
  zero that delivers the whole file is a download.

Also: AppleCoreMedia is the system player for any iOS app and is no longer
credited to Apple Podcasts; the bytes delta is formatted in its own unit; a
resumed download answered whole keeps the range it asked for in the log.

Dependencies brought to patched releases (fastify 5.12.5, sharp 0.35.5,
music-metadata 11.16.1, transitive fixes); npm audit is clean.

The acceptance script now proves HEAD, 304, bytes=0- and an abandoned
transfer over a real socket, which fastify.inject cannot. The full audit
report is in doc/audit-2026-10-09.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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