Repository navigation
feat: a fork server can be the Android push host for itself and linked environments - #45
Merged
Merged
Conversation
…M key The fork's Android app uses its own Firebase project, so upstream's relay cannot reach it. A server started with T3CODE_FCM_SERVICE_ACCOUNT_FILE now keeps the latest agent activity, a device registry and its peers in one JSON file, and sends devices the same FCM payloads upstream's relay sends. It reuses the relay's aggregate, alert, payload and FCM client code from infra/relay by relative import; the two alert functions that live beside the relay's database are copied, with a test that compares them to upstream's. T3CODE_FCM_VALIDATE_ONLY makes FCM check every message without delivering it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…host Each server looks among its linked environments for one that answers as a push host, and AgentAwarenessRelay then publishes there with that link's credential instead of to the T3 Connect relay, keeping its retries. The push host publishes its own threads in process. Its routes take updates only from a linked environment's session and refuse its own environment. A new or lost route republishes active threads. Publishing to the push host respects an explicit off in "Publish agent activity", and runs when the toggle was never set, since T3 Connect sets it. Without a key or a linked push host, publishing is upstream's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd read its status forkPush.getStatus reports each server's role, its push host and link expiry, the registered devices and the peers last heard from. registerDevice and unregisterDevice need settings access; getStatus and sendTest need read access. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its status The app finds the connected environment that holds the FCM key, configures the native notification handler with an identity that names it, and registers its FCM token there again on rotation and on return. While the push host owns the handler, upstream's T3 Connect registration can no longer reconfigure or clear it. Settings → Notifications shows the push host, whether each other environment sends to it and when its link expires, a test notification, and stopping or resuming notifications on this phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…egistration A send that FCM answered UNREGISTERED removed the device by its ID, so a token registered while the old token's send was pending was lost too. Results now apply only while the registration still has the token they were sent to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A send that failed in transport, timed out, was rate limited or met an FCM server error was recorded and dropped, after ingest had already answered the peer, so the alert was lost. Such sends now retry three times over about 21 seconds, while the registration still holds the same token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every delivery advanced the device's card baseline, so a deletion processed after another thread had changed acknowledged that change, and the change's own delivery then saw no transition and never alerted. Deletions now repaint the card without moving the baseline, as upstream's relay does; its regression case is ported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stop was checked only when a registration began, so one waiting on the notification permission or FCM token configured the native handler and registered again after Stop had cleared and unregistered. Stop now bumps a generation that such an attempt checks before each step, and waits for a registration already sent before it unregisters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each connected host started its own registration, and one that lost the race stayed idle for good, so the phone stopped registering once the first host disconnected. One place now picks among the connected hosts: it keeps the current one while it stays, otherwise takes the first by environment ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s headers FcmClient keeps the response status when reading the body times out, so a token answer that stalled after a 200 looked permanent and its alert was dropped. A timeout or transport cause now counts as transient whatever the status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cklog One serial worker carried every device's deliveries, so a device FCM kept rate limiting held up the others for its retries, and updates queued faster than a failing device drained without limit. Each device now delivers on its own fiber, and while it is busy its pending work keeps one entry per thread plus a replay. Delivery reads the rows and compares them with the device's baseline when it runs, as upstream's relay does when its queue lags, so a later update to a thread decides the same alerts as the updates it replaces, and deletions still keep the baseline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…proval alert A replay moves the device's card baseline, and with per-device coalescing it can run before a thread's pending delivery. It then acknowledged that thread's transition silently, so the alert never fired. A replay now picks its alert from the baseline the same way a thread delivery does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Release installs skip infra/relay's dependencies, so effect could not be resolved from the relay sources the push host bundles and the executable build refused the leftover external imports. The server's pack config now falls back to its own node_modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The fork's Android app gets no notifications. Its FCM tokens belong to the fork's own Firebase project, and upstream's relay can only send as upstream's project.
This makes one T3 server the push host. A server started with
T3CODE_FCM_SERVICE_ACCOUNT_FILEsends the app its alerts and ongoing activity card, for itself and for every environment linked to it. It reuses upstream's relay payload and alert code frominfra/relay, so the app's native module and alert rules are unchanged.apps/server/src/fork/push/stores devices and the latest thread rows in a JSON file under the state directory. Each device gets its own delivery fiber that retries FCM failures, with at most one pending entry per thread.POST /api/fork/push/v1/…/agent-activity, using the link's token. Over T3 Connect this works off the LAN. With no key and no host link,AgentAwarenessRelaybehaves as upstream.configureandclearcalls are skipped while the fork owns push. Settings → Notifications shows the host and each environment's link state, and has Send test and Stop buttons.docs/user/push-host.md.Upstream files with small hunks:
AgentAwarenessRelay.ts,server.ts,ws.ts,rpc.ts,clientRpcPermissions.ts,RpcAuthorization.ts,androidNotifications.ts, and the mobile settings screen and app root.Verified end to end up to FCM with two linked dev servers and
T3CODE_FCM_VALIDATE_ONLY=1. A phone test with the rebranded APK from #32 is still to do. Four rounds of independent review by GPT Sol (Codex); the last one approved 163a47a with no findings.Built with Claude Opus in Claude Code (T3 Code), reviewed by GPT Sol in Codex.
🤖 Generated with Claude Code