oficina / meet Public

spec: Meet revision 8, approved by Paul; ruling 15, native clients

Paul approved the written form on 2026-09-08 and added the direction
that a suite of fully native apps follows the web suite. Ruling 15 and
8.4 record it: the meeting API, the signalling protocol and /ice are
client-neutral contracts; native sign-in is the home's assertion work.
The round 6 findings file is refreshed with the later of two completed
runs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev d4186e7c99f1a1f6d2939606161f032205a8aaa7 parent f467cd9
2 files changed, +59 −33
  • docs/superpowers/specs/2026-09-07-meet-design.md +35 −7
  • docs/superpowers/specs/CODEX-FINDINGS-MEET-R6.md +24 −26
diff --git a/docs/superpowers/specs/2026-09-07-meet-design.md b/docs/superpowers/specs/2026-09-07-meet-design.md
index bf3c1b2..7c9558b 100644
--- a/docs/superpowers/specs/2026-09-07-meet-design.md
+++ b/docs/superpowers/specs/2026-09-07-meet-design.md
@@ -1,9 +1,10 @@
# 🤖 Meet — design
Design, 2026-09-07. Direction approved by Paul in conversation; this is the
-written form. **Revision 7**, carrying the two corrections of the
-sixth Codex review (`CODEX-FINDINGS-MEET-R6.md`, verdict: accept with
-corrections); §14 has all six rounds. Drafted by the Meet
+written form. **Revision 8**, approved by Paul on 2026-09-08 with one
+direction added as ruling 15; revision 7 carried the two corrections of
+the sixth Codex review (`CODEX-FINDINGS-MEET-R6.md`, verdict: accept
+with corrections); §14 has all six rounds. Drafted by the Meet
session (Fable 5.1) from a brainstorm with Paul on 2026-09-06 and
2026-09-07. Every ruling in §1 attributed to Paul was given in that
conversation or on the discussion it cites.
@@ -133,6 +134,7 @@ for the signalling transport (§4.1).
| 12 | **The link is the gate for sign-in.** A magic link is sent to a non-member address only when the browser asking has just followed a live meeting link, and the address is recorded as a pending guest before the mail goes out so the emailed link admits it wherever it is opened. Without a live link, the allowlist gates sign-in exactly as Docs does. | Opening sign-in to any address (revision 1), which opened unsolicited mail and a shared rate-limit budget to anyone | This session, 2026-09-07, on Codex findings R1-8 and R2-1 |
| 13 | **Negotiation is collision-safe**, the W3C perfect-negotiation pattern with politeness decided by peer id order, over an ordered, acknowledged signalling queue per peer pair (§4.6). | A fixed offerer, which cannot renegotiate when the other side adds a track; fire-and-forget POSTs | This session, 2026-09-07, on Codex findings R1-10 and R2-5 |
| 14 | **Entry and participation are two authorities.** Standing (§2.3) decides who may enter a room. A participation (§2.4), created at admission and bound to session and peer, decides who may continue in one. A guest whose grant expires mid-call continues on the participation; a member who loses standing does not. | One authority for both, which either drops an admitted guest at the two-hour mark or lets an expired grant re-enter | This session, 2026-09-07, on Codex finding R2-3 |
+| 15 | **The wire contracts are client-neutral.** A suite of fully native apps follows the web suite, so the meeting API (§8.2), the signalling protocol (§4) and `/ice` (§5.2) are written and tested as contracts a native client could speak, with nothing in them that assumes HTML or a browser (§8.4). | Contracts that exist only as what the templates happen to post | Paul, 2026-09-08 |
---
@@ -926,6 +928,30 @@ retry from. No operation joins a call (ruling 11).
A thin adapter over §8.2, deferred until a consumer asks by name.
+### 8.4 Native clients
+
+Ruling 15: a native app is the next client after the browser, and
+nothing in Meet's server contracts may assume the browser. Concretely,
+in version one:
+
+- The signalling protocol (§4.3, §4.5, §4.6) is JSON over SSE and POST
+ with no HTML in either direction, and the message table is the
+ contract; `room.js` is one client of it, not its definition.
+- `/ice` (§5.2) returns a plain `RTCIceServer` list a native WebRTC
+ stack consumes unchanged.
+- The meeting API (§8.2) is the same surface a native app would use to
+ list, create, link and end meetings.
+- Authentication is the one piece a native client cannot take from
+ version one as is: sessions are cookies minted by a magic link, and a
+ bearer exists only for agents. A native client's sign-in is the
+ home's assertion work (doctrine §5, `oficina/home` §13), not a
+ Meet-local token, and Meet adds no interim of its own.
+
+What version one does **not** do: ship a native client, publish an
+OpenAPI document, or version the protocol beyond `gen` and `seq`. The
+fixtures for the message table (§13) are the machine-readable contract
+until an OpenAPI document earns its place.
+
---
## 9. The scriptless floor
@@ -970,7 +996,8 @@ are drafts for that review, not approved copy.
Recurring meetings. Calendar integration. Recording. Attendance
records. A relay of Meet's own. Rooms above four. Persisted chat.
Reactions. Dial-in. Captions. Home integration. Multi-host signalling.
-Push-to-talk. Virtual backgrounds. Denying a knock (a guest who is not
+Push-to-talk. Virtual backgrounds. A native client and its sign-in
+(§8.4). Denying a knock (a guest who is not
admitted simply waits or leaves). Each is named so the next session
does not rediscover it.
@@ -1202,8 +1229,9 @@ corrections are in revision 7:
| R6-1 CSRF gate wording | The scaffold's `csrf.Protect` checks origin, not a token; the gate now asserts a cross-origin POST refused and a same-origin confirmation accepted (§13). |
| R6-2 successor peer in the 410 | `by` removed; terminal handling keys on `reason` (§4.5). |
-The independent review is complete at revision 7. Revision 7 awaits
-Paul's review of the written form; this line is the record until that
-happens.
+The independent review is complete at revision 7. **Paul approved the
+written form on 2026-09-08**, adding the native-clients direction that
+became ruling 15 and §8.4 in revision 8. Implementation begins at slice
+1 from this revision.
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-MEET-R6.md b/docs/superpowers/specs/CODEX-FINDINGS-MEET-R6.md
index 0476f09..cf2a030 100644
--- a/docs/superpowers/specs/CODEX-FINDINGS-MEET-R6.md
+++ b/docs/superpowers/specs/CODEX-FINDINGS-MEET-R6.md
@@ -1,46 +1,44 @@
# Findings on the Meet spec, revision 6
-GPT-6 via `codex exec`, read-only, round 6, reviewing commit 61475ed against the five earlier findings files. Verbatim.
+GPT-6 via `codex exec`, read-only, round 6, reviewing commit 61475ed against the five earlier findings files. Two runs completed (the first was relaunched after a kill and both finished); this is the later report, which also notes revision 7 already carried its corrections. Verbatim.
-Reviewed revision 6 at `61475ed787d945b2e76ccff372ded6295d409c5d`. No files modified. “Closed” means the design survives the reported failure; implementation remains subject to its gates.
+Reviewed revision 6 at `61475ed787d945b2e76ccff372ded6295d409c5d`. No files modified. **All R5 findings and remaining earlier residues are closed. Two new P3 corrections; no blocking finding.** “Closed” assesses the design against the reported failure, not implementation results.
| R5 finding | Status | Assessment |
|---|---|---|
-| R5-1 cursor across generations | **Closed** | Sequence counters survive pair resets. In the reported failure, the new offer now has a sequence above the receiver’s old cursor and is replayed. Learning the generation through the roster no longer suppresses that offer. [§4.6](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:664) |
-| R5-2 waiting takeover disclosure | **Closed** | Takeover branches on admission state: `gone` to admitted peers, `knock-gone` to admitted members, or no announcement. An admitted guest receives no waiting-peer departure. [§4.2](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:505) |
-| R5-3 destructive GET | **Closed** | Replacement requires a confirmed POST under the scaffold’s CSRF middleware. Fresh-stream GETs refuse conflicts; query parameters cannot authorize replacement. The new test wording has an advisory defect below. [§4.2](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:498) |
+| R5-1 cursor across generations | **Closed** | §4.6 preserves both sequence counters across resets. In the reported failure, B’s new offer now has `seq > 20`, so A’s old cursor cannot suppress it. The roster supplies the missed generation change, and §13 explicitly tests this case. |
+| R5-2 waiting takeover departure | **Closed** | §4.2 branches on the old participation’s state: admitted produces `gone`; waiting produces `knock-gone` for admitted members only; unjoined produces nothing. An admitted guest learns nothing about the waiting departure. |
+| R5-3 destructive GET | **Closed** | §4.2 requires a confirmation page and a CSRF-protected POST. Fresh-stream GETs conflict instead of replacing participation. §2.5 requires current standing and the session’s existing participation at execution. The erroneous test terminology below does not reopen the attack. |
-The entries in R5’s two status tables, checked individually:
+The half-closed entries in R5’s two tables, checked individually:
-| Earlier finding | Status | Assessment |
+| Earlier residue | Status | Assessment |
|---|---|---|
-| R4-1 reset protocol | **Closed** | Typed reset, authoritative pair generations, roster recovery and monotonic cursors now cover the recorded reset-delivery failures. |
-| R4-2 lost replacement notice | **Closed** | Replacement tombstones make resume terminal; fresh-entry conflicts prevent automatic displacement after tombstone expiry. |
-| R4-3 authorization-table disagreements | **Closed** | Participation-only leave, admitted-member moderation and page-access rules remain aligned. |
-| R4-4 revoked continuation | **Closed** | Authentication refusal and authenticated continuation fallback remain separate; neither mints through the revoked link. |
-| R3-7 downstream signalling loss | **Closed** | Retained messages replay across resets; missing history invokes coordinated recovery. |
-| R3-9 replacement loop | **Closed** | Lost notices cannot cause automatic takeover. |
-| R2-4 resume/restart | **Closed** | Admission-branched resume, roster reconciliation and connection disposal on restart remain specified. |
-| R2-5 delivery | **Closed** | Ordered retries, deduplication, replay and shared reset generations answer the recorded failures. |
-| R1-9 reconnect | **Closed** | Renewal preserves admission; missed departures reconcile; restart and replacement have distinct recovery paths. |
-| R1-10 negotiation | **Closed** | Perfect negotiation remains supported, and reset recovery no longer withholds the retained offer needed to finish it. |
+| R4-1 reset protocol | **Closed** | Typed reset operations, hub-owned generations, roster recovery and preserved sequence counters now work together. Losing `pair` no longer makes a retained new-generation offer invisible. |
+| R3-7 downstream signalling loss | **Closed** | An accepted message lost downstream is replayed when retained; missing history triggers a coordinated reset recoverable through either `pair` or the roster. |
+| R2-5 delivery | **Closed** | Ordered POSTs, receiver deduplication, replay and generation recovery answer the recorded delivery failures without restarting the cursor. |
+| R1-10 negotiation | **Closed** | Perfect negotiation supports either offerer; reset recovery supplies the missing exchange; renewal completion remains tied to the replacement ICE generation. |
-No listed residue remains half-closed or worse.
+These closures follow the operative [replay rules](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:598) and [delivery rules](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:662), rather than §14’s dispositions.
-**R6-1 — P3 — §13: The takeover test requires a CSRF token that the reused protection does not use.**
+The other entries in R5’s tables—R4-2, R4-3, R4-4, R3-9, R2-4 and R1-9—remain **closed**. Terminal replacement handling, fresh-entry conflicts, admission-branched resume, restart reconciliation and the corrected endpoint/continuation contracts survive the amendments. None is half-closed or worse.
-The new gate requires “a takeover POST without the CSRF token refused.” The scaffold explicitly uses origin checking, and `csrf.Protect` accepts same-origin POSTs without any token. A legitimate confirmation submission therefore satisfies the stated negative-test condition. [New gate](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:1050), [scaffold middleware](/home/paulca/amadan.net/oficina/meet-spec/internal/meet/app.go:47), [CSRF contract](/home/paulca/go/pkg/mod/amadan.net/rastrillo/rastrillo@v0.26.0/csrf/csrf.go:47).
+**R6-1 — P3 — §13: The takeover gate specifies a CSRF token the reused middleware does not use.**
-**Correction:** Test refusal of cross-origin POSTs and requests lacking accepted same-origin evidence. Also assert that a legitimate same-origin confirmation succeeds without a token. This corrects the gate; it does not reopen R5-3.
+At the reviewed commit, line 1049 requires “a takeover POST without the CSRF token refused.” The scaffold mounts `csrf.Protect`, whose protection checks `Sec-Fetch-Site`, `Origin` or `Referer`. It neither issues nor checks a token. A legitimate same-origin confirmation succeeds without one. [Scaffold mounting](/home/paulca/amadan.net/oficina/meet-spec/internal/meet/app.go:55), [framework protection](/home/paulca/go/pkg/mod/amadan.net/rastrillo/rastrillo@v0.26.0/csrf/csrf.go:47).
-**R6-2 — P3 — §§4.2, 4.5: The replacement response still requires a successor peer that may not exist.**
+**Correction:** Assert that a cross-origin takeover POST is refused without changing participation, and that an authorized same-origin confirmation succeeds without a token. Retain the cross-site GET navigation gate. This corrects the test contract; the POST mechanism already closes R5-3.
-Takeover now ends the old participation and redirects. The replacement peer is allocated by a later stream request, which may never happen or may lose the documented race. Nevertheless, the old peer’s resume response still requires `410 {reason: "replaced", by: <peer>}`. Immediately after the POST, there is no successor ID to return. [Deferred allocation](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:515), [410 response](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:639).
+**R6-2 — P3 — §§4.2, 4.5: The replacement response requires a successor peer that may not exist.**
-**Correction:** Remove `by`, or make it optional until a successor exists. Terminal handling depends on `reason`, so this needs no change to the takeover mechanism.
+§4.2 now ends the old participation and redirects. The successor peer is allocated only when a later fresh stream opens. The old tab can resume between those requests—or after the destination tab closes without opening its stream—yet §4.5 still requires `410 {reason: "replaced", by: <peer>}`. No successor ID exists to populate `by`. [Takeover ordering](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:505), [410 contract](/home/paulca/amadan.net/oficina/meet-spec/docs/superpowers/specs/2026-09-07-meet-design.md:639).
-The amended authorization and recovery mechanisms introduce no blocking defect at the stage-spec threshold. Takeover’s standing check is consistent with its fresh-entry semantics; it does not revoke an expired guest’s existing continuation authority. The disclosed allocation race produces another confirmation opportunity, not automatic displacement.
+**Correction:** Remove `by`; terminal handling needs only `reason: "replaced"`. The tombstone already establishes displacement without identifying a successor.
-The checked reuse contracts and slice ordering introduce no new blocker. The media API assumptions remain supported by the [WebRTC specification](https://www.w3.org/TR/webrtc/) and [candidate statistics contract](https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatestats-usernamefragment). Relay deployment, `rastrillo/rastrillo` discussion 17 and `oficina/suite` discussion 5 remain unverified from the supplied evidence.
+The source checks found no further blocking defect. The relay configuration and credential schedule match relay §2 at `dcf0cad`. The browser contracts support [ICE restart](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-restartice) and the [candidate generation statistic](https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatestats-usernamefragment) used to establish renewal. The scriptless floor remains buildable, and the amendments introduce no dependency on a later slice.
+
+Verification limits remain for `rastrillo/rastrillo` discussion 17, `oficina/suite` discussion 5 and the claimed live relay deployment.
+
+During review, the checkout advanced externally to revision 7 at `f467cd9`, which already contains both corrections above. This report’s findings and verdict concern revision 6 at `61475ed`; they are not an independent review of revision 7.
**Verdict: accept with corrections.**
\ No newline at end of file