Skip to content

docs(webhooks): only document content arms providers actually emit inbound#71

Merged
Yan Xue (yanxue06) merged 1 commit into
mainfrom
docs/webhooks-inbound-arm-accuracy
May 28, 2026
Merged

docs(webhooks): only document content arms providers actually emit inbound#71
Yan Xue (yanxue06) merged 1 commit into
mainfrom
docs/webhooks-inbound-arm-accuracy

Conversation

@yanxue06
Copy link
Copy Markdown
Member

@yanxue06 Yan Xue (yanxue06) commented May 28, 2026

Why

Goal: the webhook docs should only claim what's verifiably true. A few statements promised behavior that no shipping provider produces.

Overclaim: inbound reply / edit / typing / voice / effect

The events spec said "reactions, typing, edits, and replies arrive inside the messages payload as content.type arms." Traced through the actual inbound parsers in spectrum-ts:

  • iMessage (providers/imessage/remote/stream.ts + inbound.ts): only message.receivedtext/attachment/group/richlink/contact/custom, message.reactionAddedreaction, and poll votes → poll_option. Everything else yields empty values. Inbound replies are flattened to textreply_target_guid / thread_originator_guid are present on the gRPC message but never read, so the thread link never reaches the wire.
  • WhatsApp Business (providers/whatsapp-business/messages.ts mapContent): text, media → attachment, reaction, interactive → poll_option, contacts → contact, everything else → custom. No reply/edit/typing.

So reply/edit/voice/effect/typing are send-only or simply not emitted inbound today, and a standalone poll arm is never emitted (poll context rides inline on poll_option). Meanwhile poll_option (which is emitted, and shows up in prod logs) was missing from the table.

The per-arm reference is now split into "delivered inbound today" vs "tolerated but not emitted inbound" so the page stops promising arms that never arrive.

Broken reference: app.spaces.get(spaceId)

The quickstart reply example called app.spaces.get(spaceId). The Spectrum instance has no spaces (nor any get-space-by-id API) — the runtime object only exposes messages / send / edit / stop / responding. Replaced with the real, documented path: rebuild the DM from the sender via imessage(app).space(await im.user(sender.id)), and pass message.sender.id from the webhook. The events "what you don't get" notes were updated to match.

Files

  • docs-src/webhooks/events.mdx.vel (source; webhooks/events.mdx is a gitignored build artifact, regenerated via vellum build)
  • webhooks/overview.mdx, webhooks/delivery.mdx, webhooks/quickstart.mdx (hand-written)

Verification

  • vellum build + eslint + typecheck:docs all pass (pre-commit hook).
  • Claims cross-checked against spectrum-ts inbound parsers and spectrum-webhook/src/delivery/serialize.ts.

Test plan

  • Skim rendered webhooks/events — delivered vs not-delivered tables read correctly
  • Confirm quickstart reply snippet compiles against current spectrum-ts

Made with Cursor


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Documentation
    • Clarified that reactions are delivered inside the messages event via content.type (not as separate top-level events); typing, edits, poll votes, and read receipts remain undelivered.
    • Updated reply guidance to derive outbound context from the sender and build/send replies via the SDK rather than relying on webhook space IDs.
    • Reworked content-shapes and target-ref guidance, narrowed byte-bearing attachment warnings, and added concrete reaction and poll examples.

Review Change Stack

Copilot AI review requested due to automatic review settings May 28, 2026 21:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Warning

Review limit reached

@yanxue06, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 9 minutes and 54 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24eedd52-7c8f-4a60-8c07-12ce6564a454

📥 Commits

Reviewing files that changed from the base of the PR and between 69ef005 and a23f617.

📒 Files selected for processing (4)
  • docs-src/webhooks/events.mdx.vel
  • webhooks/delivery.mdx
  • webhooks/overview.mdx
  • webhooks/quickstart.mdx
📝 Walkthrough

Walkthrough

Updated webhook event documentation: reactions and similar arms arrive inside the single messages event (distinguish via message.content.type). Content wire-shapes and target-ref guidance were revised, and reply examples now derive outbound context from the webhook sender using a live spectrum-ts Space.

Changes

Webhook Event Specification and Handler Guide

Layer / File(s) Summary
Event payload structure and delivery
docs-src/webhooks/events.mdx.vel, webhooks/overview.mdx, webhooks/delivery.mdx
Clarified that the single messages event contains all content and that reactions are distinguished via message.content.type (not separate top-level events). Updated "What we don't deliver" wording to exclude only standalone reaction events.
Content shapes and wire reference documentation
docs-src/webhooks/events.mdx.vel
Reworked the "Content shapes" section to describe the wire-projected form of SDK Content, split inbound-emitted arms vs send-only/forward-compat arms, narrowed byte-bearing-arm warnings (attachments/contact.photo ship metadata only), and updated per-arm tables and target ref guidance with a concrete reaction example.
Outbound reply and response pattern
docs-src/webhooks/events.mdx.vel, webhooks/quickstart.mdx
Replaced space.id-based reply guidance with instructions to initialize/use a separate spectrum-ts instance and obtain or rebuild a live Space from the sender before calling space.send(...). Quickstart example changed to accept senderId and derive context via im.user() and im.space() chains; webhook enqueue call now passes payload.message.sender.id.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • photon-hq/docs#26: Overlaps edits to docs-src/webhooks/events.mdx.vel around messages payload and content modeling guidance.
  • photon-hq/docs#60: Related changes to delivered-vs-undelivered content arms and target/arm-shape documentation.
  • photon-hq/docs#64: Overlapping updates to the per-arm wire reference tables in docs-src/webhooks/events.mdx.vel.

Poem

🐰 In one messages stream the reactions hop,
No separate event — they land and stop.
Rebuild the space from the sender's track,
Let spectrum-ts carry your reply back.
A hopped-up doc, now tidy on the map.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: documentation updates to only document content arms that providers actually emit inbound, which aligns with the PR objectives of auditing inbound parsers and correcting webhook documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/webhooks-inbound-arm-accuracy

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from ea0d7ed to 3bc37a9 Compare May 28, 2026 21:53
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Copilot AI review requested due to automatic review settings May 28, 2026 21:55
@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from 3bc37a9 to 224bd75 Compare May 28, 2026 21:55
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from 224bd75 to 69ef005 Compare May 28, 2026 21:58
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Copilot AI review requested due to automatic review settings May 28, 2026 22:11
@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from 69ef005 to 9da46f4 Compare May 28, 2026 22:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch 2 times, most recently from 4caa479 to b19b9f2 Compare May 28, 2026 22:22
Copilot AI review requested due to automatic review settings May 28, 2026 22:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from b19b9f2 to 82ced5d Compare May 28, 2026 22:31
Webhooks are inbound-only; providers deliver a subset of the SDK's Content
union (spectrum-ts/content documents the full send-side union).

Delivered inbound: text, attachment, reaction, contact, richlink, group.
Confirmed against live iMessage deliveries and spectrum-ts main inbound parsers.

Not delivered inbound (covered by a short note + the spectrum-ts/content link,
not enumerated): reply (arrives as text), voice (arrives as attachment),
edit / typing (send-only), poll / poll_option (the SDK's inbound parsers
construct poll_option, but inbound polls aren't a supported feature), custom
(WhatsApp-only, untested; these docs are iMessage-focused).

Also corrects message.id (composite for derived events, e.g. reactions),
space.phone (shared for pooled lines), and adds reaction + album examples.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yanxue06 Yan Xue (yanxue06) force-pushed the docs/webhooks-inbound-arm-accuracy branch from 82ced5d to a23f617 Compare May 28, 2026 22:31
@yanxue06 Yan Xue (yanxue06) merged commit 77d009b into main May 28, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request May 28, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants