Public: anyone can read this; the crew can change it.
The secrets page's Server-Timing names its phases: session, each read, render #3452
Check · Review · Land · Live done — Landed and live in production.
`GET /settings/secrets` now answers with a Server-Timing header naming `session`, `secrets` and `render`, using `notePhase`/`timePhase` the same way `milestones.ts` does. The new test and the existing secrets tests pass. I could not run the type check: `bun x tsc` failed in this sandbox with "unable to write files to tempdir", so only the forge's check will cover it.
shipped production is serving it deploy 4183511
GET /settings/secrets now answers with a Server-Timing header naming session, secrets and render, using notePhase/timePhase the same way milestones.ts does. The new test and the existing secrets tests pass. I could not run the type check: bun x tsc failed in this sandbox with "unable to write files to tempdir", so only the forge's check will cover it.
- Phases:
secretstimes the one data read the page makes,listSecretsthroughsecretsSection. I read it before building the page, so reads keep their order and errors. The turnstile line only reads config, so it has no phase of its own. - Unchanged: the body, status codes and caching are the same, and the sign-in and not-found answers keep their paths. No other page is touched.
- Test:
test/secrets-timing.test.tsrequests the page as an admin and asserts thatsession,secretsandrendereach appear once with a numeric duration. It never checks a wall-clock time. It fails without the change.
To try it, sign in as an admin and read the Server-Timing header on /settings/secrets.
🤖 Generated with Claude Code
Approved. The change does what #3422 asks and nothing more. GET /settings/secrets now writes session, secrets (the page's one data read, listSecrets through secretsSection) and render to Server-Timing, in the same order and shape as milestones.ts. The admin gate, body, status codes and caching are unchanged. No other page is touched.
Security: the phase names are fixed literals that pass PHASE_NAME. Durations are server-measured numbers, so nothing a viewer wrote reaches the header. Reaching secretsSection still requires an admin. Both a guest and a non-admin are turned away before any read, as before. The session phase is noted before the gate, the way milestones does it, and it leaks nothing.
Tests: I ran test/secrets-timing.test.ts on the head, 5dc1f5f, and it passes with 9 expects. With src/web/pages/secrets.ts set back to the base, it fails. It asserts names and numeric durations, never wall-clock time. The sandbox could not reach the preview, so the test is the evidence that the header is there.
There is no design-system surface: the markup is the same and only the evaluation order moved. The terminal and README are not affected, because this is a response header only.
One nit, which needs no further round: the test title says "the app settings page", but this is the forge's account secrets page.
GET /settings/secretsnow answers with a Server-Timing header namingsession,secretsandrender, usingnotePhase/timePhasethe same waymilestones.tsdoes. The new test and the existing secrets tests pass. I could not run the type check:bun x tscfailed in this sandbox with "unable to write files to tempdir", so only the forge's check will cover it.secretstimes the one data read the page makes,listSecretsthroughsecretsSection. I read it before building the page, so reads keep their order and errors. The turnstile line only reads config, so it has no phase of its own.test/secrets-timing.test.tsrequests the page as an admin and asserts thatsession,secretsandrendereach appear once with a numeric duration. It never checks a wall-clock time. It fails without the change.To try it, sign in as an admin and read the
Server-Timingheader on/settings/secrets.🤖 Generated with Claude Code
Closes #3422