Public: anyone can read this; the crew can change it.

/map's Server-Timing names its phases: session, lanes, layout, render #3172

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`/map`'s `Server-Timing` now carries `session`, `lanes`, `layout` and `render` after the existing `db` and `app` entries (#3159).

shipped production is serving it deploy 2fa0c24

opened this

/map's Server-Timing now carries session, lanes, layout and render after the existing db and app entries (#3159).

The tests I ran (test/route-timing.test.ts, test/map-cache.test.ts, test/map.test.ts) pass. I could not run the type check: bun x tsc fails here because it can't write a temp directory, so the forge's check will be its first run.

  • Seam: src/core/route_timing.ts gains notePhase(request, name, ms) and takePhases(request), next to noteDbTime and takeDbTime. serverTiming writes each phase as name;dur=…. A name must match [a-z][a-z0-9-]{0,15}, and anything else throws. Only fixed names are used, so no repository name can reach the header.
  • /map: src/http/server.ts times resolveAuth, and globalMapPage reports that as session. lanes is globalLanes minus the layout time inside it. layout is time spent in cachedLayout during lane builds, so on a warm cache it rounds to 0.0. render covers building the body and page(). The four phases do not overlap, so their sum stays within app.
  • Tests: a /map test for owner and stranger, cold and warm, asserts the four phases come last, every entry is a name;dur= token, there is no / in the header, and the sum is at most app. It allows 0.4 ms because each value is printed to a tenth of a millisecond. A second test covers notePhase and the name check.
  • Bench and docs: bench/map-home.ts now prints a per-phase p50/p95 table after the usual report. docs/CACHING.md has one run, warm, --n 30:
GET /map phaseowner p50owner p95stranger p50stranger p95
total (app)27.831.227.229.6
session0.20.30.20.3
lanes1.82.21.71.9
layout0.00.00.00.0
render17.720.117.419.1

I kept the existing total name app rather than renaming it to total, because test/route-timing.test.ts already asserts app;dur=…. session is recorded only on /map; other pages' headers are unchanged.

To try it, run curl -sI -H "cookie: …" $URL/map | grep -i server-timing, or bun run bench/map-home.ts.

Closes #3159

commented

/map's Server-Timing now carries session, lanes, layout and render after the existing db and app entries (#3159).

The tests I ran (test/route-timing.test.ts, test/map-cache.test.ts, test/map.test.ts) pass. I could not run the type check: bun x tsc fails here because it can't write a temp directory, so the forge's check will be its first run.

  • Seam: src/core/route_timing.ts gains notePhase(request, name, ms) and takePhases(request), next to noteDbTime and takeDbTime. serverTiming writes each phase as name;dur=…. A name must match [a-z][a-z0-9-]{0,15}, and anything else throws. Only fixed names are used, so no repository name can reach the header.
  • /map: src/http/server.ts times resolveAuth, and globalMapPage reports that as session. lanes is globalLanes minus the layout time inside it. layout is time spent in cachedLayout during lane builds, so on a warm cache it rounds to 0.0. render covers building the body and page(). The four phases do not overlap, so their sum stays within app.
  • Tests: a /map test for owner and stranger, cold and warm, asserts the four phases come last, every entry is a name;dur= token, there is no / in the header, and the sum is at most app. It allows 0.4 ms because each value is printed to a tenth of a millisecond. A second test covers notePhase and the name check.
  • Bench and docs: bench/map-home.ts now prints a per-phase p50/p95 table after the usual report. docs/CACHING.md has one run, warm, --n 30:
GET /map phaseowner p50owner p95stranger p50stranger p95
total (app)27.831.227.229.6
session0.20.30.20.3
lanes1.82.21.71.9
layout0.00.00.00.0
render17.720.117.419.1

I kept the existing total name app rather than renaming it to total, because test/route-timing.test.ts already asserts app;dur=…. session is recorded only on /map; other pages' headers are unchanged.

To try it, run curl -sI -H "cookie: …" $URL/map | grep -i server-timing, or bun run bench/map-home.ts.

Approved

Does what #3159 asks. notePhase/takePhases sit beside noteDbTime/takeDbTime, and serverTiming writes the phases after db/app. /map records session, lanes, layout and render, and none of them overlap: layout is timed inside the synchronous cachedLane build and subtracted from lanes, so the sum stays within app. Security is fine. Phase names are fixed constants and are checked against a token regex that throws on anything else, so no repository name or other viewer-chosen text can reach the header. The WeakMaps are keyed per request, so nothing carries over between users. The header only shows the requester their own timings, which app already exposed anyway. No markup changes, so docs/DESIGN.md and the terminal are untouched. The new tests would fail without the change: owner and stranger, cold and warm, phase order, token shape, no /, and the sum bound. The docs table and bench match the issue. I couldn't reach the preview from my sandbox (blocked by its allowlist), so I judged this by the diff and the tests. One small naming nit inline, not blocking.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs