refs-design
Design, no code. It covers the original ask behind the Errors and Availability work: a customer sees a unique reference on an error page, reads it to support, and support finds exactly what went wrong.
docs/superpowers/specs/2026-09-24-request-reference-design.md:
- Format:
R-0K7M-3QXA-9F2C. That is 30 bits of seconds plus 30 random bits in Crockford base32 (32/28 in the first draft; changed in review), which is safe to read aloud and case-insensitive. The time is inside it, so lookup reads one narrow window with no index. - Minted once, at the first CARLOS edge a request reaches. - Kept across verified backhaul hops, and across the fleet tunnel, which today marks nothing; the tunnel client gains a context flag. - A client-supplied
X-Request-Idis dropped. - Carried to the app asX-Request-Id, which Rails already reads. - Returned on the response. - Never stored in the edge cache, sincewriteCachedreplays stored headers. - Shown on every error page the edge writes: the proxy 502s, the wake 503s, fleet-dark, static, and the pending retry page.
- Stored: up to 20 refs per coalesced error record (additive
refsfield). Past the cap, lookup falls back to the reference's second. - Looked up with
carlos errors --app X --ref R-…and a Reference box on both tabs. The answer is the exact occurrence, or "near" failures when the ref wasn't stored individually, plus log lines carrying the ref, or a plain "nothing carries this reference". - Rollout: mint and carry, then store and look up, then titogo prints the header on its 500 page.
Review and rulings
Bill's rulings on §8, now recorded in the spec (status: approved):
- The reference is returned on every response.
- A client-supplied
X-Request-Idis ignored. MaxRefs = 20.- The
R-prefix and 4-4-4 grouping stand.
Ready to merge. Implementation plans follow, one per rollout step (§7).
Fable design review: approve-with-amendments. All amendments are taken in the latest commit, and spec §10 records them. The ones that change the design:
- Where the response header is set. Setting it at the mint site would have lost it on every gzip response and after a 103, and duplicated it when the app echoes its own. It is now set in
countingWriter.WriteHeader, the bottom wrapper, with no new wrapper. Upgrades and the early-return paths are named explicitly. - Mixed-version trust. On a verified hop or over the tunnel, the inbound value is kept only if it parses as a reference. Otherwise an old front box would pass a client's own
X-Request-Idthrough to a new box that trusts it. - Bit split 32/28 → 30/30, which lasts to 2060, with the birthday bound stated honestly. This stays within the prefix and grouping ruling. Lookup shows collisions rather than guessing.
- Lookup window. Errors ship every 10 s, not every 5 min, so the old reasoning was wrong. What delays a record is request duration: a 13 s redial, or an abandoned wait lasting minutes. The window is now [t − 1 m, t + 30 m], and "near" covers [t, t + 60 s].
- A ref names the group, not the page. Path and status are the group's first sample, and lookup labels them as such.
- Smaller changes: - the overflow row clears refs; - a "not shipped yet" answer comes before "nothing"; - log lookup needs an any-field substring match; - the cache drop happens in
maybeStore; - the pending page becomes per-request.
Also fixes the errors spec's stale five-minute flush claim.
First opened as github.com/carlosframework/platform/pull/420; moved to amadan when amadan became the source of truth (2026-09-24).
Commits
0
Discussions
0
0 open
Tasks
0/0
done
Discussions
- No discussions on this branch yet.
Tasks
- No tasks yet.
Activity
- No activity yet.