feat(base,learn): spaces people share, kept by halkyon_base

ADR 0044, step 2 (D1, D2, D11, D13, and D15 to D17, decided today).
halkyon_base keeps the spaces several people share, for every app:
shared_space, its members with their roles (Owner, Editor, Viewer), and
invitations by handle waiting for someone with no account on the
service yet. The sharedSpace endpoint creates a space, lists its
members, invites by handle, changes roles, removes members, hands the
space on, leaves and deletes it.

Who may do what:
- Only people with an identity reach the endpoint.
- A space the caller isn't in can't be told from one that doesn't
  exist.
- Members are named by their membership, never by their account's ID.
- Only the Owner manages the members, unless the space lets members
  invite.
- The Owner's role passes only by handing the space on, and the Owner
  leaves only naming who takes it on.
- An invitation counts as an answer about a handle, as it tells whether
  one exists.
Every rule has a test asserting the refusal.

The module stays free of the sync engine: a host hands it a SpaceGrants,
and every call runs in the module's transaction, so the engine's grants
follow the roles or nothing changes. The Owner and an Editor write; a
Viewer reads. Learn hands over SyncSpaceGrants on OfflineSyncSpaces. Todo
hands over none yet, so its server refuses until its projects are
shared.

Deleting an account hands each space the person owns to the Editor who
joined first, else the Viewer who joined first. A space with no other
member goes. This runs before the host's own deletions. A person's first
sign-in on a service makes their waiting invitations memberships, in the
same transaction that makes them a person there.

Migrations: the module's and every host's (Learn, Todo, Train, Meditate)
create the three tables, their indexes and the two cascading foreign
keys to shared_space, and nothing else. The old server keeps working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-11 10:33:12 +01:00
commit d08d8ad545
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -82,12 +82,29 @@ member reads everything in the space.
the same ID can't be inserted into another space; teaching the engine to move a row
was the other way, set aside as a deeper change to its merge, kept on every rebase.
- **D15.** **The module reaches the sync engine through its host** (decided 11 Nov 2026,
the agent's recommendation): each host hands halkyon_base a `SpaceGrants` (create a
space, grant, revoke, delete), made with `OfflineSyncSpaces`, as it hands a
`FileStore` (ADR 0043), so the module stays free of the engine and its tests run on a
stand-in.
- **D16.** **A shared space's tables are its service's own** (decided 11 Nov 2026, the
agent's recommendation): a Learn studyset's space and members are in Learn's
database, beside the engine's space they mirror, a Todo project's in Todo's; members
are the register's account IDs, their handles asked of the register as now.
- **D17.** **Never used the app means no account on its service yet** (decided 11 Nov
2026, the agent's recommendation, reading D13): someone without an `AuthUser` row on
the service gets a waiting invitation, made a membership the first time they sign in
there; on the register, where everyone has one, the invited are members at once.
## Steps
1. **Share with the community's confirmation** (D8, D9), needing nothing else here.
Built 11 Nov 2026.
2. **Shared spaces in halkyon_base** (D1, D2, D11, D13): the module's tables (a shared
space, its members and roles, its Owner), its endpoints with their denial tests,
the engine's grants kept in step, the hand-on as an account is deleted.
the engine's grants kept in step, the hand-on as an account is deleted. Built 11 Nov
2026: the module's `sharedSpace` endpoint, Learn's `SyncSpaceGrants`; Todo hands over
no engine yet, so its server refuses (`unavailable`) until its projects are shared.
3. **Keys** (D3): a private studyset's key wrapped to each member's key pair.
4. **Learn shares a studyset** (D14): the copy, *Manage collaborators* (invite by
@handle, the members, their roles, leaving), each member's own reviews.