Skip to content

feat(chat): wire contract — acked sends, 16k reject, server-minted identity - #205

Merged
Anuraj-dev merged 2 commits into
mainfrom
feat/192-chat-wire-contract
Jul 30, 2026
Merged

Anuraj-dev merged 2 commits into
mainfrom
feat/192-chat-wire-contract

Conversation

@Anuraj-dev

Copy link
Copy Markdown
Owner

Summary

  • Chat sends move to an acked Socket.io contract: SendChatMessageAck union with EMPTY_MESSAGE / MESSAGE_TOO_LONG / RATE_LIMITED / NOT_IN_ROOM rejection codes; server mints id/kind/sentAt and derives the room from the socket session.
  • Messages over 16,000 chars are rejected outright — never sliced. Composer shows a counter past 14,000 and surfaces rejections inline while keeping the draft.
  • Rate limiting is size-weighted: token cost = max(1, ceil(utf8Bytes/1000)) of the whole serialized payload, clamped to bucket capacity (documented — keeps every legal message sendable while draining the bucket), plus a 64 KiB serialized backstop and maxHttpBufferSize: 128 KiB.
  • Client gates the composer while a send is pending, times the ack out at 8s, and clears the draft only when it still matches the sent text.

Testing

  • Server: handler tests incl. malformed-args regression, serialized-byte backstop, and production rate-limit wiring (call-through guard spy + behavioral bucket drain) — 51 passing.
  • Client: ChatPanel composer/error/counter tests — 19 passing.
  • E2E: over-limit rejection (Enter + button paths), exact-16,000 delivery, and rate-limit rejection → draft kept → recovery, with an ordered sentinel proving the denied send never reached the peer.

Closes #192

…entity

Chat sends now use a Socket.io ack union (SendChatMessageAck): the server
mints id/kind/sentAt, derives the room from the socket session, rejects
empty and >16,000-char messages outright (never slices), and rate-limits
by size — token cost = ceil(utf8 bytes of the whole serialized payload
/ 1000), clamped to bucket capacity so any legal message stays sendable,
with a 64 KiB serialized backstop and maxHttpBufferSize at 128 KiB.
The client gates the composer while a send is pending, times the ack out
at 8s, keeps the draft on rejection, and only clears it when the ack
matches the sent text. Includes a character counter past 14,000 and
inline error surfacing.

Covered by handler unit tests (malformed args, backstop, production
guard wiring via call-through spy + behavioral bucket drain), rate-limit
unit tests, ChatPanel tests, and a Playwright e2e for over-limit
rejection, exact-16k delivery, and rate-limit rejection/recovery with an
ordered non-delivery proof.

Closes #192
@vercel

vercel Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
a-meet Ready Ready Preview Jul 30, 2026 3:15pm

@Anuraj-dev Anuraj-dev closed this Jul 30, 2026
@Anuraj-dev Anuraj-dev reopened this Jul 30, 2026
…ntract

# Conflicts:
#	client/src/components/ChatPanel.tsx
@Anuraj-dev
Anuraj-dev merged commit 583b79b into main Jul 30, 2026
16 checks passed
@Anuraj-dev
Anuraj-dev deleted the feat/192-chat-wire-contract branch August 28, 2026 18:49

This branch was successfully deployed

1 active deployment
Preview — d61136c1 Deployed Jul 30, 2026 by vercel[bot]
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.

Chat wire contract + server reject (no more silent truncation)

1 participant