Skip to content

feat(server): phones register Expo push tokens with each server - #229

Merged
jayleaton merged 1 commit into
mainfrom
feat/push-registration-20261113
Nov 14, 2026
Merged

jayleaton merged 1 commit into
mainfrom
feat/push-registration-20261113

Conversation

@jayleaton

@jayleaton jayleaton commented Nov 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

Phones register their Expo push token directly with each server. No T3 Connect relay. First layer of three; #230 sends the pushes and #231 is the iOS app. Rebased onto main after the Ada rebrand (#235–#242).

phone ──pushRegistrations.register { installId, expoPushToken, label? }──▶ server
                                                  │  (scope: orchestration:read)
                                                  ▼
             push_registrations (install_id PK, session_id, expo_push_token UNIQUE, label, updated_at)
                                                  │
     listDeliverable: first deletes rows whose session is revoked, expired or missing in auth_sessions
  • pushRegistrations.register / unregister RPCs, in CLIENT_GUARDED_RPC_SCOPES behind orchestration:read. A push only reveals thread titles and states that a reader already sees.
  • Fork migration 024 push_registrations. A row belongs to one install, and re-registering replaces it. A token that moves to a new install id (reinstall) drops its old row.
  • A row is tied to the calling session. Revoking or expiring the phone's session stops its pushes at the next delivery, with no extra stream subscription. The phone re-registers on every connect.
  • capabilities.pushNotifications lets the phone skip older servers.

Evidence

  • Before: no way for a phone to register for pushes. The fork removed T3 Connect in 6147526 / b4424b9.
  • After: apps/server/src/push/PushRegistrations.test.ts passes. It covers upsert by install id, a token moving to a new install, and rows of revoked and expired sessions being deleted. RpcAuthorization.test.ts scope coverage includes the new RPCs.
  • vp run check:changed on the rebased layer: all pass (format, lint, knip, typecheck, tests). The one local ServerEnvironment.test.ts mismatch is the macOS /tmp → /private/tmp symlink and passes with TMPDIR=/private/tmp.

Merge Danger

Door: two-way. The new table is additive. A revert leaves an unused table.

Blast Radius: server. Two new RPCs and one capability flag. Existing RPCs are unchanged.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:L labels Nov 13, 2026
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: 6dec7c9 · PR result: 0d4dfa9 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Adds pushRegistrations.register/unregister RPCs (orchestration:read), a
fork migration for push_registrations keyed by install id and bound to the
calling session, and the pushNotifications capability. Rows of revoked or
expired sessions are deleted before any delivery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jayleaton
jayleaton force-pushed the feat/push-registration-20261113 branch from 98f9e6b to 0d4dfa9 Compare November 14, 2026 03:41
@jayleaton
jayleaton marked this pull request as ready for review November 14, 2026 04:21
@jayleaton
jayleaton merged commit f69560e into main Nov 14, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant