From 87e15dd817dd5aa186fce0b484d6580b9f435fc4 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Mon, 15 Jun 2026 04:28:54 -0400 Subject: [PATCH] docs: mark W7 P4 pure core done (presence protocol + auth gate) --- docs/contacts-plan.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/contacts-plan.md b/docs/contacts-plan.md index 326ee29..2d75aec 100644 --- a/docs/contacts-plan.md +++ b/docs/contacts-plan.md @@ -115,16 +115,20 @@ address book), though a lightweight mutual-add is optional polish. needs a ticket struct change) and tighter ticket encoding (drop JSON/base64 fat, index the relay URL; lossless ~halving). -### P4 — Friends-only idle listener + presence — Medium (the new primitive) -A long-lived endpoint while the app is open (own ALPN, e.g. `peerspeak/friends/0`), -**outside** the room-session lifecycle, that: -- answers a ping only if `remote_id()` ∈ friends list; -- replies with online + (if in a gathering) a fresh member-issued ticket + the - cosmetic room name; -- is governed by the invisible/normal/discoverable state. -On app open (and a slow rate-limited refresh), ping each friend; render their -status in the friends list. If a friend reports a gathering, show a small -**room-name tag + Join** entry; clicking bootstraps off their ticket. +### P4 — Friends-only idle listener + presence — pure core DONE 2026-06-15 (`a897f5c`) +- **Pure protocol + policy DONE** (`src/presence.rs`, +8 tests): `ControlMsg` + {Ping, Pong{room: Option}} (tagged JSON, unknown tags rejected); + `should_answer(from, friends, mode)` — the friends-only + not-invisible auth gate + (the anti-stranger-surface whitelist; `from` = authenticated `remote_id`); + `PresenceMode` {Invisible, Normal(default), Discoverable} persisted in + `AppConfig`; `interpret_pong` — defensive (sanitizes peer room name, only + surfaces a joinable room if the ticket parses, never auto-joins). +- **Deferred to a 2-machine session (the I/O edges):** bind the live control + endpoint on its own ALPN (e.g. `peerspeak/friends/0`) **outside** the room + session lifecycle; its accept loop (gated by `should_answer`); the rate-limited + outbound ping scheduler (on app open + slow refresh); reporting our current + gathering as a member-issued ticket (reuse `restamp`); rendering friend status + + a **room-name tag + Join** entry in the friends list (overlaps P5). ### P5 — Recents + UI — Medium Local recents list (cosmetic room tags). Friends-list UI with status dots