ADR 0044 records the answers to its open questions: a shared studyset passes on when its owner leaves or deletes their account (D11); an agent's token lapses after 90 days unused (D12); an invitation by handle waits for someone who never used the app (D13); and sharing copies the studyset under new IDs into the shared space (D14), since the sync engine's delete is soft and a row's ID can't be inserted into another space. Its Steps section orders the work, starting with the community's confirmation (D8, D9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
107 lines
6.9 KiB
Markdown
107 lines
6.9 KiB
Markdown
# ADR 0044: Shared spaces and collaboration, people and agents alike
|
|
|
|
- **Status:** decided 10 Nov 2026 by the developer: D8 is their own request, D9 and D10
|
|
their choices over the agent's recommendations (all ticked at first; agents editing
|
|
directly), D1 to D7 the agent's recommendations, which they chose; D11 to D13 the
|
|
agent's recommendations, which they chose on 11 Nov 2026, D14 too. Not built yet;
|
|
the steps below.
|
|
- **Builds on:** ADR 0005 (publishing, reports and suggestions), ADR 0014 (the module),
|
|
ADR 0016 (one account across an instance), ADR 0017 (key pairs), ADR 0019 (private
|
|
studysets), ADR 0021 (operators and assistants).
|
|
|
|
## Context
|
|
|
|
A studyset belongs to one person: their rows are in their personal space, a private
|
|
one sealed with a data key that only their own devices unwrap. The developer asked (10
|
|
Nov 2026) for Vaia's sharing (*Manage collaborators*: invite by email, an invite link,
|
|
the members and their roles; *Collaboration settings*: joining by link, collaborators
|
|
inviting others; *Share with the community*: choosing what material goes public) and
|
|
for collaboration with everyone, people and agents alike: *invite @Paul or @Claude to a
|
|
studyset*, Claude Code on halkyon.li's host working as an agent account, as Copilot or
|
|
Claude work on a GitHub repository.
|
|
|
|
The sync engine already has shared spaces (`OfflineSyncSpaces`: create, grant, revoke,
|
|
members), with two roles, `readOnly` and `readWrite`, which limit writes alone: a
|
|
member reads everything in the space.
|
|
|
|
## Decisions
|
|
|
|
- **D1.** **Shared spaces live in halkyon_base,** for every app: members, roles,
|
|
invitations, links, settings and the wrapped keys. Learn's studysets use them first,
|
|
Todo's projects later on the same tables.
|
|
- **D2.** **Roles: Owner, Editor, Viewer.** The Owner can do everything, delete the
|
|
studyset and hand it to another member; an Editor changes content; a Viewer reads and
|
|
studies, with their own reviews in their own space. Editor and Owner are the engine's
|
|
`readWrite`, a Viewer its `readOnly`; who is Owner is the module's own table, checked
|
|
by its endpoints.
|
|
- **D3.** **A private studyset's key is wrapped to each member's public key** (ADR
|
|
0017's key pairs) by a member's device that holds it, at its next sync after someone
|
|
joined. The instance never sees the key; reading waits for that sync. A member
|
|
removed gets no new content: the studyset rolls to a new key, as ADR 0019's rewrites.
|
|
- **D4.** **Invites by @handle or by email.** An @handle adds a person on the instance at
|
|
once (they see it in their Inbox and may leave). An email address gets a mail with a
|
|
link to join, which works after signing up; the address is never shown to the other
|
|
members.
|
|
- **D5.** **Joining by link is off at first;** someone joining by it is a Viewer, whom
|
|
the Owner can raise. *Collaborators may invite others* is off at first too.
|
|
- **D6.** **Agents are accounts of their own,** marked as agents, each owned by a person
|
|
who made it from their Profile; listed in the owner's Profile, deleted with them. An
|
|
agent has its own key pair, kept where it runs, signs in with a token the owner made
|
|
(never a password), and is invited like a person: *@claude*.
|
|
- **D7.** **An agent reaches the instance through a small CLI or MCP server** run beside
|
|
it (Claude Code on halkyon.li's host runs as its own user, without Docker): it signs
|
|
in with its token, syncs the spaces it is a member of, opens the sealed rows with its
|
|
own keys, and writes through the same endpoints an app uses.
|
|
- **D8.** **Share with the community** (publishing to Explore, ADR 0005) gets a step
|
|
confirming the material: every PDF, other file and note listed by kind.
|
|
- **D9.** That step's choice: **all unticked at first**, with per kind *tick all*, and
|
|
on any item *everything but this* and *nothing but this*. Cards and the learning path
|
|
always go.
|
|
- **D10.** **An agent suggests; a person accepts.** An agent is a Viewer in the engine's
|
|
sense and writes nothing into the studyset; its changes go as suggestions, which a
|
|
member with Editor's rights accepts or declines, each marked as by @claude. Learn's
|
|
reports and suggestions (ADR 0005, stage 4: `feedback_thread`, the author's
|
|
decisions, accepted suggestions applied by their item) are the start: they become
|
|
suggestions within a shared space too, not only on published releases.
|
|
|
|
- **D11.** **A shared studyset passes on.** Leaving, the Owner picks the next Owner
|
|
first. Deleting their account, ownership passes by itself to the Editor who joined
|
|
first, else to the Viewer who joined first; only with no other member does the
|
|
studyset go with them.
|
|
- **D12.** **An agent's token lapses after 90 days unused;** while used it has no fixed
|
|
end, the owner revokes it any time, and their Profile shows when it was last used.
|
|
- **D13.** **An invitation by @handle waits** for someone who has an account on the
|
|
instance's register but has never used the app: they find it in their Inbox the first
|
|
time they sign in to it, and the inviter sees them as invited until then.
|
|
|
|
- **D14.** **Sharing copies the studyset under new IDs** into the shared space, rewrites
|
|
what names its rows (reviews, tags, the learning path, files) and deletes the old ones,
|
|
as ADR 0019's rewrites do; the fork stays as it is. Found 11 Nov 2026: the engine's
|
|
delete is soft (`insteadOfDelete`: the domain row stays, hidden by a tombstone in its
|
|
space's `crdt_data_rows`), and a synced table's primary key is the row's ID alone, so
|
|
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.
|
|
|
|
## Steps
|
|
|
|
1. **Share with the community's confirmation** (D8, D9), needing nothing else here.
|
|
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.
|
|
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.
|
|
5. **Invitations by email and by link** (D4, D5), the Inbox.
|
|
6. **Agents** (D6, D7, D10, D12).
|
|
|
|
## Open questions, before building
|
|
|
|
- **Moving rows between spaces.** Decided: D14.
|
|
- **Whose reviews.** A Viewer's or Editor's schedule for a shared card stays in their own
|
|
space, keyed by the card's ID; the card's own review rows today assume one learner.
|
|
- **Handing on and leaving.** Decided: D11. To build: the account's deletion hands the
|
|
shared spaces it owns on before it deletes the person's own.
|
|
- **Members across services.** Decided: D13. A member of a Learn studyset needs no Todo
|
|
account, and the reverse.
|
|
- **The agent's token:** made and revoked in the owner's Profile, scoped to the agent's
|
|
account, never shown again after making; its lapse decided: D12.
|