oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1# Findings on the Meet spec, revision 5
2
3GPT-6 via `codex exec`, read-only, round 5, reviewing commit bbfe440 against the four earlier findings files. Verbatim.
4
5Reviewed revision 5 at `bbfe4406b5cffaba11ab40e4d1cd6034efc2bfc4`. No files modified. “Closed” assesses the design against the reported failure, not implementation or test results.
6
7| R4 finding | Status | Assessment |
8|---|---|---|
9| R4-1 reset protocol | **Half-closed** | Typed reset messages, server-held generations and roster reconciliation supply coordinated recovery. Resetting sequence numbers without changing the resume cursor makes retained signalling disappear: R5-1. |
10| R4-2 lost replacement notice | **Closed** | A takeover creates a new peer; the old peer receives 410 on resume. After its tombstone expires, fresh entry still receives 409 while another participation owns the session’s room. Automatic reconnection cannot displace that participation. The new takeover operation has separate defects below. |
11| R4-3 authorization-table disagreements | **Closed** | §2.5 now permits participation-only `leave`, requires admitted members for admission and removal, and supplies the page-access rule that §3.3 explicitly adopts. |
12| R4-4 revoked-continuation response | **Closed** | §3.2 distinguishes the inherited 403 at `Authorize` from the authenticated continuation fallback. §13 matches those branches. Neither creates a grant through the revoked originating link. |
13
14The half-closed residues from R4’s two tables, checked individually:
15
16| Earlier residue | Status | Assessment |
17|---|---|---|
18| R3-7 downstream signalling loss | **Half-closed** | Replay works within one generation; recovery across generations remains defective: R5-1. |
19| R3-9 replacement loop | **Closed** | Lost `replaced` delivery no longer permits automatic displacement of another live participation. |
20| R2-4 resume/restart | **Closed** | Admission-branched resume, roster reconciliation, connection disposal on restart and fresh-entry conflict handling answer the recorded failures. |
21| R2-5 delivery | **Half-closed** | Ordering and replay remain, but their sequence cursor cannot identify the new generation: R5-1. |
22| R1-9 reconnect | **Closed** | Admission survives ordinary renewal; missed departures reconcile; restart closes old connections; stale tabs cannot automatically take over. |
23| R1-10 negotiation | **Half-closed** | Perfect negotiation and renewal completion remain specified, but reset recovery can withhold the offer needed to complete negotiation: R5-1. |
24
25**R5-1 — P2 — §§4.5–4.6: The resume cursor cannot distinguish generations after sequence numbers restart.**
26
27`last` maps a sender ID to a sequence number. The hub replays only messages above that number. A pair rebuild resets both browsers’ sequence counters, but the resume request carries no generation. [Resume cursor and replay filter](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:589), [counter reset](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:673).
28
29A concrete failure:
30
311. A has received B’s generation-1 messages through sequence 20, then loses its stream.
322. B triggers a reset. The hub advances the pair to generation 2. B receives `pair`, rebuilds and sends its new offer at sequence 1. The hub accepts it and retains it for A.
333. A resumes with `last[B]=20`. Its roster says generation 2, so A rebuilds. The hub nevertheless suppresses B’s retained offer because `1 <= 20`.
34
35Resetting A’s local receive counter when processing the roster cannot change the cursor already supplied to the server. If B is the impolite peer and still has its local offer outstanding, B ignores A’s colliding offer. A never receives the offer it must answer. The protocol has lost an accepted, retained message without necessarily emitting `gap`.
36
37The server also cannot infer whether `20` belongs to generation 1 or generation 2. Both are valid browser states under the declared wire format. The added browser gate expressly requires recovery when `pair` was missed and its generation is learned through the roster; it needs this missing distinction. [Recovery gate](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:1056).
38
39**Correction:** Carry `{gen, seq}` per sender in `last`, and scope replay, gap detection and receive deduplication to that generation. When the client’s generation is older, send the authoritative generation and replay its retained messages from the beginning, or explicitly initiate another coordinated reset if that history is incomplete. Alternatively, keep sequence numbers monotonic across pair resets. Add a slice-2 test with a nonzero old cursor, a missed `pair`, and a new-generation offer accepted before resume.
40
41**R5-2 — P1 — §§4.2–4.3: Taking over a waiting participation broadcasts its departure into the call.**
42
43The new takeover procedure unconditionally sends `gone` for the old peer to admitted peers. It does not branch on whether that peer was admitted, waiting or unjoined. [Takeover procedure](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:498).
44
45A waiting guest opens a second tab and chooses takeover. The guest’s old waiting peer now produces `gone` for everyone admitted, including admitted guests who are not entitled to see the waiting queue. This discloses a waiting peer’s existence and lets an unadmitted participant inject a call-presence event. Members also receive the wrong event for removing the old knock.
46
47This recreates R1-1’s waiting-departure failure through a new endpoint. Ordinary `leave` correctly sends `knock-gone` only to members; the roster likewise restricts the waiting queue to members. [Departure permissions](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:528), [queue visibility](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:538).
48
49**Correction:** Make takeover use the same state-dependent departure operation as leave and removal: admitted → `gone` to admitted peers; waiting → `knock-gone` to admitted members; unjoined → no room announcement. Test all three states, with an admitted guest observing the room.
50
51**R5-3 — P1 — §§4.2, 4.5: Takeover is a destructive GET that bypasses the reused CSRF protection.**
52
53`GET /m/{sqid}/stream?takeover=1` ends the session’s existing participation. Saying the parameter is sent only by the button does not enforce that condition at the server. [Mutation and button assumption](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:498).
54
55The scaffold mounts rastrillo’s `csrf.Protect`, which expressly passes GET requests without checking their origin. The inherited session cookie uses `SameSite=Lax`. [Scaffold middleware](/home/paulca/amadan.net/oficina/meet-spec/internal/calls/app.go:55), [GET exemption](/home/paulca/go/pkg/mod/amadan.net/rastrillo/rastrillo@v0.26.0/csrf/csrf.go:47), [cookie configuration](/home/paulca/go/pkg/mod/amadan.net/rastrillo/rastrillo@v0.26.0/sessions/sessions.go:119).
56
57An attacker who knows the meeting sqid can send a signed-in member through a cross-site, top-level navigation to that URL. The browser supplies the session cookie, standing succeeds, and the GET ends the member’s call in another tab. The attacker needs neither the session token nor a successful `join`. The unauthorized disconnection happens when the stream opens.
58
59**Correction:** Move takeover to a CSRF-protected POST, with the repository-required confirmation page using `ui/confirm-form`. Make the ownership change atomic and return the new peer for subsequent stream attachment. A GET must not end an existing participation. Add a slice-2 browser test proving that cross-site navigation cannot trigger takeover.
60
61The remaining checked source claims introduce no new blocking defect. The relay list and credential shape match relay §2 at `dcf0cad`; the three-hour credential and two-and-a-half-hour renewal schedule remain within its hard deadline. The browser APIs support replacing ICE configuration followed by restart, and candidate statistics expose the generation field used by §5.3. [W3C configuration semantics](https://www.w3.org/TR/webrtc/#set-the-configuration), [candidate statistics](https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatestats-usernamefragment).
62
63The scriptless floor remains buildable. No new dependency on a later slice was found; all three corrections belong to slice 2 and its gates.
64
65Verification limits remain for `rastrillo/rastrillo` discussion 17, `oficina/suite` discussion 5 and the claimed live relay deployment. The supplied discussion dumps do not establish those claims.
66
67**Verdict: request changes.**