carlos / platform Public

spec: media roadmap revision 6, codex round 5 accepts

Round 5 found no P1 or P2. Two wording fixes: media-<app> can be, not
is, a valid app name; RemoveParticipant is what ends an active LiveKit
media session, the proxy closes signalling and refuses readmission.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 397cde4f4e19ffe8df0fb0addc3f1c1ad8ac9d19 parent 1255d28
2 files changed, +50 −10
  • docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md +14 −10
  • docs/superpowers/specs/CODEX-FINDINGS-MEDIA-R5.md +36 −0

CI passed — run details

diff --git a/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md b/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md
index db02fea45..50950e42c 100644
--- a/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md
+++ b/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md
@@ -1,6 +1,6 @@
# Media on CARLOS: a staged roadmap
-**Date:** 2026-09-07, revision 5
+**Date:** 2026-09-07, revision 6
**Status:** rulings taken. Paul ruled on all eleven decisions in §7 on
2026-09-07; each is marked **(ruling)**. Everything not so marked is a
**(decision)** that a stage spec may overturn cheaply.
@@ -11,9 +11,12 @@ by GPT-6 via Codex, independently of the author: revision 1's 27
findings are in `CODEX-FINDINGS-MEDIA.md`, revision 2's 14 in
`CODEX-FINDINGS-MEDIA-R2.md`, revision 3's 9 in
`CODEX-FINDINGS-MEDIA-R3.md`, revision 4's 8 in
-`CODEX-FINDINGS-MEDIA-R4.md`, all unedited. Each place a finding changed
-the text is marked **(codex N)**, **(codex R2-N)**, **(codex R3-N)** or
-**(codex R4-N)**. §10 names the two parts declined.
+`CODEX-FINDINGS-MEDIA-R4.md`, and revision 5's 2 in
+`CODEX-FINDINGS-MEDIA-R5.md`, all unedited. **Round 5 returned accept:
+no P1 or P2 remained, and its two wording corrections are in this
+revision.** Each place a finding changed the text is marked
+**(codex N)**, **(codex R2-N)**, **(codex R3-N)** or **(codex R4-N)**.
+§10 names the two parts declined.
This is a roadmap, not an implementation spec. Each stage below gets its
own design and plan when it is picked up. The roadmap exists so the first
@@ -316,8 +319,8 @@ its open questions answered. **(codex R4-8)**
**What an app sees.** `carlos media enable` writes an additive `media`
block into `store.json` (prefix, allowed regions, key ids, hostname)
and mints `media-<app>.<sqid>.<apps domain>`, one label so the account
-wildcard already covers it. **(codex 24)** Because `media-<app>` is
-also a valid app name, the hostname is a **media-host claim** of its
+wildcard already covers it. **(codex 24)** Because `media-<app>` can
+also be a valid app name, the hostname is a **media-host claim** of its
own, owned by the source app and recorded in the account, not an app
row. It is one entry in the account's hostname namespace, and every
door that acquires a hostname there consults it: new app names,
@@ -707,9 +710,10 @@ about sixty room-hours a month, since both are dominated by bandwidth.
refresh for connected clients does not matter, because admission is
keyed on identity and room against platform state, not on a token
being unexpired. Removal is an app-to-platform door that records the
- revocation, calls LiveKit's remove-participant, and has the proxy drop
- that participant's signalling connection, which ends the session
- without waiting for anything the client does. Webhooks are for
+ revocation, calls LiveKit's remove-participant, which is what ends the
+ active media session, and has the proxy close that participant's
+ signalling connection and refuse its next admission, none of it
+ waiting for anything the client does. Webhooks are for
observation and reconciliation, never enforcement. Management
operations are the door's, scoped to the app's rooms. **(codex R3-6,
R4-1, R4-2)**
@@ -952,7 +956,7 @@ failing, then playback working. **(codex 27, R3-9)**
tenant reports a 443-only network, because it changes the fleet's
networking for every box to serve a case nobody has hit yet.
-Every revision-2, revision-3 and revision-4 finding was accepted.
+Every finding from revisions 2 to 5 was accepted.
## 11. Amendments to existing specs
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-MEDIA-R5.md b/docs/superpowers/specs/CODEX-FINDINGS-MEDIA-R5.md
new file mode 100644
index 000000000..9cdb8f36c
--- /dev/null
+++ b/docs/superpowers/specs/CODEX-FINDINGS-MEDIA-R5.md
@@ -0,0 +1,36 @@
+# Findings on the media roadmap, revision 5
+
+Reviewed by **GPT-6 (Codex), 2026-09-07**, fifth pass, against revision 5 at `1255d28`, with Paul's rulings treated as fixed. Unedited apart from this note. Verdict: accept. Revision 6 applies the two wording corrections.
+
+| Revision-4 finding | Disposition | One-line reason |
+|---|---|---|
+| R4-1 — Rejoin admission | Closed | An unavoidable proxy checks revocation before upstream admission, serialized against removal. |
+| R4-2 — Established-session removal | Closed | An explicit backend removal operation calls `RemoveParticipant`, independently of client refresh; §9 bounds termination to one second. |
+| R4-3 — Synchronous publication bypass | Closed | The initiating request receives transformed bytes only after successful console publication. |
+| R4-4 — Instance-host collisions | Closed | All hostname-acquisition doors share the claim; enable checks existing app, route and instance ownership. |
+| R4-5 — Invalid generated hostnames | Partial | Trailing-hyphen refusal and length handling are sound; one blanket app-name assertion remains false. |
+| R4-6 — Existing relay allocations | Closed | Authority expiry now terminates established allocations as well as refusing new ones. |
+| R4-7 — External STUN defaults | Closed | Stage 4b explicitly requires platform-only discovery and client ICE configuration, with no external fallback. |
+| R4-8 — Existing-code descriptions | Closed | Scanning enforcement is qualified, and media is correctly described as the fourth app-mintable kind. |
+
+Reviewed commit `1255d28529a1db3def775c46618df5e98e5eac21`, with Paul’s eleven rulings fixed. “Closed” means complete at roadmap level, not implementation-proven. No files were changed.
+
+**Severity:** P1 breaks a trust guarantee or makes a stage unbuildable; P2 requires correction before the stage spec; P3 is advisory.
+
+## R5-1 — P3 — Stage 1: the blanket app-name assertion remains false
+
+**Problem and evidence:** [Lines 319–320](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/media-roadmap-spec/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md:319) still say that `media-<app>` “is also a valid app name.” [`release.ValidApp`](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/media-roadmap-spec/internal/release/release.go:242) permits at most 32 characters. Prefixing a valid 27–32-character app name produces a 33–38-character label.
+
+The surrounding mechanism correctly accepts these as hostname claims without using the app-name validator, and §1 already states the 26-character qualification. Only the explanatory sentence remains wrong.
+
+**Correction:** Say that `media-<app>` **can also be a valid app name**, which creates the collision the separate claim prevents.
+
+## R5-2 — P3 — Stage 4b: attribute media termination to `RemoveParticipant`
+
+**Problem and evidence:** [Lines 709–712](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/media-roadmap-spec/docs/superpowers/specs/2026-09-07-media-platform-roadmap-design.md:709) describe dropping the participant’s signalling connection as ending the session. LiveKit’s `HandleSignalSourceClose` closes the participant only when ICE has **not** connected; an established media connection can survive signalling loss. [LiveKit implementation](https://github.com/livekit/livekit/blob/master/pkg/rtc/participant.go#L977).
+
+The same paragraph already names the appropriate server operation, `RemoveParticipant`, and the admission gate prevents revoked identities from reconnecting. This closes the earlier architectural defect; the remaining issue is the explanation of which operation terminates media. [LiveKit removal API](https://docs.livekit.io/reference/other/roomservice-api/#removeparticipant).
+
+**Correction:** State that `RemoveParticipant` terminates the active media session, while the proxy closes signalling and refuses subsequent admission. Preserve §9’s one-second termination gate.
+
+**Verdict: accept.** No P1 or P2 problems remain. The two P3 corrections concern explanatory wording; the mechanisms are named, bounded and assigned to stages, and no remaining mechanism-level conflict with Paul’s fixed rulings was found.
\ No newline at end of file