Skip to content

The receiver retries a discovered Mac forever, even when nothing is listening #78

Description

@nbkdoesntknowcoding

What happens

Reported from a real session. The receiver listed the Mac, said Connecting to nischays-mac-mini…, then Disconnected. Reconnecting…, and looped there indefinitely. The reasonable conclusion is that the app is broken.

What was actually true: the Mac was running but not sharing, so nothing was listening on 8788 at all. The entry the receiver was retrying came from a stale mDNS record cached from an earlier session.

Two separate faults meet here:

  1. A cached discovery entry is retried forever with no re-validation. The record said the Mac was there; it had not been there for some time.
  2. Connection refused — nothing listening — is reported identically to connection dropped mid-session. They mean completely different things. Refused means the Mac is very likely not sharing; dropped means it was and stopped.

What it should do

Tell the two apart. The Rust side already has the error; humanise() in windows/src/errors.ts already distinguishes refusal from other transport failures. That distinction is being thrown away by the time the retry loop writes its message.

Refused, repeatedly, against a discovered address is a specific and very common state, and it has a specific remedy:

Found nischays-mac-mini, but it is not sharing. Press Start on the Mac.

Stop trusting the cache indefinitely. After N consecutive refusals, the entry should be re-validated by browsing again rather than retried. A record for a machine that has stopped advertising should not survive forever.

Where it lives

windows/src/main.ts — the retry loop and ds://disconnected handler. Related work landed in #70, which stopped refusals from being overwritten; this is about the case where no refusal message arrives at all, because there was never a session to refuse it.

Careful of

This is the receiver's connect path, which has reached users broken twice before ("retrying, retrying" and "invalid authority"). The pure parts belong in errors.ts with checks in scripts/verify-refusals.mjs, so the decision can be tested without two machines.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconnectionDiscovery, pairing and the connect path

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions