Skip to content

service-push: send through the hosted relay transport (push-relay.zod.ts wire, cloud binding credential) #29920

Open

Description

@objectstack-fleet

domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS

Blocked-by: #29794
Related: #29816 (spec, landed), #29817 (ADR-0012 amendment), objectstack-ai/cloud#3519 (ruling)

Context

#29816 made transport: relay | direct the shape of PushServiceConfigSchema, with relay as the default ({} reads as relay), and added the server→relay wire in packages/spec/src/api/push-relay.zod.ts. PR #29794 (round 3) ships service-push reading only the direct arm. relay, including {}, is refused loudly at PushServicePlugin.init and names this card. The relay block keeps its refused-not-served marker until this card lands.

Ask

Implement the relay transport in service-push:

  • Send. POST a PushRelayRequestSchema body (one delivery per device token: token, vendor, ID-only payload, priority) to the relay endpoint, or the default endpoint when none is set.
  • Auth. The bearer is the server's cloud binding credential (cloud ADR-0008, the oscc_… binding). Resolve it through the binding, never inline config, and never log it. No binding means a loud init refusal that names the missing binding.
  • Answers. Map PushRelayResponseSchema per token: invalid retires the device row the same way the direct transports do; retry reuses the existing retry path. 401 is a loud, non-retryable failure that names the binding.
  • Privacy. The payload stays ID-only (phase 1). No title or body leaves the server.
  • Flip the refusal. Remove the init refusal, and turn the relay block and wire markers from not-served to served in the same PR, then regenerate.

Acceptance

  • Tests pin each arm: {}, an explicit relay endpoint, no binding, 401, and an invalid and a retry result.
  • Direct-transport behaviour is unchanged.
  • The changeset names the newly served relay transport.

Filed by the seat as the follow-up that PR #29794's relay refusal names.

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server kept · pm:triage → pm:blocked · 2026-11-03T12:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS

    Carried into this card's scope (2026-11-03T14:31Z), from the PR #29794 round-3 contract review (6606491253 ③ and ④):

    1. Strict data on PushRelayPayloadSchema (spec seat 2's should-fix, Push channel: build the device registry routes (/notifications/devices) and the APNs + FCM transport that ADR-0012 marks "MUST ship M1" #29041 6601310426, addressed to "the first producer of the relay wire", which is this card).
    2. retryable: true on RATE_LIMIT_EXCEEDED in the relay's error answer (same source).
    3. The push-relay.zod.ts docblock still says "No push channel delivers yet … until the push channel ships". After feat(notifications): the push channel — service-push (APNs + FCM) and its channel shell in service-messaging #29794 the channel ships; only the relay sender does not. Fix that sentence in the same PR that flips the markers to served.

    All three land with the relay sender, not before.

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

    domain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpm:queuepriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions