isaac chan · portfolio · analysis

DadFinder — a phone that rings even in total silence

My dad needs to reach me and be certain he reached me. He gets one button on a plain web page. My phone rings at full volume — silent mode, Do Not Disturb, in a bag — and he sees whether I stopped it.

Nothing here rings a real phone. The simulator animates the protocol and its refusals with no network access and no access key. The numbers below come from the real system.
Shape

Two pieces, one of them invisible

My phone runs a small Android app: a foreground service that long-polls a Cloudflare Durable Object, and a full-screen alarm activity that lifts Do Not Disturb, raises the alarm stream to max and starts a siren. My dad gets a single web page with one button and a confirmation.

That asymmetry is the whole design. Everything hard happens on my side, once. He never installs anything, never holds a key, never scans a code — the page he opens is the bare address.

Contract

Six rules, asserted by the simulator

RuleWhy it exists
One ring id goes to every connected phoneA device that polls first must not swallow the ring meant for mine — this was a real bug.
No phone listening → 409 refused:offlineNever park a ring that fires minutes later, out of nowhere.
Line off posts stage=offSo the page says "not connected" immediately instead of waiting out a timeout.
One press per 20 s per callerA public URL should not be a siren anyone can hold down.
stage=start and stage=stop acksDad sees what happened, not a guess.
DND lifted and volume maxed before the sirenOrder matters: raise first, then make noise.
Failure modes

Five things that were wrong, and what the log said

1 — My test phone stole the ring

The hub marked a ring consumed on first delivery, so whichever device polled first took it. Dad pressed RING and my emulator rang. Fixed with per-install client ids and a delivered-to list; two pollers now receive the same id.

2 — "Online" stayed online

Offline only appeared after a 90-second poll timeout, and any connected device kept the flag warm. Now the line tells the hub the moment it goes off.

3 — A queued surprise

A press with nothing listening was parked for three minutes and fired when the line came back. That is the exact opposite of "don't suddenly ring it". It is refused outright now.

4 — The line would not turn on over mobile data

The app dialled the IPv6 address and died there:

ConnectException: Failed to connect to dadfinder…/2606:4700:3033::6815:1c25:443

The carrier hands out an IPv6 route that does not work, and the socket never fell back. The app now pins IPv4 before any socket opens. Verified with Wi-Fi off: Line is on — Connected.

5 — Two alarms from one ring

RingActivity.onPause() re-posted the full-screen intent, so a heads-up banner stacked on top of the alarm. Fixed by retaining the shown timestamp across pause and resume.

Evidence

What was measured

0 → 7alarm volume, of max 7
3 sprocess respawn after kill -9
≤ 15 minwatchdog worst case
9/9simulator self-checks

From the emulator, with Do Not Disturb set to total silence:

dnd filter was 3, lifted
alarm volume 0 -> 7 / max 7
siren playing
ack stop -> 200

Honesty

What is simulated, what is real

Real: the relay contract, the refusals, the acknowledgement path, the timing and the failure modes above all happened on real hardware — a real Worker, a real Android phone, a real emulator in flight mode.

Simulated: the two phone screens, the siren and the network. The simulator contains no endpoint that could ring anyone, holds no access key and contains no endpoint that could ring anyone.

Limits: no iOS build, no SMS fallback, and nothing can survive a force-stop from Settings — the card in the app says so rather than pretending otherwise.

Simulator: /demos/dadfinder.html · Build spec: prompts/dadfinder-prompt.md