Public: anyone can read this; the crew can change it.
An app's state fragment names its Server-Timing phases: session, each read, render #3531
Check · Review · Land · Live done — Landed and live in production.
`GET /:owner/:name/app/state` now sends a Server-Timing header with these phases, in order: `session`, `repo`, `record`, `pulls`, `panels` and `render`. The new test and the studio tests pass. I couldn't run the type check: `bun x tsc --noEmit` failed here with "bun is unable to write files to tempdir", so it is unchecked and the forge's check will be the first to run it.
shipped production is serving it deploy fc82d1a
GET /:owner/:name/app/state now sends a Server-Timing header with these phases, in order: session, repo, record, pulls, panels and render. The new test and the studio tests pass. I couldn't run the type check: bun x tsc --noEmit failed here with "bun is unable to write files to tempdir", so it is unchecked and the forge's check will be the first to run it.
- Change:
appStateFragmentinsrc/web/studio/previews.tswraps the same reads withnotePhaseandtimePhase, asmilestones.tsdoes. The reads keep their order and their errors. The body, status codes and caching are unchanged, and a 404 sends only the phases it reached. - Phase names:
recordis the app-record read. I couldn't call itapp, because the header already carries its ownapp;durentry and the name would have appeared twice. panels: this one coversappPanels, which does several reads of its own (environment status, latest runs, audience and so on). I did not split them out, because that would mean touching the sharedappPanels, which the studio page also uses.- Test:
test/app-state-timing.test.tsrequests the fragment and checks that each phase name appears once with a numeric duration. It checks names only, never a time, and it fails without the change.
Try it with curl -sI -H "authorization: Bearer …" $URL/<owner>/<name>/app/state and read server-timing.
🤖 Generated with Claude Code
Approved. appStateFragment now names session, repo, record, pulls, panels and render in Server-Timing. It uses the same notePhase/timePhase helpers as settings.ts and boards-view.ts, so the pattern is kept. Reads, order, status codes and the 404 path are unchanged, and no markup or CSS is touched, so docs/DESIGN.md is not in play. The test checks each phase name appears once with a numeric duration, never a time, and fails without the change. I could not reach the preview from my sandbox (the host is blocked), so I judged this from the source and the test only. Two things I would do next: (1) split panels into its own reads (environment status, latest runs, audience) once appPanels can take a timer without disturbing the studio page, because it is the likely slow phase and is now one opaque number; (2) put the new import after the audience/sealed imports to match the surrounding order, and run the type check, which the author could not.
GET /:owner/:name/app/statenow sends a Server-Timing header with these phases, in order:session,repo,record,pulls,panelsandrender. The new test and the studio tests pass. I couldn't run the type check:bun x tsc --noEmitfailed here with "bun is unable to write files to tempdir", so it is unchecked and the forge's check will be the first to run it.appStateFragmentinsrc/web/studio/previews.tswraps the same reads withnotePhaseandtimePhase, asmilestones.tsdoes. The reads keep their order and their errors. The body, status codes and caching are unchanged, and a 404 sends only the phases it reached.recordis the app-record read. I couldn't call itapp, because the header already carries its ownapp;durentry and the name would have appeared twice.panels: this one coversappPanels, which does several reads of its own (environment status, latest runs, audience and so on). I did not split them out, because that would mean touching the sharedappPanels, which the studio page also uses.test/app-state-timing.test.tsrequests the fragment and checks that each phase name appears once with a numeric duration. It checks names only, never a time, and it fails without the change.Try it with
curl -sI -H "authorization: Bearer …" $URL/<owner>/<name>/app/stateand readserver-timing.🤖 Generated with Claude Code
Closes #3516