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

Merged opened this

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

Merged

`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

opened this

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: appStateFragment in src/web/studio/previews.ts wraps the same reads with notePhase and timePhase, as milestones.ts does. 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: record is the app-record read. I couldn't call it app, because the header already carries its own app;dur entry and the name would have appeared twice.
  • panels: this one covers appPanels, 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 shared appPanels, which the studio page also uses.
  • Test: test/app-state-timing.test.ts requests 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

Closes #3516

commented

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: appStateFragment in src/web/studio/previews.ts wraps the same reads with notePhase and timePhase, as milestones.ts does. 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: record is the app-record read. I couldn't call it app, because the header already carries its own app;dur entry and the name would have appeared twice.
  • panels: this one covers appPanels, 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 shared appPanels, which the studio page also uses.
  • Test: test/app-state-timing.test.ts requests 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

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs