Half of this is built, on branch activator-wake-timing. The other half I have deliberately not built, and the reason is worth more than the code would have been.
Built: wake to first byte, split
The wake event carlos logs already carries now reports its own timing:
instance woke in 1.4s (spawn 1.2s) (version 7507a33)
Two figures rather than one, because a single total would not settle what your budget is actually asking. spawn is Backend.Start alone — exec to the socket accepting, which is your process opening SQLite, running its ~400 DDL statements and parsing its templates, and none of the platform's work. The rest of the total is the lease, the restore, the seed and starting replication.
So "woke in 1.4s (spawn 1.2s)" says your boot is the problem, and "woke in 1.4s (spawn 200ms)" says it is not. That distinction is the thing your write-up says is unavailable today, and it is the one a cold budget lives or dies on.
You offered three shapes — a header on the first response after a wake, a control-socket read, or a log line to scrape. This is the third, chosen because it costs nothing in the request path. Unmeasured stays unmeasured: a wake with no timings reads exactly as the line did before, rather than claiming an instant wake.
Not built: the edge's Server-Timing header, and why
Your second ask is the right idea and it is a design question, not a patch. This repo has a rule it paid for: a ResponseWriter wrapper that edits headers needs its own header map, because the wrappers in internal/edge embed the writer below, so Header() is ONE shared map from handler to connection — and maybeStore caches rec.Header().Clone().
A timing header added the obvious way would therefore be cached with the response and served to every later visitor, describing a request that happened to somebody else, minutes ago. The gzip wrapper already has a private map for exactly this reason. There are two more traps behind it: a header set after WriteHeader is a TRAILER, so late timing has to be synced down explicitly; and the wrapper order is load-bearing (recorder above the compressor, usage counter below it), so where the timing wrapper sits decides what it can measure.
None of that is hard. It is just a decision about which responses may carry the header and where it goes in the order — and getting it wrong poisons the edge cache with other people's timings, which is a worse bug than the one it fixes. It wants your eye, not an overnight branch.
The per-request half
Worth stating plainly since it follows from the above: the figures on the branch are per WAKE, on the platform's own log stream, not per request. Tying a wake to the request that triggered it is the header question by another name.
Leaving this open on the header.