fix(api): consistent, addressable surface ids & indexes across read/write responses#192
Merged
Conversation
e8036a9 to
b256378
Compare
REST create/update responses now include a lean surfaces array of {id, kind} entries so callers can target server-assigned surface ids without a follow-up read.
The existing kinds array stays as a deprecated compatibility alias because the CLI publish output and its tests still consume it.
The session posts list now exposes the canonical surfaces key with one shape: each entry has id and kind, non-html payloads remain available, and elided html bodies omit the html key instead of sending an empty string. The legacy parts key remains as an alias because sideshow list emits this endpoint's raw JSON and external CLI users may already consume that field; viewer code only reads ids from the list before fetching full post details.
Post detail responses now serialize current and historical surfaces with a derived zero-based index, and session post lists include the same derived index even when html bodies are elided.
The index is computed at response serialization time and is not stored or accepted in write bodies. Lean write receipts remain limited to {id, kind}; they identify minted surfaces but are not positional read payloads.
Make the agent-facing docs reflect the API changes already shipped in this branch: the show CLI help and the get_post MCP description now list surface indexes (the coordinate the --surface <N> / edit_surface target commands consume), and the publish/update MCP descriptions note they return the new surface ids (so an agent can target a surface without a get_post round-trip). No changeset: this only makes docs match behavior already covered by the api-write-surface-ids and surface-read-indexes changesets.
7d0af9d to
7cfd380
Compare
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.
Why
While mirroring a session's posts between two sideshow servers, I noticed the API gives three different, partly-inconsistent answers to the same question — "what surfaces does this post have?" depending on which endpoint you hit. The drift made surfaces hard to address for per-surface edits, and one read path returned an ambiguous, lossy shape. This PR converges the read/write responses on one surface model so a surface is consistently identifiable and addressable everywhere.
What changed
Same post (an
html+ adiffsurface), before → after across the affected REST and MCP surfaces. Every nested surface now deliberately uses one of the shared response views: lean{ id, kind, index }, full indexed payloads, or indexed preview payloads.1.
POST /api/posts— write responseThe response only named the kinds, so to address a surface you'd just created you had to GET the post again to learn its ids.
2.
GET /api/sessions/:id/posts— listLegacy
partskey; thehtmlsurface lost itsidand its body was blanked to""(indistinguishable from a genuinely empty surface).(
partsstays as a deprecated alias ofsurfaces.)3.
GET /api/posts/:id— detailAlready canonical, but no surface stated its position — yet
edit_surface/remove_surface/--surface <N>take a 0-based index.4. MCP
list_posts— tool responseThe MCP list tool still returned
kinds, even after the write responses and REST reads had moved to addressable surface metadata. It now matches the lean list shape: no surface bodies, but every surface has{ id, kind, index }. The deprecatedlist_surfacesalias follows the same shape.5.
GET /api/surfaces/recent/GET /api/posts/recent— recent feed previewThe cross-session recent feed still used only legacy
parts/partKinds, and nested surfaces had noindex. It now has canonicalsurfaceswith indexed preview payloads, while keepingpartsandpartKindsfor compatibility.GET /api/posts/recentis a canonical alias with the same auth behavior as/api/surfaces/recent.6.
GET /api/sessions— post count namingSessions were reporting
surfaceCount, but the value counts posts. The response now exposes canonicalpostCountand keepssurfaceCountas the deprecated alias used by existing viewers.7. Agent feedback payloads — canonical post ids plus aliases
Piggyback feedback on write responses and MCP
wait_for_feedbackstill named the target assurfaceId, even though comments attach to posts. Feedback now includes canonicalpostId/postTitleplus the legacy aliases.8. Shared response views
The response shapes above now flow through shared helpers in
server/apiViews.ts(postWriteView,postDetailView,sessionPostListRowView,mcpPostListRowView,recentPostRowView,feedbackView,sessionRowView) so future nested-surface shape changes are made in one place instead of being patched endpoint-by-endpoint.