Record what may be shared, ahead of federation

The bot-side half of TODO #4. Nothing federates yet; this establishes
what would be eligible to, and proves the boundary before there is a
hub that could leak across it.

- Schema v5 adds visibility, defaulting to private. Upgrading an
  existing library therefore opts nothing into sharing, which a test
  on the legacy upgrade path pins down.
- list_syncable() is the only function that will ever feed a hub, and
  it requires both public and approved. Tests force rows into states
  set_visibility refuses, so the filter is what protects the boundary
  rather than the caller being careful.
- set_visibility refuses anything not approved: media still in the
  moderation queue cannot be marked shared.
- /share lists memes with their current state and asks before making
  one public, since un-sharing stops future copies but cannot recall
  those already taken. The wording describes what sharing will mean
  once a hub exists, because by then warning is too late.
- /list shows the same markers.

Vault posts have no path into the sync set at all; being in a separate
table is what guarantees it, and there is a test saying so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
goyban
2026-09-01 22:09:37 +00:00
parent a35abb0541
commit 0732f2c34b
7 changed files with 272 additions and 7 deletions
+14 -2
View File
@@ -8,9 +8,9 @@ Progress on branch `develop` (not pushed):
- [x] **#3** moderation queue — `0a8c81d`
- [x] **#2** public mode + membership gate — `82b5da4`
- [x] **#5** save vs. extract (vault) — forward-based
- [ ] **#4** federation
- [~] **#4** federation — bot-side visibility done; hub, channel and sync client outstanding
Test suites: `test_db.py`, `test_bot.py`, `test_access.py`, `test_vault.py` — 29 cases, all passing.
Test suites: `test_db.py`, `test_bot.py`, `test_access.py`, `test_vault.py` — 34 cases, all passing.
---
@@ -166,6 +166,18 @@ Split media transport from metadata sync:
- Rate-limit per instance. A compromised peer token should be able to spam, at worst, its own rows.
- Practical note: a federated pool of user-submitted media needs a takedown path for illegal content, and as the hub operator that lands on you. Worth deciding the policy before launching, not after.
### Status
Done in this repo: the `visibility` column (private by default), `/share` to
change it, and `list_syncable()` — the single function that defines what is
ever allowed to leave this instance. It is guarded by tests that force rows
into states the writer would refuse, so the filter is proven rather than
assumed. Nothing calls it yet.
Outstanding, and all of it depends on decisions only the owner can make:
the federation channel, the hub deployment, the instance tokens, and the sync
client that pushes to and pulls from the hub.
### Open question
The hub is a separate deployable (small FastAPI + SQLite would do). Do you want it in this repo as `hub/`, or as its own repository? It has a different release cadence and a different threat model, which argues for separate.