Skip to content

fix(relay): an iPad no longer gets a Done alert for every unrelated publish - #15015

Open
juliusmarminge wants to merge 1 commit into
mainfrom
t3code/relay-push-spam
Open

juliusmarminge wants to merge 1 commit into
mainfrom
t3code/relay-push-spam

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Problem

iPads (and iPhones with Live Activities off) get regular push notifications instead of Live Activity updates. That fallback built its alert from the first row of the user's activity aggregate, not from the thread being published. A finished thread sits at the top of the aggregate for two minutes, so every publish in that window, including tombstones for its subagents and updates from unrelated threads, re-sent the same "Done" alert.

Production traces for one user show a single completion turning into 42 identical "Done" pushes in one minute on an iPad. That device has received 3,089 pushes since Sep 2.

Fix

  • iOS push alerts now describe only the published thread's state (notificationForState). A tombstone (state: null) or another thread's update can't re-ring a completion. Android already worked this way (FcmDeliveries.androidAlertForState).
  • The separate notification-only send (sendPushNotificationForTarget) folds into sendForTarget. One function now decides whether an iOS device rings. Links without notifications still update the card but pass no state, so they never alert.
  • Delivery-time checks are unchanged: stale state, notification preferences, and freshness are still verified when the queued job runs.

Live Activity alerts are unaffected. They already compare against the last delivered aggregate.

Verification

Not visual; the before/after evidence is a regression test.

  • New test alerts a push-only device once per completion, not per later publish: fails on main (the 3 tombstone publishes each queue another "Done" push) and passes with this change (exactly one push).
  • vp test run src/agentActivity/{ApnsDeliveries,AgentActivityPublisher,FcmDeliveries}.test.ts: 111 passed.
  • vpr typecheck (relay): passed. vp lint / vp fmt on changed files: clean.

Needs a relay deploy to take effect. The server-side change that stops subagent tombstones from being published at all is a separate PR.

🤖 Generated with Claude Code

Model: Claude Opus 5.5 (1M context) · Harness: Claude Code in T3 Code


Devin Review

…ublish

Devices without a Live Activity token (iPads, iPhones with Live Activities
off) fall back to regular push notifications. That fallback alerted on the
first row of the user's aggregate rather than the thread being published.
A finished thread stays at the top of the aggregate for two minutes, so
every publish in that window re-sent its Done alert: one completion with six
subagent tombstones produced 42 pushes in a minute.

Push alerts now describe only the published thread's state, matching the
Android path. The notification-only send folds into sendForTarget so one
function decides whether an iOS device rings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Oct 3, 2026
@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 3, 2026
@github-actions github-actions Bot added the size:M 30-99 changed lines (additions + deletions). label Oct 3, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a7f6e7

Macroscope's review found this PR approvable — This is a small, self-contained relay bug fix that prevents unrelated Live Activity aggregate rows from producing duplicate iOS completion alerts while preserving existing preference, replay, Android, and card-delivery behavior. Focused tests cover the new state-based notification flow and duplicate-alert scenario.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.1 KiB 1.1 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.4 KiB 20.4 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 4.9 KiB 4.9 KiB −41 B (−0.8%) 6.8 KiB ✅
Claude Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB −41 B (−3.4%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 20.8 KiB 20.7 KiB −41 B (−0.2%) 29.3 KiB ✅
Claude Live turn messages 2 1 −1 (−50.0%) 8 ✅

Baseline: 22e9d35 · PR result: 1a7f6e7 · 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: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

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

@coderabbitai

coderabbitai Bot commented Oct 3, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Team
  • Run ID: eac4a881-4b24-4595-922b-ef94ffdb9cac
📥 Commits

Reviewing files that changed from the base of the PR and between 22e9d35 and 1a7f6e7.

📒 Files selected for processing (4)
  • infra/relay/src/agentActivity/AgentActivityPublisher.test.ts
  • infra/relay/src/agentActivity/AgentActivityPublisher.ts
  • infra/relay/src/agentActivity/ApnsDeliveries.test.ts
  • infra/relay/src/agentActivity/ApnsDeliveries.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

APNs notification selection now uses published thread state. AgentActivityPublisher sends the aggregate and, when notifications are enabled, the thread state through one APNs delivery call. Android delivery remains unchanged.

Changes

State-Based APNs Delivery

Layer / File(s) Summary
Select and enqueue notifications from thread state
infra/relay/src/agentActivity/ApnsDeliveries.ts, infra/relay/src/agentActivity/ApnsDeliveries.test.ts
sendForTarget accepts optional thread state and uses it to select eligible notifications. The separate push-notification operation is removed. Tests cover state-based delivery, including repeated completed publishes.
Pass published state through publisher delivery
infra/relay/src/agentActivity/AgentActivityPublisher.ts, infra/relay/src/agentActivity/AgentActivityPublisher.test.ts
The publisher makes one APNs sendForTarget call and passes state only when notifications are enabled. Android delivery remains unchanged.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant AgentActivityPublisher
  participant ApnsDeliveries
  participant APNs job queue
  AgentActivityPublisher->>ApnsDeliveries: sendForTarget with aggregate and optional thread state
  ApnsDeliveries->>APNs job queue: enqueue eligible notification derived from thread state
Loading

Suggested reviewers: t3dotgg

Merge Risk: ⚪ Minimal · up to 1a7f6

This change limits iOS alerts to the published thread's state and fixes repeated "Done" alerts on push-only devices. No merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main fix: preventing repeated “Done” alerts for unrelated publishes. It is specific and concise.
Description check ✅ Passed The description explains the problem, fix, and focused verification in detail. It does not include a “Scope and approval” section or explain why the change qualifies for an exemption, but the descript…
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.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

This branch has not been deployed

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

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:M 30-99 changed lines (additions + deletions). vouch:trusted PR 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