perf(api): drop unread surface bodies from the session hydrate - #237
Merged
Conversation
Opening a session fetches every post in one go with `?hydrate=1`, which served
each post through postDetailView: full current surfaces plus every prior
version's surfaces. The viewer can't use most of that. A sandboxed surface
(html, diff, markdown, terminal, mermaid, code) renders as an opaque-origin
iframe pointed at /s/:id?part=N, which fetches its own body — Card only ever
reads { id, kind, index } to build that URL. So the response that blocks the
stream from rendering carried a second, unread copy of every surface.
Add sessionPostHydratedView: same envelope (the viewer keys "hydrated" off
`history` being an array), minus the bodies. Sandboxed surfaces lose just their
content field, resolved from the existing SURFACE_KIND_METADATA registry rather
than a second hand-maintained list. History surfaces reduce to refs — history
exists to size the version dropdown, and picking an older version re-points each
iframe at ?ver=N rather than rendering from this payload. Native kinds (image,
trace, json) do render from inline data and are untouched.
Across the six largest sessions in a real store: 368 KB -> 18 KB raw, 58 KB ->
5 KB gzipped. GET /api/posts/:id and the MCP read_post tool still return full
detail; only the session-list hydrate view changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Opening a session fetches every post in one request with
?hydrate=1. That response served each post throughpostDetailView— full current surfaces, plus every prior version's surfaces inhistory. The viewer can't use most of it.A sandboxed surface (
html,diff,markdown,terminal,mermaid,code) renders as an opaque-origin iframe pointed at/s/:id?part=N, which fetches its own body.Cardonly ever reads{ id, kind, index }to build that URL — greppingviewer/srcfor reads of any content field (html,patch,markdown,text,mermaid,code) turns up nothing. So the one response that blocks the stream from rendering was carrying a second, unread copy of every surface in the session.What changed
sessionPostHydratedView— same envelope (the viewer identifies a hydrated row byhistorybeing an array), minus the bodies:SURFACE_KIND_METADATAregistry, so a newly added kind can't silently fall behind a hand-maintained list.?ver=Nrather than rendering from this payload.image,trace,json) do render from inline data and are untouched.GET /api/posts/:idand the MCPread_posttool still go throughpostDetailViewand return full detail.?hydrate=1has exactly one consumer (viewer/src/state.ts).Measured
Against the six largest sessions in a real store, comparing the new response to what
postDetailViewproduced for the same posts:The per-surface
/s/:id?part=Nfetches are unchanged — they're the sandbox boundary, and they're individually cacheable and lazy. This shrinks the blocking response, not the request count.Testing
npm test— 440 pass, including a rewritten hydrate test plus a new one covering sandboxed-vs-native stripping across both current and history surfaces.npm run test:e2e --project=chromium— 85 pass (webkit can't launch in this environment: missing system deps, pre-existing).typecheck,lint,format:checkclean.🤖 Generated with Claude Code