Skip to content

Remote follow-ups can stay Not confirmed after a lost delivery receipt #2716

Closed

Description

@christso

What happened

A remote PC can deliver a queued follow-up while its browser misses the delivery receipt. After reconnecting, the saved message can remain Not confirmed even though the agent received it.

To reach that state:

  1. Queue a follow-up on a remote PC while the agent is working.
  2. Lose the browser connection before the remote bridge returns the exact sent receipt.
  3. Reconnect the same browser and device within the receipt retention window.

The browser should recover that message's exact outcome without sending terminal input again.

The local recovery path was added in #2475, which explicitly left remote PCs unchanged. In the upstream commit inspected for this report, MachineRelay.message() removes receipt_resume_id from every attach. The remote bridge therefore cannot associate the returning browser with its retained receipt, and the saved copy stays unconfirmed.

This report is based on that code path and our fork's isolated contract coverage. I have not reproduced it against a newly installed upstream remote bridge in this pass.

How often

Not measured on a live upstream installation. The case depends on losing the exact delivery receipt; it is covered by an isolated test in our fork.

Ovis version

Upstream source inspected: 74dfea3e72de1f26a07e9028aef77d8f77396e67. Our installed fork is based on Ovis 0.4.22. I do not know a last upstream version where remote receipt recovery worked; #2475 deliberately kept it local-only.

How it runs

herdr plugin for the installed fork. The evidence for this report comes from source inspection and isolated contract tests, not a fresh upstream plugin installation.

Server PC

The inspection and test host is Ubuntu 26.04 LTS, x86_64, herdr 0.9.5. An upstream remote-bridge OS was not captured for a live reproduction.

Device and browser

Not collected for this report. No live browser reproduction was run in this pass.

How the device reaches the server

Not collected for a live reproduction. The affected path is the browser's connection to a remote PC through Ovis's machine relay.

How it signs in

Not collected for a live reproduction. The proposed recovery must preserve the authenticated device's scope; it must not trust a raw browser-supplied UUID across devices.

Agent and PC

Queued follow-up delivery on a remote PC. An agent version and remote OS were not collected for a live reproduction.

Screenshots or logs

No live-session screenshots or logs are attached. The code path is MachineRelay at the inspected upstream commit. The fork's contract coverage is test evidence, not native-agent dogfooding.

Proposed approach

Forwarding the raw browser UUID would cross the boundary described in #2475: the remote bridge authenticates the connection server's shared token, not the browser's device.

Our fork derives an ID at the connection server from a per-server random key and the tuple (remote PC, authenticated device, browser UUID). Only controlling attachments receive it. The same scope survives a browser reconnect during that server's lifetime; another device or PC gets a different ID. Observers receive none. The bridge's existing exact-message checks, retention limit and no-resend behavior still apply. Restarting the connection server leaves the copy unconfirmed.

Would you accept a small PR along those lines, or prefer a different way to give the relay a trusted device namespace? I am discussing it first because it extends an intentional boundary.

Activity

  1. devswha commented on Nov 4, 2026

    @devswha
    Owner

    Thanks for the careful write-up. This reproduces on current main (cf40bb0): in an isolated contract test, a follow-up queued through MachineRelay to a real bridge is delivered, but when the same browser reconnects through the relay with its receipt_resume_id, it never gets the sent receipt. As you found, the relay drops the id on every attach, so the remote bridge keeps no receipt for that browser.

    Your proposed approach sounds good to us, and we'd welcome a small PR along those lines: an id derived on the connection server and scoped to (remote PC, authenticated device, browser id), sent only on controlling attaches, with the bridge's existing checks unchanged. A contract case through a relay in server/pending-input.contract.test.ts (same device gets the receipt and nothing is typed again; another device with the same browser id gets nothing) would cover it well.

    Go ahead and open it from your fork whenever you're ready. If we don't hear back in a couple of days, we'll pick it up and credit you.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions