Skip to content

Stream subsystem — the tail #1134's PR train did not close #1144

Description

@teetangh

The #1134 train shipped as eight PRs (#1136#1143). This is everything that audit surfaced and did not close, in one place, so the tail does not get lost when the train merges.

Each item is marked with how it was established: [live] read from the running Stream app, [code] verified against dev, [audit] carried from #1134 and not re-checked.


1. Never written — the two PRs that were planned and skipped

PR 9 · P3 cleanup

  • [live] SDK upgrades. Installed versions run ahead of what package.json implies: @stream-io/video-react-sdk 1.35.2 (latest 1.40.2), stream-chat 9.41.1 (9.50.3), stream-chat-react 13.14.4 (14.11.x — a MAJOR, needs its own PR), @stream-io/node-sdk 0.7.54 (0.7.63).
  • [code] Dead schema. MeetingSession.passcode and MeetingSession.hostKeys are written by the seeds and read by nothing. Class.recordingUrls bypasses the Recording model entirely.
  • [code] MeetingAttendance is never seeded, so every surface that reads it renders empty locally.

PR 10 · Docs

  • docs/stream/README.md does not exist but is linked from three files.
  • Zero occurrences of "BetterAuth" across docs/stream/, while five files still describe NextAuth.
  • 05-video-implementation.md documents a streamCallId format that has not been used for months.
  • 13-recording-webhooks.md declares a StorageType enum that does not exist.
  • Three different names for the org tag across three documents.

2. Open findings

2a. call_member can end a call for everyone — new, found during #1136 review triage

[live] The default call type grants call_member the end-call permission, and POST /api/meetings/[meetingId]/join assigns call_member to every participant. Any attendee can end a consultation for both sides from devtools.

ensure-call-type-grants.ts deliberately does not revoke it: EndCallButton.tsx:46 calls call.endCall() client-side, and the Stream role no longer separates host from participant (host-ness comes from custom.consultantUserId). Revoking it today would take the host's End Call button down with it.

Closing it needs one of:

  • a server-side End Call route that re-checks host-ness via resolveMeetingAccess, then revoke the grant; or
  • assigning admin (a real role on this type, 40 permissions) to access.role === "host" and call_member to everyone else, then revoke.

The same PR did revoke start-recording/stop-recording from call_member, because recording is server-only here — there is no client-side call.startRecording() in the tree — and leaving it granted made the pre-join consent gate from #1139 bypassable.

2b. No unban path calls restoreStreamAccessnew, found during #1136 review triage

[code] restoreStreamAccess() exists and has zero callers. A USER_BANNED action calls deactivateUser, which is permanent; if an operator lifts a permanent ban, the account is left unable to chat with no visible cause and nothing in the codebase undoes it.

#1136 narrowed the function's catch so a timeout or 5xx no longer resolves as a successful restore, but building the reversal path itself is a feature, not a review fix. Note that Stream documents neither outcome for reactivateUser on an already-active user, so the narrow match is asserted rather than documented — worth confirming against the live app when this is built.

2c. sendCallEvent has no subscriber

[audit] There is no call.on("custom") handler, so the notified count measures API acceptances rather than humans warned. Item 4 of #1134's "found wrong and not yet fixed" list, and the only one of those four still open.

2d. The remove-member control has never rendered for anyone

[code] lib/user.ts:82 mapRoleToStream collapses every non-staff account to Stream's "user" role — correct, it is the #981 least-privilege fix. But components/chat/ChannelInfoAndManageDialog.tsx:93 gates ownership on client?.user?.role === "CONSULTANT", an app role client.user.role can never hold. isEventOwner is permanently false and the button at :610 is dead.

Product decision needed — who may remove a member from a webinar/class channel? Plan owner only / owner + accepted collaborators (matching resolveMeetingAccess) / staff+admin only. Whichever it is, the check must read the session, never client.user.role.

Generalises: any comparison of client.user.role against an app role (CONSULTANT/CONSULTEE/STAFF) is dead code by construction. Worth grepping for. The identical bug in ChatSidebar is already fixed in #1142.


3. Missed by the audit — the highest-value unbuilt item

Session Timers (settings.limits.max_duration_seconds)

[live] Currently null on the default call type.

Setting it makes the SFU end the call server-side at the slot boundary, so Stream stamps ended_at whether or not our webhook pipeline works. Given the audit found 1,417 orphaned sessions and a webhook pipeline that had never processed a single event, this is the one control that would have degraded gracefully through the entire outage. Stream's own worked example for it is a telemedicine app with extendable one-hour appointments.

lib/meeting.ts explicitly declines to send it, deferring to #1070. That deferral is worth revisiting. Overlaps #472 (session overrun detection), which describes the same problem from the application side.


4. Deferred by #1143, stated in its body

  • No background-blur toggle in the lobby.
  • Background images are wired but not exposed — needs a curated asset set.
  • No setSuppressionLevel slider for noise cancellation.

[live] Correction worth carrying: #1134's comment thread states the call type "already advertises noise_cancellation.mode: auto-on". It does not — settings.noise_cancellation reads back undefined on the live default type. This changes the billing risk framing for shipping @stream-io/audio-filters-web: the exposure is real but it is not already switched on. Confirm live before acting either way.


Not in here

Part of #1134

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestlaunch: post-mvpFirst 90 days after launch — coverage, polish, operational maturitystreamStream Chat/Video integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions