okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
1ac72d8
main
HTTP API architecture
OpenAPI defines wire shapes. HTTP API design defines ordering, retry, recovery, and resource behavior. This document explains the owners and persistence boundaries behind those operations.
State ownership
Session actors, the store transaction connection, the family owner, the settings lock, and the bounded bus own the state below. HTTP handlers call these owners and project their results.
session/creation owns new, fork, and child intents, their canonical submitted
JSON, and rejection policy. http_api parses requests into that type. The
registry resolves defaults and coordinates creation; conversation and
operations persist the submitted intent and the resulting decision. Dependency
failures stay retryable; validation refusals retain their original fingerprint
and rejection.
The runtime owns a generic store.Store handle named ledger. Extensions such
as work initialise and consume their own tables through that handle. Kernel APIs
accept the same generic store and receive their plugin wiring from callers.
| State | Owner and commit boundary | Recovery and removal |
|---|---|---|
| Creation intent and decision | conversation and operations, on the shared store transaction connection. Persist the submitted descriptor separately from resolved defaults and editable configuration. | Keep provenance while the session exists. Keep rejected decisions and deletion tombstones for the contract's seven-day window. A lost response is recovered by the same session URI and original ID. |
| Child creation and initial task | Family owner serializes membership validation. One store transaction commits session, relationship, creation decision, and identified task. | A failed commit leaves none of them. Deletion admission prevents a racing child from escaping captured membership. |
| Input admission | operations commits the immutable decision and pending input together. Check a known ID before mutable validation. | Accepted pending input survives restart. Queue-full rejection stays rejected on retry. Unknown expired IDs cannot execute. |
| Input consumption and turn outcome | Session actor orders execution. Store owner commits transcript rows, images, input delivery, turn membership, and pending removal together. | Failed consumption leaves input pending. An unfinished previous run becomes abandoned after restart. Start seven-day receipt retention only when both delivery and the associated turn are terminal. |
| Configuration and workspace intent | Session actor validates its configuration revision and idleness. Family owner captures descendant membership; store owner commits desired workspace and deferred descendant intentions. | Persist desired revision before kernel work. A late completion cannot restore an older workspace. Report failed application separately from committed desired state. |
| Visits and deletion | Store owner commits visit identity with the counter, and deletion outcomes with pending cancellations and tombstones. Family owner serializes captured subtree changes. | Repeated visits do not increment again. Partial deletion reports the actual captured remainder. Never automatically repeat subtree deletion after transport loss. |
| Session watch | Session actor captures live state, replay position, and durable high-water mark together. Generation belongs only to that actor lifetime. | Reset reads history through the captured high-water mark. Advance the client's cursor pair after delivery succeeds. Actor replacement cannot authorize old numeric replay. |
| Collection watch | Existing bus admits bounded notifications before subscriber mailboxes and coalesces wakes. | Overflow and closure require resubscription followed by authoritative refresh. Disconnect removes subscription state. No duplicate full-event mailbox queue. |
| Settings and credentials | Existing settings owner constructs the candidate under the per-home lock. MCP connection probes run outside the lock; publication rechecks the group validator and private candidate inputs. | Use the crash recovery procedure below. Runtime application is distinct from persistence. Secrets remain write-only. |
| Provider login | OAuth owner owns the bounded live listener/exchange. It owns durable admission and terminal records through the supplied store transaction connection. | Persist admission before opening a listener. Restart marks unfinished records failed. Preserve terminal decisions for 15 minutes; a duplicate ID cannot start another exchange. |
| Prepared context | Existing runtime owner publishes one immutable latest prepared snapshot. | Paging pins its ID; replacement returns 410 context_changed. Reading context never prepares a request. |
| Extension ledgers | Each extension owns its tables, migrations, validation, permissions, and handlers. | Commit domain changes before best-effort notifications. Notification failure cannot undo committed work. |
Composition discovery runs outside the runtime actor in bounded preparation workers. Admission reserves capacity for both observations and preparation, so slow kernel starts cannot occupy every read slot.
Settings crash recovery
Provider and MCP changes publish public settings and creds.json atomically.
The settings owner uses the per-home lock and a private recovery record for a pending group replacement:
- Recover any prior replacement before reading or changing settings. All credential writers, refreshes, and readers that can observe these files participate in this boundary.
- Read the current group, check
If-Match, and construct the complete candidate while retaining unrelated sections. Resolve conflicting secret sources and validate the candidate before changing authoritative files. - Write the complete replacement documents into private temporary files.
Set mode
0600before writing secrets. Sync the files. - Publish a private recovery record containing the complete replacement documents and their allowed destination names. Sync the record and its directory. Publication is the durable commit decision. Before this point, failure leaves the old group authoritative.
- Replace the affected files and sync their directory. After the commit decision, recovery completes those replacements; it does not undo them. Recovery can regenerate a consumed temporary file from the record, so a crash after the first rename does not lose the remaining replacement data.
- Remove the recovery record and temporary files only after replacement is durable. Then expose the new group and validator to readers.
Crash before the commit decision keeps the old group. Crash after it completes the new group on restart. An inability to finish recovery fails startup or the settings operation with an actionable storage error; it cannot expose a mixed snapshot. Keep old runtime composition usable until candidate application succeeds. A post-commit application failure reports the persisted desired state and failed application, without claiming persistence rolled back.
Scope this mechanism to the existing settings owner. Do not create a generic file transaction library. Bound each replacement by its existing file limit and the recovery record by the sum of those limits plus bounded metadata. Reject a recovery record with foreign paths, invalid contents, missing replacement data, or unsafe permissions. Never log its secret contents. Exercise real crash points before and after the commit decision.
Durable facts
Creation provenance, turn-terminal retention, workspace intent, and login admission are durable. Their owners migrate their records before actors start. Migration failures stop startup before admitting work.
For a session created before provenance was stored, expose unavailable
provenance explicitly. Do not infer its original request from its current name,
workspace, or model. Existing history, forks, and attachments remain usable.
Such a session returns creation: null in the single target schema and cannot
prove a matching identified creation.
Login intent comparison includes private form values. Use a keyed fingerprint with a protected, persistent daemon-owned key rather than a publicly readable hash of a low-entropy password. Do not persist callback codes or access tokens in admission records. The OAuth owner removes fingerprint metadata when the record expires; the credentials owner continues to own resulting accounts.
1# HTTP API architecture 2 3[OpenAPI](openapi.yaml) defines wire shapes. [HTTP API design](http-api-design.md) 4defines ordering, retry, recovery, and resource behavior. This document explains 5the owners and persistence boundaries behind those operations. 6 7## State ownership 8 9Session actors, the store transaction connection, the family owner, the 10settings lock, and the bounded bus own the state below. HTTP handlers call 11these owners and project their results. 12 13`session/creation` owns new, fork, and child intents, their canonical submitted 14JSON, and rejection policy. `http_api` parses requests into that type. The 15registry resolves defaults and coordinates creation; `conversation` and 16`operations` persist the submitted intent and the resulting decision. Dependency 17failures stay retryable; validation refusals retain their original fingerprint 18and rejection. 19 20The runtime owns a generic `store.Store` handle named `ledger`. Extensions such 21as work initialise and consume their own tables through that handle. Kernel APIs 22accept the same generic store and receive their plugin wiring from callers. 23 24| State | Owner and commit boundary | Recovery and removal | 25| --- | --- | --- | 26| Creation intent and decision | `conversation` and `operations`, on the shared store transaction connection. Persist the submitted descriptor separately from resolved defaults and editable configuration. | Keep provenance while the session exists. Keep rejected decisions and deletion tombstones for the contract's seven-day window. A lost response is recovered by the same session URI and original ID. | 27| Child creation and initial task | Family owner serializes membership validation. One store transaction commits session, relationship, creation decision, and identified task. | A failed commit leaves none of them. Deletion admission prevents a racing child from escaping captured membership. | 28| Input admission | `operations` commits the immutable decision and pending input together. Check a known ID before mutable validation. | Accepted pending input survives restart. Queue-full rejection stays rejected on retry. Unknown expired IDs cannot execute. | 29| Input consumption and turn outcome | Session actor orders execution. Store owner commits transcript rows, images, input delivery, turn membership, and pending removal together. | Failed consumption leaves input pending. An unfinished previous run becomes abandoned after restart. Start seven-day receipt retention only when both delivery and the associated turn are terminal. | 30| Configuration and workspace intent | Session actor validates its configuration revision and idleness. Family owner captures descendant membership; store owner commits desired workspace and deferred descendant intentions. | Persist desired revision before kernel work. A late completion cannot restore an older workspace. Report failed application separately from committed desired state. | 31| Visits and deletion | Store owner commits visit identity with the counter, and deletion outcomes with pending cancellations and tombstones. Family owner serializes captured subtree changes. | Repeated visits do not increment again. Partial deletion reports the actual captured remainder. Never automatically repeat subtree deletion after transport loss. | 32| Session watch | Session actor captures live state, replay position, and durable high-water mark together. Generation belongs only to that actor lifetime. | Reset reads history through the captured high-water mark. Advance the client's cursor pair after delivery succeeds. Actor replacement cannot authorize old numeric replay. | 33| Collection watch | Existing bus admits bounded notifications before subscriber mailboxes and coalesces wakes. | Overflow and closure require resubscription followed by authoritative refresh. Disconnect removes subscription state. No duplicate full-event mailbox queue. | 34| Settings and credentials | Existing settings owner constructs the candidate under the per-home lock. MCP connection probes run outside the lock; publication rechecks the group validator and private candidate inputs. | Use the crash recovery procedure below. Runtime application is distinct from persistence. Secrets remain write-only. | 35| Provider login | OAuth owner owns the bounded live listener/exchange. It owns durable admission and terminal records through the supplied store transaction connection. | Persist admission before opening a listener. Restart marks unfinished records failed. Preserve terminal decisions for 15 minutes; a duplicate ID cannot start another exchange. | 36| Prepared context | Existing runtime owner publishes one immutable latest prepared snapshot. | Paging pins its ID; replacement returns `410 context_changed`. Reading context never prepares a request. | 37| Extension ledgers | Each extension owns its tables, migrations, validation, permissions, and handlers. | Commit domain changes before best-effort notifications. Notification failure cannot undo committed work. | 38 39Composition discovery runs outside the runtime actor in bounded preparation 40workers. Admission reserves capacity for both observations and preparation, so 41slow kernel starts cannot occupy every read slot. 42 43### Settings crash recovery 44 45Provider and MCP changes publish public settings and `creds.json` atomically. 46 47The settings owner uses the per-home lock and a private recovery record for 48a pending group replacement: 49 501. Recover any prior replacement before reading or changing settings. All 51credential writers, refreshes, and readers that can observe these files 52 participate in this boundary. 53 2. Read the current group, check `If-Match`, and construct the complete candidate 54while retaining unrelated sections. Resolve conflicting secret sources and 55 validate the candidate before changing authoritative files. 56 3. Write the complete replacement documents into private temporary files. 57Set mode `0600` before writing secrets. Sync the files. 58 4. Publish a private recovery record containing the complete replacement 59documents and their allowed destination names. Sync the record and its 60 directory. Publication is the durable commit decision. 61 Before this point, failure leaves the old group authoritative. 62 5. Replace the affected files and sync their directory. After the commit 63decision, recovery completes those replacements; it does not undo them. 64 Recovery can regenerate a consumed temporary file from the record, so a 65 crash after the first rename does not lose the remaining replacement data. 66 6. Remove the recovery record and temporary files only after replacement is 67durable. Then expose the new group and validator to readers. 68 69 Crash before the commit decision keeps the old group. Crash after it completes 70the new group on restart. An inability to finish recovery fails startup or the 71settings operation with an actionable storage error; it cannot expose a mixed 72snapshot. Keep old runtime composition usable until candidate application 73succeeds. A post-commit application failure reports the persisted desired state 74and failed application, without claiming persistence rolled back. 75 76Scope this mechanism to the existing settings owner. Do not create a generic 77file transaction library. Bound each replacement by its existing file limit 78and the recovery record by the sum of those limits plus bounded metadata. 79Reject a recovery record with foreign paths, invalid contents, missing 80replacement data, or unsafe permissions. Never log its secret 81contents. Exercise real crash points before and after the commit decision. 82 83### Durable facts 84 85Creation provenance, turn-terminal retention, workspace intent, and login 86admission are durable. Their owners migrate their records before actors start. 87Migration failures stop startup before admitting work. 88 89For a session created before provenance was stored, expose unavailable 90provenance explicitly. Do not infer its original request from its current name, 91workspace, or model. Existing history, forks, and attachments remain usable. 92Such a session returns `creation: null` in the single target schema and cannot 93prove a matching identified creation. 94 95Login intent comparison includes private form values. Use a keyed fingerprint 96with a protected, persistent daemon-owned key rather than a publicly readable 97hash of a low-entropy password. Do not persist callback codes or access tokens 98in admission records. The OAuth owner removes fingerprint metadata when the 99record expires; the credentials owner continues to own resulting accounts.