oficina / meet Public

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

Plain git — no account needed to clone.

Download

Download this file

1# Product
2
3<!-- impeccable:product-schema 1 -->
4
5> **How this file was written.** Written unattended, on the same
6> instruction that produced `oficina/docs`' `PRODUCT.md`: every fact
7> below comes from repository evidence, not an interview —
8> `docs/superpowers/specs/2026-09-07-meet-design.md` (revision 9, plus
9> the 2026-09-10 and 2026-09-12 amendments), `AGENTS.md`, the slice
10> records under `docs/superpowers/reviews/`, `native/README.md`, and the
11> shipped code in `internal/calls/` on branch `slice/6-deploy`, main
12> `9225ec2`. Facts are cited to a spec section or a file. A reading
13> rather than a citation is marked **[inferred — confirm]** and should
14> be corrected, not trusted. A bare "ruling N" is the Calls spec's §1; a
15> doctrine ruling is always written "suite ruling N".
16
17## Platform
18
19Web, plus native Mac and iPhone/iPad clients over the same server
20contracts (spec §8.4's 2026-09-14 amendment, `native/README.md`).
21
22## Users
23
24**Primary: a member of one team**, making and joining that team's video
25calls. The instance boundary is the team — one instance per team
26(preamble; suite ruling 1, 5, §0.2), the "lone shape" until a suite home
27exists (§7.1). **Secondary: an outside guest**, admitted with a real
28identity, never as an anonymous URL holder: every participant signs in,
29and a meeting link gives an outsider a **guest grant**, never a way in
30without a name (ruling 1; suite ruling 15); a guest waits until an
31admitted member lets them in (ruling 9, §3.3).
32
33Access is a magic link gated by `CALLS_ALLOWED_ADDRESSES`
34(`internal/calls/config.go`), with optional Home sign-in when an operator
35sets all four `CALLS_HOME_*` settings (§7.1.1) — Home only *links* an
36existing member after independent local sign-in; it never creates a
37person or grants membership. Unlike Docs' §8.1, the spec states no
38passkey ruling of its own. **[inferred — confirm]** the team is assumed
39small enough that an address allowlist is appropriate; the spec states
40no target size.
41
42## Product Purpose
43
44Calls is **video calling for one Oficina team**: a member makes a
45meeting, sends one link, and the people who follow it set up camera and
46microphone, wait to be let in if not on the team, and talk (preamble).
47"The instance carries the pages, the sign-in, the signalling and the
48in-call chat, and never a frame of media" (§0.1) — falsifiable: publish
49the SQLite file, its WAL, and every log line, and the worst anyone
50learns is the shape of the team's meetings and who minted what, never a
51title, chat text, or signalling payload, enforced by a WAL-grep test and
52a captured-logger test, not merely asserted (§0.1). Since 2026-10-03 the log also
53holds quality and problem reports under random tags (§15.26): the shape of
54a call's connections, never which meeting or who.
55
56## Positioning
57
581. **The claim is made per process, not once** (§0.1): Calls' own
59 process never touches a media packet; the platform TURN relay
60 forwards encrypted DTLS-SRTP it cannot read; a future platform SFU
61 decrypts to forward and gets its own spec revision when it ships
62 (§5.7).
632. **No relay of its own, by ruling** (suite ruling 6, §5.2): present
64 `CARLOS_RELAY` mints ICE credentials per call; absent means host
65 candidates only, stated before the join button (§5.5).
663. **Two authorities, not one, for a room.** *Standing* (§2.3, computed
67 per request, never stored) decides who may **enter**; a
68 *participation* (§2.4, hub state) decides who may **continue** — an
69 admitted guest keeps talking past its grant's expiry while a member
70 who loses standing is dropped at once (ruling 14).
71
72## Operating Context
73
74- **One Go binary per instance**, `CGO_ENABLED=0`, deployed on CARLOS as
75 a **unit route** (§7.3). Native Apple bindings under `native/` are the
76 one place cgo is used, isolated in `native/go.mod` (`AGENTS.md`).
77- **Routes today** (`internal/calls/app.go`): `GET /`, `POST /meetings`;
78 `GET /j/{token}` (outside the session group); the holding screen and
79 room; signalling (`stream`, `signal`, `ice`); `POST /m/{sqid}/share`
80 (2026-09-12); five destructive confirmation pairs (remove, takeover,
81 replace invitation, end meeting, revoke agent); Settings and agent
82 tokens; sign-in including optional Home routes; native handoff
83 endpoints; a bearer-only `/api/v1/*` group (`api.go`) outside CSRF and
84 the session group. `GET /healthz`/`GET /api/version` answer from
85 rastrillo itself, outside app middleware.
86- **Scriptless, with browser media participation as the exception, and
87 two script-only parts inside a live room.** Reaching a camera and
88 another browser needs script; so, once a call exists, do the chat
89 panel (`partials/chat.html` renders it `hidden` until script un-hides
90 it) and the admission queue's Admit controls (`room.js`). Every other
91 screen — the list, creating a meeting, a link shown once, every
92 confirm page, sign-in, `/welcome`, the agent token page, the Share
93 page and the Home account-link screens (§7.1.1), and the
94 server-rendered parts of the holding screen and room — works with
95 scripts off (§9; `AGENTS.md`'s UX line carries the media exception;
96 full list below).
97- **Nothing stored beyond a meeting's bones.** Rooms, peers, admission,
98 chat and presence live in an in-process hub and die with the process
99 (§2.2); a restart drops every live call (§4.5). Stored: `persons`,
100 `meetings` (sealed title, `internal/calls/seal/`), `meeting_links`
101 (hash-indexed plus a sealed copy for sharing since 2026-09-12),
102 `pending_joins` (a keyed address fingerprint, never plaintext),
103 `guest_grants`, `agents` (a member's minted principal; the token
104 itself is never stored, only its SHA-256) (models.go; §2.1).
105- **Quality reports and "Report a problem" go to the log, by Paul's ruling
106 of 2026-10-03** (spec §15.26), which knowingly bends "stores nothing
107 about calls". Collected: every 30 s in a call and at leave, each client's
108 connection numbers per remote peer (bitrate, loss, RTT, jitter, audio
109 concealment and jitter buffer, video freezes and frames, frame size and
110 fps, the encoder's limitation, screen recovery steps), the candidate types
111 and transport of the path (host/srflx/relay, udp/tcp/tls), the notices
112 shown (Reconnecting, can't hear you yet, no sound, sound blocked, screen
113 stalled), app/browser/OS and their versions, and the *kind* of microphone
114 and speaker (bluetooth, usb, built-in…); all under a random call tag and a
115 random peer tag. When someone presses Send in "Report a problem": their
116 note, and their call diagnostics, which include device names and, on the
117 web, the user agent, with people as peer tags and the meeting scrubbed.
118 Never: names, emails, meeting titles or sqids, peer ids, IP addresses,
119 device names (in quality reports), chat, audio or video. Nothing goes to
120 the database; the log is the only store, kept for the platform's log
121 retention — seven days, or 50 MiB of compressed log per app per box,
122 whichever is first. `CALLS_QUALITY_REPORTS=off` stops quality reports; a
123 person can stop their own in Settings (apps) or the Devices panel (web).
124
125## Capabilities and Constraints
126
127**Shipped:** meeting creation and listing; a link shown once, replaced
128or shared via `POST /m/{sqid}/share`; sign-in with the pending-join
129exception admitting an outsider only while holding a live link (ruling
13012, §3.2); optional Home account-linking (§7.1.1); the holding screen
131and a P2P mesh room capped at four with perfect negotiation, resume, and
132a replay ring (§4); relay-minted ICE credentials renewed before deadline
133(§5.2, §5.3); ephemeral chat and screen share (§6, §5.4); a bearer-token
134drive surface for agents re-checking operator membership on every
135request (§8, §15.17); native Mac and iPhone/iPad apps sharing the Go
136protocol core (`native/README.md`).
137
138**Deliberately not built yet** (§11, as amended): see "What is
139deliberately not here" below for the full, cited list.
140
141**Binding technical constraints:**
142
143- **Media never touches Calls' own process** (§0.1); no handler accepts
144 a media packet. **`scope.Owned`, no bound request body**: every
145 user-owned query goes through it, reads and writes alike; a row that
146 isn't yours 404s, never 403s (`AGENTS.md`).
147- **Standing is computed, never cached** — every request, every
148 15-second hub tick (§2.3, §2.4). A shipped migration is never edited.
149 The agent API's rate limit keys on the resolved agent, not the client
150 address, deliberately (§15.17; see below).
151- **`CGO_ENABLED=0 make ci` is the server's cgo-free gate.** Two
152 things run under `CGO_ENABLED=1` and never ship: `make race`, for
153 any change to `internal/calls/hub` or the stream, and `make
154 native-test`'s own `callscore` race sub-step. The native Mac and
155 iPhone/iPad apps are the one place real cgo does ship — `CallsBridge`
156 is a binary target `CallsKit` links (`native/apple/Package.swift`,
157 `native/scripts/build-mac.sh`) — while every server release stays
158 `CGO_ENABLED=0` (`AGENTS.md`). **`make browser`** needs UDP, which
159 the Claude Code bash sandbox blocks (`AGENTS.md`).
160
161## Brand Commitments
162
163- **Name:** Calls, `amadan.net/oficina/calls`, served at
164 `calls.oficina.works`. Renamed from Calls on 2026-09-16. Ruling 2 chose
165 `oficina/meet` over `oficina/conferencia` (preamble); that ruling stands
166 as the record of what was decided then, and this row is the current
167 name. Built beside Docs, Calendar, Slides and the suite doctrine,
168 consuming a decision made there rather than restating it
169 (preamble, §0.2).
170- **The theme is Estilo's**, adopted at whatever Estilo holds when each
171 slice lands. As recorded on 2026-09-14 (`git ls-remote --tags`
172 against `oficina/estilo`, empty at that check), no tag exists;
173 consumed at a pseudo-version, already adopted by the Home integration
174 on main. **[inferred — confirm]** the exact commit at any later date.
175- **The chat panel is Calls' contribution to Estilo** — "one
176 self-contained template partial and one script file so a second app
177 can adopt it," the suite's first chat, built to be taken (§6).
178- **Voice: [inferred — confirm].** Copy review was waived for this
179 documentation round (steering on `oficina/suite` discussion 5), so
180 shipped strings were not checked against a review record.
181
182## Evidence on Hand
183
184- **Spec:** revision 9 plus the 2026-09-10 and 2026-09-12 amendments,
185 2100+ lines, six rounds of Codex review (§14). **Plans:**
186 `docs/superpowers/plans/`, one programme (slices 2–6) plus a plan per
187 slice. **Slice records:** `docs/superpowers/reviews/`, one per slice
188 2–5 (room, relay, chat/screen-share, drive surface), each an index
189 into the spec's own §15 rulings for that slice.
190- **Native:** `native/README.md`, `native/DESIGN.md`,
191 `native/VERIFICATION.md` — build, gates, stated acceptance limits (no
192 real-device pass claimed for camera permissions, audio-device
193 switching, sleep/wake, or Home passkeys).
194- **What does not exist and must not be invented:** customers,
195 testimonials, benchmarks, pricing, usage numbers, launch date, press,
196 or a production promotion from this slice — edge
197 (`calls.oficina.works`) is promoted by hand by Paul, separately from
198 documentation (slice 6 plan, "What slice 6 was"). The acknowledgements
199 page and the Estilo theme pin are the other two slice-6 items with a
200 disposition rather than a delivery; spec §15.18 is the record for all
201 three.
202
203## Product Principles
204
2051. **State the degradation rather than let it be discovered.** The
206 no-relay floor says calls usually connect only on the same network
207 (§5.5); §0.3 states what the privacy claim excludes (signalling in
208 flight, a replay ring of up to 32 messages for 30 seconds, a link as
209 a bearer); the mail-budget residue is written down, not claimed away
210 (§3.2).
2112. **A verification that cannot distinguish "no" from "I can't see it"
212 is not a verification.** The §0.1 claim is enforced by grepping raw
213 SQLite bytes and the WAL and capturing the logger during a real call;
214 `make browser` asserts a received track by `ontrack` and frame count,
215 never a label (§13).
2163. **Two authorities are named because one would be wrong in some
217 direction** (§2.3–§2.4, ruling 14): a single authority either drops
218 an admitted guest at the grant's two-hour mark or lets an expired
219 grant re-enter.
2204. **A contract is written for the next client, not the current one.**
221 Signalling, `/ice` and the meeting API are contracts a native client
222 could speak (ruling 15, §8.4); the native apps are that ruling paying
223 off.
2245. **Actors are `person:<id>` or `agent:<id>`, never fabricated**
225 (§7.2, doctrine ruling 9).
226
227## Accessibility & Inclusion
228
229`AGENTS.md`'s vendored UI conventions apply: labelled fields with one
230error envelope, destructive actions on their own confirm-page URL and
231never a modal (`ui/confirm-form` — §3.1, §3.5, §4.2), state shown with a
232text label and not colour alone, and empty states that say what the
233screen is for.
234
235**The scriptless floor is the accessibility constraint this app adds
236beyond that shared list.** Reaching a camera and another browser needs
237script, and so, once a call exists, do the room's chat panel and its
238admission-queue Admit controls; nothing else does. With scripts off
239the holding screen's join button becomes one paragraph saying a call
240needs JavaScript and everything else on the page works without it
241(§3.3); the room does the same (§3.4).
242
243No target locale count or WCAG conformance level is stated in the Calls
244spec or `AGENTS.md`. **[inferred — confirm]**: Docs states "WCAG 2.2 AA,
245no exemptions" for itself; nothing here says the same target binds Calls,
246and this file does not assume it does.
247
248## What is deliberately not here
249
250- **Scriptless media, chat and admission** — the exceptions to the
251 scriptless floor: reaching a camera and another browser needs script,
252 and so, once a call exists, do the room's chat panel and its
253 admission-queue Admit controls; every other screen, including the
254 server-rendered parts of the holding screen and the room, works with
255 scripts off (spec §9; `AGENTS.md`'s UX-conventions line carries the
256 media exception in the same words).
257- **No STUN or TURN server of Calls' own.** ICE servers come from the
258 platform relay, present or not at all — never a server Calls names
259 itself (suite ruling 6, §5.2, §5.5).
260- **No SFU, and the room is capped at four admitted peers** — not a
261 claimed product limit, the mesh's own (ruling 5), lifted only when a
262 platform SFU that decrypts to forward ships, in its own spec revision,
263 not a quiet cap change (§5.7, §0.3, §11 "rooms above four").
264- **No client-address limiter on the drive surface.** The agent API's
265 per-agent rate limit (one request a second sustained, burst 60) keys
266 on the resolved agent, not the client address: behind the platform's
267 relay socket every request can share one address, and an
268 address-keyed limiter would let one flood take out every real agent
269 at once (§15.17).
270- **No passkeys ruling of its own.** Unlike Docs §8.1, the spec states
271 no instance-local-passkey decision. **[inferred — confirm]**.
272- **Chat is never stored.** A `chat` message fans out to admitted peers
273 and renders client-side; not replayed to a peer who joins or resumes
274 later, gone with the tab (ruling 8, §6).
275- **No recurring meetings, Calendar integration, recording, attendance
276 records, reactions, dial-in, captions, multi-host signalling,
277 push-to-talk, or virtual backgrounds, and no way to deny a knock** — a
278 guest who isn't admitted simply waits or leaves (§11).
279- **No native client sign-in method of its own** — a native client
280 authenticates through the same Home/local sign-in the browser uses,
281 handed off through a five-minute, one-use authorization; no separate
282 bearer or token scheme for native apps (§8.4's 2026-09-14 amendment,
283 `native/README.md`).
284 **No attendance claim, ever**: §0.3 says Calls does not record who was
285 in a call or for how long; an earlier revision implied one and the
286 spec dropped the implication rather than building the model. The
287 quality reports of §15.26 show that a call under a random tag happened
288 between two times with so many clients in it, for seven days; never
289 which meeting or who.
290
291---
292
293*See also:* the design spec, `README.md`, `AGENTS.md`, and the slice
294records under `docs/superpowers/reviews/`.
295
296