docs: set the shared-state authority spine
This commit is contained in:
parent
f4683a6f1a
commit
9b54eb41eb
5 changed files with 224 additions and 0 deletions
|
|
@ -32,6 +32,13 @@ suspend, with receipts.
|
|||
the threat register), [`souveraine-components/`](souveraine-components/) (the
|
||||
authority binaries and their audit ladder).
|
||||
|
||||
**Shared state.** [`SHARED-STATE-ARCHITECTURE.md`](SHARED-STATE-ARCHITECTURE.md)
|
||||
is the design of record for household tasks, calendar, contacts, and their
|
||||
sync. Culver is a Personal-class client; Culver/machined owns identity and
|
||||
admission; the shared-state service owns the canonical event trail and local
|
||||
projection; QML only renders it. Loro is an offline merge substrate, never an
|
||||
authority.
|
||||
|
||||
**Designs of record.** [`STORAGE-ENCRYPTION.md`](STORAGE-ENCRYPTION.md),
|
||||
[`WAYDROID.md`](WAYDROID.md), [`../USB/README.md`](../USB/README.md),
|
||||
[`FEDERATION.md`](FEDERATION.md),
|
||||
|
|
|
|||
130
docs/SHARED-STATE-ARCHITECTURE.md
Normal file
130
docs/SHARED-STATE-ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
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.
|
||||
|
|
@ -292,6 +292,32 @@ So the deliverable is **`souveraine-fpd`**: a system daemon owning
|
|||
`gazed` does, and minting through `souveraine-stepup`. The `fp-*.py` tools are
|
||||
instruments, not the factor.
|
||||
|
||||
### Preview surface — built 2026-08-10, deliberately not a factor
|
||||
|
||||
The smaller `blueline-fingerprintd` producer now publishes its own FPC IRQ as
|
||||
a root-owned, world-readable pulse record at
|
||||
`/run/blueline-fingerprintd/preview-pulse`. The Souveraine touch lock watches
|
||||
that record and shows a configurable three-second hold exercise; the settings
|
||||
page labels it a wiring preview and it is off by default. The daemon is now
|
||||
`blueline-fingerprintd` package-owned as well as present in the provisioning
|
||||
overlay, so a normal `pacman -Syu` can update the live device path.
|
||||
|
||||
This proves only **FPC daemon → shell preview**. The pulse neither calls
|
||||
`unlocked()` nor mints a step-up grant, and the hold always says PIN remains
|
||||
required. The reader's `KEY_WAKEUP` stays mapped to panel wake only: the FTS
|
||||
touch driver emits the same generic key, so binding that key inside Hyprland
|
||||
would falsely call a touchscreen double-tap an FPC event. A real factor still
|
||||
needs `souveraine-fpd`'s verified match result and TASK-41's attested producer
|
||||
route.
|
||||
|
||||
**The intended real flow is PIN after boot, FPC after that.** The PIN performs
|
||||
the first unlock that makes Personal-class key material and the enrolled FPC
|
||||
template database available. A verified FPC match may then unlock a later
|
||||
screen lock or mint a narrow read/step-up grant, according to the requested
|
||||
operation; it never replaces first-boot storage unlock, household membership,
|
||||
or remote-device admission. A reboot returns the device to PIN-required. The
|
||||
raw IRQ and this preview do none of those things.
|
||||
|
||||
### Prior art, checked 2026-08-09
|
||||
|
||||
| | |
|
||||
|
|
|
|||
60
docs/tasks/68-shared-household-state.md
Normal file
60
docs/tasks/68-shared-household-state.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# TASK 68 — Shared household state: tasks first, authority intact
|
||||
|
||||
**Status:** planned 2026-08-10. **Size:** begin with one vertical slice.
|
||||
**Design:** [`../SHARED-STATE-ARCHITECTURE.md`](../SHARED-STATE-ARCHITECTURE.md).
|
||||
|
||||
## Goal
|
||||
|
||||
Build a shared Household space where distinct people can create and complete
|
||||
their own task participation without making the sidebar, Culver, or a CRDT the
|
||||
authority.
|
||||
|
||||
## First slice
|
||||
|
||||
1. A local service with an append-only admitted event trail and materialized
|
||||
task projection.
|
||||
2. Household membership with separate Casey and spouse identities.
|
||||
3. Tasks with title, notes, assignees, per-assignee status, due/reminder,
|
||||
subtasks, and links.
|
||||
4. One full QML application plus a sidebar projection asking what needs the
|
||||
current person now.
|
||||
5. No remote replication until the local data model and authority boundary are
|
||||
pleasant and inspectable.
|
||||
|
||||
## Non-negotiable boundaries
|
||||
|
||||
- Culver is the Personal-class contacts/messenger client, not household
|
||||
admission authority.
|
||||
- Culver/machined owns enrolment, membership, revocation, and scoped signing.
|
||||
- The service admits mutations; QML surfaces only project them.
|
||||
- Loro may merge admitted offline state. It never decides identity,
|
||||
membership, or permission.
|
||||
- Calendar is a first-class time object, not a task with a date.
|
||||
- CalDAV/CardDAV/JMAP are compatibility edges, never the authority model.
|
||||
- A local biometric factor may improve step-up once it verifies a real match;
|
||||
it does not admit a remote device or replace shared-space identity.
|
||||
|
||||
## Dependencies to make explicit, not hide
|
||||
|
||||
- `souveraine-machined` needs scoped, expiring capability tokens (component
|
||||
audit P1).
|
||||
- Per-agent/account caller identity is needed before a token can name a
|
||||
meaningful local producer or caller (P3).
|
||||
- `souveraine-secrets` must scope Personal-class release to caller and item
|
||||
(P2).
|
||||
- sessiond supplies live lock state, step-up, and key eviction; it is not the
|
||||
shared-state database.
|
||||
|
||||
## Acceptance
|
||||
|
||||
Casey and his wife can each see a Household task, mark only their own
|
||||
participation complete, and inspect who changed what. The sidebar and full app
|
||||
show the same materialized state. No widget writes another state store, and no
|
||||
offline peer becomes a member merely by merging data.
|
||||
|
||||
## Connects to
|
||||
|
||||
TASK-16 (Culver contacts as Personal-class data), TASK-23 (locked notification
|
||||
cadence), TASK-30 (enumerable surface verbs), TASK-41 (attested producers),
|
||||
`souveraine-components/audit-status.md`, and
|
||||
`SHARED-STATE-ARCHITECTURE.md`.
|
||||
|
|
@ -64,6 +64,7 @@ Four that are cheap relative to what they unblock:
|
|||
|
||||
| # | Task | What's left |
|
||||
|---|------|-------------|
|
||||
| 68 | [Shared household state: tasks first](68-shared-household-state.md) | Canonical plan landed 2026-08-10. First slice is an admitted local task trail + materialized QML app/sidebar view; Culver is the Personal-class client, not the authority. |
|
||||
| 67 | [The caching landed blind, and compaction drifted](67-caching-landed-blind-and-compaction-drift.md) | Prompt caching works — one turn shows `cache_write=22585` then `cache_read=22585` — and **nothing reads the counters**: `assistant_with_usage` has zero callers, so the only proof is a log line. Separately, the live config hands the subconscious `sliding_window` where the doc and the code default both say `sliding_reflect`, and the `memory` tool's enum exposes the blind strategy while hiding the safe one. §1 needs Casey's word, not a fix. |
|
||||
| 64 | [One SouveraineOS build for the iPhone](64-one-iphone-build.md) | Scoped 2026-08-10, not started. `linux-pauli` is not a repository, reaches the phone by `scp`, and CI has never built it. The display work that day is worth more than its code: the raster is **derived, not guessed** — 888×1845 @ 60 off `adp_mipi_regs` — and `aperture_remove_all_conflicting_devices()` is the correct handoff. ADP still shows nothing with everything else correct; the `adp16` kernel is staged and has never booted. |
|
||||
| 59 | [Her face on the glass: a Live2D presence](59-her-face-on-the-glass.md) | **Phase 1 passed on hardware 2026-08-05: ~58 fps, rig verified drawing (`painted_px` 23.6k/24k), 283 MB WebKit RSS.** Scoped from a Live2D board-girl found in a cloned blog. The reference streams its chat over **SSE terminated by `[DONE]`** — the contract souveraine's server already speaks, so the integration is accidentally done. Base layer is **wry**, not the Chromium already on the phone; the first deliverable is a measured frame rate for the Cubism runtime in WebKit on freedreno, and if that fails the task stops there. Replaces ani-avatar's 2.5 GB of sprite states with one rig. Reference rig ships as the working placeholder and gets edited toward Annie — it just stays out of any public repo. Summoned by app launch and/or the radial dial, not always-on. |
|
||||
|
|
|
|||
Loading…
Reference in a new issue