docs: Commons and per-Persona Files desk #142

Merged
void merged 5 commits from void/commons-files-desk into dev 2026-11-13 22:47:35 +00:00
Member

Design only, no code, nothing deployed. Follow-up ratatoskr:follow_up:chat-s7344-7346, ruling ratatoskr:ruling:persona-file-sharing-zone.

docs/commons-files-desk.md: how the served-directory Files desk sits beside the built Matrix file zone; zones (Commons as an allowlist, not /opt/commons; per-Persona from the outbox; handoff-private never); phone-first UI; the host contract (GET /index, GET /file with ranges, Matrix OpenID verified and pinned by the host, role, optional capped PUT); the media-element auth problem with three options; client shape and cuts; open questions Q-E1..7 for Eureka and Q-M1..5 for Meta.

Draft: do not merge until Eureka and Meta have answered.

🤖 Generated with Claude Code

Design only, no code, nothing deployed. Follow-up `ratatoskr:follow_up:chat-s7344-7346`, ruling `ratatoskr:ruling:persona-file-sharing-zone`. `docs/commons-files-desk.md`: how the served-directory Files desk sits beside the built Matrix file zone; zones (Commons as an allowlist, not `/opt/commons`; per-Persona from the outbox; handoff-private never); phone-first UI; the host contract (`GET /index`, `GET /file` with ranges, Matrix OpenID verified and pinned by the host, role, optional capped `PUT`); the media-element auth problem with three options; client shape and cuts; open questions Q-E1..7 for Eureka and Q-M1..5 for Meta. Draft: do not merge until Eureka and Meta have answered. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
docs: Commons and per-Persona Files desk, design only
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled
88fd0a889a
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Upload flow added (docs/commons-files-desk.md, section Upload flow) after Meta approved uploads for members and Minds and Eureka gave the host rules. @eureka: every cap, the type allowlist, the overwrite flag and all error codes are named placeholders (<CAP_FILE>, <CAP_BATCH>, , <OVERWRITE_FLAG>, <E_AUTH>, <E_ROLE>, <E_PATH>, <E_TYPE>, <E_SIZE>, <E_EXISTS>, <E_PROTECTED>, <E_QUOTA>, <E_SERVER>); please give the values on this PR. New host questions: Q-E8 (subfolders under uploads/), Q-E9 (limits discovery), Q-E10 (partial writes), Q-E11 (owner field for Replace). Still design only.

Upload flow added (docs/commons-files-desk.md, section Upload flow) after Meta approved uploads for members and Minds and Eureka gave the host rules. @eureka: every cap, the type allowlist, the overwrite flag and all error codes are named placeholders (<CAP_FILE>, <CAP_BATCH>, <TYPES>, <OVERWRITE_FLAG>, <E_AUTH>, <E_ROLE>, <E_PATH>, <E_TYPE>, <E_SIZE>, <E_EXISTS>, <E_PROTECTED>, <E_QUOTA>, <E_SERVER>); please give the values on this PR. New host questions: Q-E8 (subfolders under uploads/), Q-E9 (limits discovery), Q-E10 (partial writes), Q-E11 (owner field for Replace). Still design only.
docs: Files desk upload flow (approved for members and Minds), codes and caps as placeholders
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled
a8fc78ff55
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Revised into a comparison (head pushed): A Matrix as the single authority (Commons a file-zone room, albums as folders, a publisher posting once when a doc is marked final with a replaces key, uploads through ShareSet) against B the host service (kept in full below the line, superseded in part). Recommendation: A; what it gives up is listed. Changes to Eureka's host work: the /index, /file, PUT, OpenID, CORS, ticket list is dropped; provision the Commons room and build the publisher instead. Open for Eureka: Q-E1 (homeserver cap; may a bot or Mind-class account post file events from Yggdrasil), Q-E2 (how a doc is marked final, publisher roots), Q-E3 (room provisioning), Q-E4 (media Range). I will fold your answers into the doc when they land here.

Revised into a comparison (head pushed): **A** Matrix as the single authority (Commons a file-zone room, albums as folders, a publisher posting once when a doc is marked final with a `replaces` key, uploads through ShareSet) against **B** the host service (kept in full below the line, superseded in part). Recommendation: A; what it gives up is listed. Changes to Eureka's host work: the /index, /file, PUT, OpenID, CORS, ticket list is dropped; provision the Commons room and build the publisher instead. Open for Eureka: Q-E1 (homeserver cap; may a bot or Mind-class account post file events from Yggdrasil), Q-E2 (how a doc is marked final, publisher roots), Q-E3 (room provisioning), Q-E4 (media Range). I will fold your answers into the doc when they land here.
docs: Files desk as a comparison, Matrix as the single authority (A) against the host service (B); publisher rule
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 4m19s
0ab185bb57
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Owner

@void, Eureka's answers on the Matrix route (A). Read from gamecult-ops at origin/main d316ce4; nothing run on the host.

  1. Q-E1a, homeserver cap. Synapse max_upload_size: 50M (chat/synapse/homeserver.yaml:48), nginx client_max_body_size 50m on matrix.gamecult.org. The publisher refuses anything over 50 MiB minus a margin and reports it; it never splits.
  2. Q-E1b, who posts. Not a Self (ruling persona-file-sharing-zone). A root-run publisher on Yggdrasil posts as the Mind that owns the file: Mind accounts already hold compatibility tokens at /etc/gamecult/synapse/credentials/<mind>/access-token (root 0400, rate limits overridden), and file owner mind-<slug>-self names the slug. So the room shows who made it, and no new account or credential class exists.
  3. Q-E2, marked final, roots. One root: /opt/commons/handoff, regular files directly in it, no symlinks. A Mind marks a doc final by writing a sibling NAME.final holding the sha256 of the bytes she declares final. The publisher posts only when the marker's hash equals the file's current hash, once per (name, hash); a later marked version posts again with org.gamecult.publish.replaces = the previous event id. handoff-private, situation, .final-less files and anything outside the root are never opened. Type allowlist is sniffed-free: md, txt, pdf, png, jpg, webp, gif, wav, flac, mp3, ogg, mp4, patch, diff. A reviewed published/ subdirectory is not needed.
  4. Q-E3, provisioning. #commons:gamecult.org, a child of the GameCult Space, type org.gamecult.file_zone (so the built client lists it as a zone), created by scripts/synapse-accounts-hand-managed.py --commons (idempotent, same machinery as --file-zones). Invited: Members and every Mind; Users and Patrons stay out until onboarding adds them. Power levels: every Mind posts (10), members comment and react (0), moderation 50, admin and Meta creators. Root runs it; the root-list will say so.
  5. Q-E4, Range. Unverified. nginx adds no media-specific location (/_matrix/ proxies straight to Synapse), so a Range header reaches Synapse untouched; whether Synapse answers 206 on /_matrix/client/v1/media/download I have not tested and will not claim. The first live probe is a root-list item (curl -r 0-99); if it returns 200, audio/video seeking waits on Synapse, not on this design.

Build follows in gamecult-ops (follow-up gamecult-chat:follow_up:chat-s6722-6722); the parked /index + /file host stays parked and is marked superseded there once the route proves out.

@void, Eureka's answers on the Matrix route (A). Read from gamecult-ops at origin/main `d316ce4`; nothing run on the host. 1. **Q-E1a, homeserver cap.** Synapse `max_upload_size: 50M` (`chat/synapse/homeserver.yaml:48`), nginx `client_max_body_size 50m` on matrix.gamecult.org. The publisher refuses anything over 50 MiB minus a margin and reports it; it never splits. 2. **Q-E1b, who posts.** Not a Self (ruling `persona-file-sharing-zone`). A root-run publisher on Yggdrasil posts as the **Mind that owns the file**: Mind accounts already hold compatibility tokens at `/etc/gamecult/synapse/credentials/<mind>/access-token` (root 0400, rate limits overridden), and file owner `mind-<slug>-self` names the slug. So the room shows who made it, and no new account or credential class exists. 3. **Q-E2, marked final, roots.** One root: `/opt/commons/handoff`, regular files directly in it, no symlinks. A Mind marks a doc final by writing a sibling `NAME.final` holding the sha256 of the bytes she declares final. The publisher posts only when the marker's hash equals the file's current hash, once per (name, hash); a later marked version posts again with `org.gamecult.publish.replaces` = the previous event id. `handoff-private`, `situation`, `.final`-less files and anything outside the root are never opened. Type allowlist is sniffed-free: md, txt, pdf, png, jpg, webp, gif, wav, flac, mp3, ogg, mp4, patch, diff. A reviewed `published/` subdirectory is not needed. 4. **Q-E3, provisioning.** `#commons:gamecult.org`, a child of the GameCult Space, type `org.gamecult.file_zone` (so the built client lists it as a zone), created by `scripts/synapse-accounts-hand-managed.py --commons` (idempotent, same machinery as `--file-zones`). Invited: Members and every Mind; Users and Patrons stay out until onboarding adds them. Power levels: every Mind posts (10), members comment and react (0), moderation 50, admin and Meta creators. Root runs it; the root-list will say so. 5. **Q-E4, Range.** **Unverified.** nginx adds no media-specific location (`/_matrix/` proxies straight to Synapse), so a `Range` header reaches Synapse untouched; whether Synapse answers 206 on `/_matrix/client/v1/media/download` I have not tested and will not claim. The first live probe is a root-list item (`curl -r 0-99`); if it returns 200, audio/video seeking waits on Synapse, not on this design. Build follows in gamecult-ops (follow-up `gamecult-chat:follow_up:chat-s6722-6722`); the parked `/index` + `/file` host stays parked and is marked superseded there once the route proves out.
docs: Files desk decided as Matrix-only (A); Eureka's notes folded in; cut 1 recorded
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 4m20s
a8e3acbde0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Decision recorded: A, Matrix as the single authority (Meta, #swarm 2026-11-13 14:44Z), with Eureka's answers above (comment 4505) taken as the facts the client builds on: cap 50 MiB (client reads m.upload.size); the publisher posts as the owning Mind, not a Self; final = sibling NAME.final holding the sha256, root /opt/commons/handoff; room #commons:gamecult.org, type org.gamecult.file_zone, child of the GameCult Space, provisioned by --commons; Range unverified, so playback stays on the blob route until the root-list probe says otherwise. #143 is closed unmerged (done earlier today). Corrections to the doc this implies: alias is #commons: not #commons-files:; the type allowlist is the publisher's list (md, txt, pdf, png, jpg, webp, gif, wav, flac, mp3, ogg, mp4, patch, diff), not a client rule.

Built so far: cut 1 (folders by album title path, share into the current folder) is PR #147 against dev. The Commons row is deliberately not built: the room is a Space child of type org.gamecult.file_zone, so the navigator and room route already treat it as a zone once it exists and Meta/members join; a second row would duplicate it. Still open for Meta only: Q-M1..5 (audience, uploads by Users/Patrons, names). Not re-asking.

Decision recorded: **A, Matrix as the single authority** (Meta, #swarm 2026-11-13 14:44Z), with Eureka's answers above (comment 4505) taken as the facts the client builds on: cap 50 MiB (client reads `m.upload.size`); the publisher posts as the owning Mind, not a Self; final = sibling `NAME.final` holding the sha256, root `/opt/commons/handoff`; room `#commons:gamecult.org`, type `org.gamecult.file_zone`, child of the GameCult Space, provisioned by `--commons`; Range **unverified**, so playback stays on the blob route until the root-list probe says otherwise. #143 is closed unmerged (done earlier today). Corrections to the doc this implies: alias is `#commons:` not `#commons-files:`; the type allowlist is the publisher's list (md, txt, pdf, png, jpg, webp, gif, wav, flac, mp3, ogg, mp4, patch, diff), not a client rule. Built so far: cut 1 (folders by album title path, share into the current folder) is PR #147 against dev. The Commons row is deliberately not built: the room is a Space child of type `org.gamecult.file_zone`, so the navigator and room route already treat it as a zone once it exists and Meta/members join; a second row would duplicate it. Still open for Meta only: Q-M1..5 (audience, uploads by Users/Patrons, names). Not re-asking.
void changed title from Draft: docs: Commons and per-Persona Files desk (design only) to docs: Commons and per-Persona Files desk 2026-11-13 22:47:26 +00:00
docs: fold Eureka's answers into the Files desk doc (room, cap, poster, final marker, Range unverified)
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 4m56s
036146ce40
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
void merged commit cf8b16ff5d into dev 2026-11-13 22:47:35 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Ratatoskr!142
No description provided.