Decision (ADR amendment) — what becomes of /p/*'s session-aware affordances once the page is cross-origin from the session
Opened by Zhu Yue ·
⚠️ AMENDED ON THE RECORD 2026-09-02, BY THE RUN THAT DISCHARGED THIS CARD. Two things below were true when this card was authored on 2026-09-01 and are not now.
- It is AMENDMENT 4, not AMENDMENT 2. MOTIR-4004 merged an AMENDMENT 2 (the legal manifest) at
8d80ac8dbon 2026-09-02, between the authoring and the run. Only the ordinal moved.- Two rows of the affordance table below are FALSE, and the amendment records both (§A). "submit a feature request … already anonymous" — it calls
requireCompliantSession()and its own comment says "a LOGGED-OUT caller is rejected 401 (sign-in-to-act)"; and the "ONE of ten is session-gated" count this card inherited from MOTIR-3877 is five of thirteen over the whole public write surface. Filed as MOTIR-4166. The table is kept below as authored, because AMENDMENT 4 §A is a correction OF it.
Write AMENDMENT 4 to motir-core/docs/decisions/public-surface-hosts.md, answering the ONE question that record left standing and that every code card under this story reads: once /p/* is served from motir.co and the Better-Auth session cookie stays host-only on app.motir.co, what happens to each affordance on that page that today reads or requires a session?
The parent ADR (MOTIR-3879) settled the host (§2), the seam (§3), the cookie (§4) and the cloud gate (§5). It did not settle the affordances: §9's "what this record deliberately does NOT decide" lists four items and this is not among them, which is exactly why it has to be written down before anything is built to it. MOTIR-3877's own body says the ADR resolves it; the ADR does not.
Decide it per affordance, in a table, and name the mirror each row follows. The affordances, read off the deleted surface and the shipped routes:
| affordance | what it is today |
|---|---|
| the account menu / sign-in dialog in the public top bar | getSession() on the layout, a sign-in modal that returns you to the page |
follow (POST/DELETE /api/public/p/{identifier}/follow) | 401 without a session — an account relationship |
subscribe (POST …/subscribe) | already anonymous, email only |
roadmap vote and request upvote (POST /api/public-requests/{id}/upvote) | requireCompliantSession(), cross-org, 401 without a session |
request comment (POST /api/public-requests/{id}/comments) | same gate |
submit a feature request (POST /api/public/projects/{projectId}/requests) | requireCompliantSession(), 401 to a logged-out caller, and the same gate on its duplicate pre-check |
in-place overview editing (publicProjectsService.setPublicOverview, canManage on the subject DTO) | a tenant manager editing their own README from the public page |
viewer-awareness on the reads (actorUserId ?? null: the epic-privacy exclusion, "you follow this") | optional personalisation, not a gate |
Rung 1 is the instrument, not the tie-breaker. Check what the mirrors actually do rather than remembering: Notion's published pages are read-only and hand you back to the app; Canny's portal carries its own identity; Statuspage subscribes by email and nothing else; GitHub Pages is static. Use them per row — the answer for vote need not be the answer for edit my own README.
Three constraints the amendment may not trade away, because they are already decided elsewhere: the session cookie is not widened to .motir.co (§4 — that is the whole reason the residual exposure is survivable); motir-marketing does not read the database (§2 alternative E); and nothing here re-opens MOTIR_CLOUD (§5).
The output is a document and the deferrals in it are cards. If the amendment defers anything — a per-tenant identity, a token exchange, a later CORS posture — file the owning card in the same pass and cite its key in the sentence that defers.
Acceptance criteria
docs/decisions/public-surface-hosts.mdgains AMENDMENT 4 (⚠️ amended from AMENDMENT 2, which MOTIR-4004 took on 2026-09-02), in the file's own Status → Context → Decision → Consequences shape, dated and naming this subtask and its story.- It carries a row per affordance in the table above — eight rows — and each row states: what the visitor sees on
motir.co, by what mechanism, and which mirror's behaviour it follows, with the observation recorded (a URL and what was seen), not asserted from memory. - It states explicitly, as a normative sentence, that the session cookie's
Domainis not widened and that no row's mechanism requires it. - It records what happens to viewer-awareness on the reads — whether an anonymous
actorUserId: nullis now the only casemotir.cocan produce, and what that costs (the epic-privacy exclusion and the "you follow this" state). - Every affordance whose mechanism needs code on the
motir-coreside is named, so that the sibling that ships it has a spec: the motir-core act path. - Every deferral in the amendment cites a work-item key that exists.
§9and the§7card table are amended so the record no longer says this question is open, and so the rows for this story and the act affordances on motir.co read true.- No application behaviour ships in this subtask — the diff is
docs/decisions/only.
Context refs
motir-core/docs/decisions/public-surface-hosts.md— §2, §3, §4 (the cookie), §5, §7, §9, AMENDMENT 1motir-core/app/api/public/p/[identifier]/follow/route.ts·subscribe/route.ts— the one gated route and the anonymous one beside itmotir-core/app/api/public-requests/[id]/upvote/route.ts·comments/route.ts—requireCompliantSession(), outside/api/public/*and therefore outside the public contract and the cloud gate; that is a fact this amendment must dispose ofmotir-core/lib/services/publicProjectsService.ts—getOverview(canManage),setPublicOverviewmotir-core/lib/auth.ts— where the cookie is configured, and the thing §4 forbids widening- the design that draws whatever this decides — the consumer that cannot start until this lands
⚠️ ORDINAL CORRECTED AGAIN, 2026-09-02 — it is AMENDMENT 4. MOTIR-4139 (
b615991c4) merged its own AMENDMENT 3 intopublic-surface-hosts.md— the subprocessor seam — while this story was in flight, so the affordance table is AMENDMENT 4. Every reference to AMENDMENT 2 or AMENDMENT 3 on this card and its siblings means that section. Twice in one day: an ADR ordinal is a serialized resource and nothing in the corpus says so — the amendment's own banner now does.
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.