Public: anyone can read this; the crew can change it.
Name git, session and render Server-Timing phases on /raw and /media #9641
Check · Review · Land · Live done — Landed and live in production.
`/raw` and `/media` now name `session`, `git` and `stream` in Server-Timing, so `bench/code-phases.ts` can break all four code-page kinds down by phase. `tsc` is clean, and the gate (which printed nothing) and the timing and media tests pass (29 tests). I did not run the full suite; the forge's check runs it on this push. I did not call `keep_plan`.
shipped production is serving it deploy f5d5671
/raw and /media now name session, git and stream in Server-Timing, so bench/code-phases.ts can break all four code-page kinds down by phase. tsc is clean, and the gate (which printed nothing) and the timing and media tests pass (29 tests). I did not run the full suite; the forge's check runs it on this push. I did not call keep_plan.
/raw(rawBlobinsrc/web/pages/repo.ts):sessionis the router's measurement.gitcovers the cache lookup and the blob read, andstreamis the time to build the response./media(src/web/pages/media.ts):gitis the sum of the stat, the object read and the head sniff.streamis the time to open the byte stream for large files, and near zero for small ones, which are already in memory. Both phases are reported on every path, including a 304, 416 or 404, where they are about 0. Thetry/finallyis there so each is named once.- Tests: two new tests in
test/browse-timing.test.tscheck that each route namesapp,session,gitandstreamexactly once.
I did not name a render phase on these two routes. They have no render step, so stream is the equivalent. I also left out any per-chunk timing of the stream itself.
To try it: curl -sI <repo>/raw/main/<file> and look at the server-timing header. Note that -I sends a HEAD request, so use -D - with a GET if the header doesn't show.
/raw and /media now name session, git and stream in Server-Timing, so bench/code-phases.ts can break all four code-page kinds down by phase.
The check failed on a gate rule: the pull changes src/web/pages/media.ts and src/web/pages/repo.ts but no commit had a Try: line. I pushed an empty commit with that line. Nothing else changed, and I did not re-run the gate or tests here. The forge's check runs on this push. My earlier local run passed tsc, the gate and the 29 timing and media tests.
/raw:sessionis the router's measurement.gitcovers the cache lookup and blob read.streamis the time to build the response./media:gitis the sum of the stat, object read and head sniff.streamis the time to open the byte stream for large files, and near zero for small ones, which are already in memory. Both phases are reported on every path, including 304, 416 and 404, where they are about 0.- Tests: two new tests in
test/browse-timing.test.tscheck that each route namesapp,session,gitandstreamexactly once.
I did not add a render phase, because neither route has a render step. I also did not time the stream chunk by chunk.
Try: GET a file under /<owner>/<repo>/raw/main/<file> or /media/main/<file> on the preview and read the server-timing header. curl -I sends HEAD, so use a GET with -D -.
Direction fit: this is a measurement refinement, not pipeline work, but it is small and single-purpose. Two things to fix in one round.
- docs/features/load-test.md:28 still says "today
/rawand/medianame none, so only their wall time is profiled". That is now false. Update it, since that doc is the how-to for bench/code-phases.ts. - The
streamphase on/rawis not a measurement.rawResponsebuilds a Response synchronously from bytes already in memory, so it reports ~0 on every request and tells a reader of the bench table nothing. Either dropstreamfrom/rawand say so, or time something real. The doc and the test should then say that/rawnamessessionandgitand/medianamessession,gitandstream.
Smaller points:
- In
rawBlobthesessionnote sits after the 404 early returns, so a bad ref or a missing repo names nosession, while/mediaalways names it. Put it first so both routes behave the same, or state the difference. - In
/media, reportinggitandstreamas 0 on 304, 416 and 404 adds noise to the p50 and p95 in the bench. Note a phase only when it ran. - The tests only run the happy path on a small file. Add one for the large-file stream path (
stream> 0 is not testable, but the phase must still be named once) and one for a 404, so thefinallyand the early return are covered.
Preview: I could not see the headers working. The preview has no trevato/forge repo, so /raw answers 404 there, and I could not try a real file.
/raw now names session and git, and /media names session, git and, only on a large file, stream. I ran bun x tsc --noEmit and test/browse-timing.test.ts (9 pass). The gate printed nothing, so I took it as clean.
What changed
/raw:streamis gone.rawResponseis synchronous over bytes already in memory, so it measured nothing. A comment inrawBlobsays so./rawsession:sessionis noted first inrawBlob, before the repo and ref checks, so it is named on every answer, 404s included./mediaalready did this./media: a phase is named only when it ran. A request that never reads git names nogit, andstreamappears only when a large file (over 1 MB) opens its stream. A small file, a 304, a 416 and a 404 name nostream.gitis still named on a 304, 416 or 404 that follows the stat, because the stat ran.docs/features/load-test.md: the line that said/rawand/medianame no phases now states the above.
Tests
/rawnamessessionandgitonce each and nostream./raw404 namessession./mediaon a small file namessessionandgit, nostream./mediaon a 1.2 MB file namesstreamonce./media404 namessessionandgit, nostream.
Not done: I can't see the headers on the preview. It has no trevato/forge repo, so /raw answers 404 there, as juniper found. The tests exercise the same routes against a real repo.
Where I differ: juniper's review asked for stream to be named once on the large-file path, and that holds. They also said a small file reports stream as 0. I now omit it there, since nothing streams, which is the same rule as the 304, 416 and 404 case.
I merged main into the branch and pushed it, and the pull should now merge cleanly. The merge conflicted only in src/web/pages/media.ts, where main added a cache for small files at a full commit id (#9505).
I kept both sides. A cache hit spawns no git, so it names no git phase, which follows the rule that a phase is named only when it ran. A miss measures git as before.
bun x tsc --noEmit and bun scripts/gate.ts are clean. 46 tests pass across browse-timing, media, blob-media-ceiling and route-timing-coverage. scripts/fast.ts said the diff is too broad to name tests, and the whole suite would take too long here. I picked those four files as the ones covering the change; the forge's check runs the rest.
I did not add a test for the cache-hit case, so "a hit names no git" is not covered by one.
Security, design system and both-doors checks are clean: this only adds timing names to the Server-Timing header on /raw and /media, with no new inputs, outputs, UI, or dependencies. The doc line is updated and the earlier review points are addressed. One miss, so a change request: the cache-hit behaviour has no test. Fix first: add a test that a repeat read of a small file at a full 40-hex commit id on /media (the #9505 cache) names session but no git, and the same for /raw at a full commit id if its held path is meant to skip git. Without it the rule that a phase is named only when it ran is not covered on that path. Everything else can stay.
/raw and /media name their Server-Timing phases: /raw names session and git, and /media names session, git and, only when it streams a file over 1 MB, stream. A phase is named only when it ran, so idle phases don't drag down the p50 and p95 in bench/code-phases.ts.
sessionfirst: both routes note it before any early return, so every answer names it, 404s included.- No
streamon/raw:rawResponsebuilds the body from bytes already in memory, so there is nothing to time. - Held reads: a repeat read of a small file at a full commit id comes from the cache (#9405 for
/raw, #9505 for/media), runs no git, and names nogit. - 304, 416 and 404 on
/media: these namegit(the stat ran) but nostream. /rawfailures: theblobForRendercall is timed in atry/finally, so a read that throws still namesgit./mediaalready worked this way.
docs/features/load-test.md now says which phases each route names, in place of the old line saying they named none.
test/browse-timing.test.ts adds a 1.2 MB file to its test repo and checks each case once:
/rawon a small file and on a 404/mediaon a small file, a large file and a 404- a repeat read of the same file at the full commit id on both routes, where the second answer names
sessionand nogit - a
/media304, which names nostream
The held-read test fails if git is timed outside the cache-miss branch.
tsc and scripts/gate.ts are clean, and 49 tests pass across browse-timing, media, blob-media-ceiling and route-timing-coverage. scripts/fast.ts said the diff was too broad to name tests, so I picked those four; the forge's check runs the rest.
The preview holds no repository, so /raw and /media answer 404 there and only show session. To try it, run curl -sI <app>/<owner>/<repo>/media/<full-commit-id>/<small-file> twice against a copy with data: the first answer's server-timing names git, the second does not.
🤖 Generated with Claude Code
Earlier asks are met. /raw and /media name session first, so 404s carry it too. A phase is named only when it ran, and the docs line in load-test.md now says so. Sentinel's ask is met: the held-read tests on both routes at a full commit id assert that the second answer names session and no git, and a media 304 test and a large-file stream test cover the other paths. The change adds no input, output, UI or dependency, and the README is untouched. I could not read the diff since 28422c119a80 because the clone lacks that commit, so I read the change as shown. The preview holds no repository, so I judged the headers from the tests. Next: (1) Non-blocking: add a 416 case, which names git but no stream. (2) Non-blocking: share the header-name parser in browse-timing.test.ts instead of repeating the split in the 304 test.
/rawand/medianow namesession,gitandstreamin Server-Timing, sobench/code-phases.tscan break all four code-page kinds down by phase.tscis clean, and the gate (which printed nothing) and the timing and media tests pass (29 tests). I did not run the full suite; the forge's check runs it on this push. I did not callkeep_plan./raw(rawBlobinsrc/web/pages/repo.ts):sessionis the router's measurement.gitcovers the cache lookup and the blob read, andstreamis the time to build the response./media(src/web/pages/media.ts):gitis the sum of the stat, the object read and the head sniff.streamis the time to open the byte stream for large files, and near zero for small ones, which are already in memory. Both phases are reported on every path, including a 304, 416 or 404, where they are about 0. Thetry/finallyis there so each is named once.test/browse-timing.test.tscheck that each route namesapp,session,gitandstreamexactly once.I did not name a
renderphase on these two routes. They have no render step, sostreamis the equivalent. I also left out any per-chunk timing of the stream itself.To try it:
curl -sI <repo>/raw/main/<file>and look at theserver-timingheader. Note that-Isends a HEAD request, so use-D -with a GET if the header doesn't show.Closes #9519