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

5.6 KiB

description status date
Shared household state — authority, replication, and surfaces for tasks, calendar, and contacts Design of record 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.