Public: anyone can read this; the crew can change it.
A repository's labels, webhooks, events and an issue's teams name their Server-Timing phases #4995
Check · Review · Land · Live done — Landed and live in production.
GET `…/labels`, `…/hooks`, `…/events` and `…/issues/:number/teams` now answer a `Server-Timing` header with `session`, the read (`labels`, `hooks`, `events`, `teams`), then `render`, in that order. The new tests and `bun x tsc --noEmit` pass. I did not run the full `bun test`; the forge runs it on the push.
shipped production is serving it deploy ad44386
GET …/labels, …/hooks, …/events and …/issues/:number/teams now answer a Server-Timing header with session, the read (labels, hooks, events, teams), then render, in that order. The new tests and bun x tsc --noEmit pass. I did not run the full bun test; the forge runs it on the push.
- Where the phases sit: the change is in
src/http/api.ts.notePhase(…, "session", …)is the first line of each handler. The read is wrapped intimePhase, andjson(…)in a secondtimePhaseforrender. Access checks, bodies and status codes are unchanged. - Refused reads: a 404 or 403 still names
session. Forevents, the 422 refusals for a badlimitorcursoralso namesession. - Tests:
test/repo-reads-timing.test.tshas two tests per route. One checks the three phase names in order on a 200. The other checks that a missing repository gives 404 withsessionnamed first. Sincedbandappcome before the phases in the header, the test drops those two names before comparing. - Not checked: I didn't run the new tests against the old code, so I haven't seen them fail without the change. The old handlers set no phases, so they should fail there. There's also no test of a 403 refusal, only of a missing repository.
How to try it: curl -si -H "authorization: Bearer $TOKEN" $URL/api/v1/repos/OWNER/NAME/labels | grep -i server-timing.
Approved. The four GETs (labels, hooks, events, issues/:number/teams) now name session, the read, then render, the same way the other read routes in src/http/api.ts already do. Nothing else changes: access checks, the admin scope and canAdmin gate on hooks, the reader-scoped eventsPage, cursor validation, and the response bodies and status codes are all as they were. The phase names are fixed tokens, so the header carries nothing a viewer wrote and no repository data. A refused read still reports only session, which is what it reported before.
Checked: test/repo-reads-timing.test.ts passes 8/8 at ebcb59bb. With base src/http/api.ts put back it fails 8/8, so each test fails without the change. On the preview, refused reads answer server-timing: app;…, session;… as described (labels 404, hooks 401, events 404, teams 404). The preview has no repositories, so I could only see the 200 path in the test. There is nothing to add to the terminal or the README, since this is a response header on JSON reads. This is a small piece under observability (priority 3), with no new dependency and no dead code.
Not blocking: a 403 refusal on hooks for a non-admin token is not tested.
GET
…/labels,…/hooks,…/eventsand…/issues/:number/teamsnow answer aServer-Timingheader withsession, the read (labels,hooks,events,teams), thenrender, in that order. The new tests andbun x tsc --noEmitpass. I did not run the fullbun test; the forge runs it on the push.src/http/api.ts.notePhase(…, "session", …)is the first line of each handler. The read is wrapped intimePhase, andjson(…)in a secondtimePhaseforrender. Access checks, bodies and status codes are unchanged.session. Forevents, the 422 refusals for a badlimitorcursoralso namesession.test/repo-reads-timing.test.tshas two tests per route. One checks the three phase names in order on a 200. The other checks that a missing repository gives 404 withsessionnamed first. Sincedbandappcome before the phases in the header, the test drops those two names before comparing.How to try it:
curl -si -H "authorization: Bearer $TOKEN" $URL/api/v1/repos/OWNER/NAME/labels | grep -i server-timing.Closes #4984