Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/SHARED-STATE-ARCHITECTURE.md

130 lines
5.6 KiB
Markdown

---
description: Shared household state — authority, replication, and surfaces for tasks, calendar, and contacts
status: Design of record
date: 2026-08-10
---
# Shared state — one authority, many surfaces
SouveraineOS needs a real shared-state system for household tasks, calendar,
contacts, and eventually mail-facing actions. It is not a CalDAV server with a
sidebar taped to it, and it is not a collection of app-local databases that
appear to agree until two people use them at once.
This document owns the cross-cutting shape. Component docs own their concrete
contracts; task files own session-sized implementation work. Where this and
code disagree, the code is right — reconcile one or the other in the same
change.
## The boundary
```
Culver + machined
identity, device enrolment, shared-space membership, revocation,
scoped signing authority
|
shared-state service
admitted event log, local materialized view, replication, audit
|
tasks | calendar | contacts | later: mail-facing actions
|
QML surfaces
sidebar, notification, dedicated application, phone view
```
One layer owns each question:
| Question | Owner | Not the owner |
| --- | --- | --- |
| Who is a person, device, or member of a household space? | Culver/machined | a task document, Loro, a DAV client |
| Which mutation is admissible? | shared-state service, against an enrolled identity and scoped capability | QML, a sync peer, the storage engine |
| What is the current task/calendar/contact view? | shared-state materializer | the sidebar or a cache in an application |
| How do offline changes converge? | Loro or another chosen CRDT substrate | identity/admission policy |
| May this device currently reveal Personal data? | sessiond + the storage/key policy | the application that wants the data |
## People are not devices
A household space has distinct people with distinct enrolled devices. Casey's
wife is not another Casey device and does not inherit his authority by sharing
a list. Membership grants an explicit role in a named space; revocation stops
new admitted events and key wrapping for the removed device.
Every accepted mutation records actor, device, capability, object, and time.
The trail must make it possible to answer who changed a task, not merely what
the current checkbox says.
## Data model
Tasks, calendar events, and contacts are different first-class objects.
- A task has shared definition fields and per-person participation. Completion
is not one shared boolean: an assignee has their own status, completion time,
and note. A household task can therefore remain open for Casey while showing
that another assignee is done.
- A calendar event owns time, recurrence, attendees, reminders, and
availability. It is not a task with a date bolted on.
- A contact is Personal-class identity data. Culver's existing contacts and
messenger UI remain a client of this architecture; they do not become the
cross-household authority by accident.
The first vertical slice is a Household space with tasks: title, notes,
assignees, per-assignee status, due/reminder, subtasks, and links. It must be
pleasant in one dedicated QML application and in the sidebar before calendar
or mail expands the scope.
## Authority and storage
The shared-state service accepts an event only after verifying the actor's
enrolment and operation-scoped capability. This is the same direction as the
component audit ladder:
- machined must mint scoped, expiring capability tokens rather than raw
signatures;
- callers need stable identity beyond uid 1000;
- secrets must release Personal-class material against a caller and scope;
- sessiond remains the live local authority for lock, step-up, and key
eviction.
Personal-class state is unavailable while the local session is locked.
Outbound actions — share, send, export, delete, or add a device — have their
own step-up policy. A successful local merge is never permission to export it.
## Replication
Loro is a candidate replication primitive because it can merge an offline tree
of task data deterministically. It does **not** decide who may submit a change,
enrol a device, or read the resulting state. Changes are encrypted for the
admitted nodes, replicated over an untrusted transport, verified locally, then
materialized into the canonical view.
CalDAV/CardDAV/JMAP are compatibility boundaries. They may import or export
data for other software; none defines the authority, audit trail, or household
membership model.
## Surface contract
QML surfaces subscribe to the service projection. They never store a competing
truth or mutate storage directly. The sidebar asks for the work that needs a
person now; the full application supplies planning and history. Notifications
are projections and obey the existing ambient/personal/step-up policy.
## Sequencing
1. Write the service contract and a session-sized Household-task task.
2. Build the local event trail, materialized task view, and QML sidebar/app
slice.
3. Add enrolled-device replication, using Loro only as the merge layer.
4. Add calendar on the same authority rail.
5. Add DAV/JMAP adapters as explicit compatibility edges.
This sequence does not wait for biometric matching. A fingerprint factor can
improve local step-up once real verification exists; it must not be mistaken
for shared-space admission or remote identity.
## Non-goals
- Replacing Culver's Matrix transport or contacts UI.
- Treating a shared checkbox as multi-person task state.
- Making the sidebar another database.
- Letting a CRDT or a DAV client grant itself authority.
- Shipping an unlabelled hold gesture as biometric authentication.