Components (L2)
1. Component map¶
AuthorityServerApi+AuthorityServerLink(posthaste-authority-server-link) — the seam's two traits (RFC D33): the typed request surface (reads, account/settings ops,apply) and the coherent-link mechanics (up/down channels, op lifecycle). One contract, two implementations. The crate carries only the authority-server-link surface; the shared wire vocabulary (MailOperation,MutationRequest/MutationReceipt, the ids) lives inposthaste-contract-core.LocalAuthorityServer(posthaste-authority-server/src/local_authority_server.rs) — the in-process implementation of both traits, delegating to the co-located far node.RemoteAuthorityServer(posthaste-runtime/src/transport.rs) — the over-HTTP implementation of both traits, held by the near node.AuthorityServerfar node (posthaste-authority-server/src/authority_server.rs) — the single owner of authority-server store access (theMailService+ store +mail_queries);LocalAuthorityServerdelegates to it.- Runtime registry (
posthaste-authority-server) — the far node's table of connected runtimes:AuthorityServerLinkId→ mutation-id pairing ((AuthorityServerLinkId, ClientMutationId)→RuntimeMutationId) + the settlement-routing sink for that runtime's down-stream. Mirrors the runtime's ownmutations_by_client_idone level down. Trivial (one entry, no identity) in-process. AuthorityServerLinkHandle(posthaste-authority-server-link) — the runtime's typed handle overArc<dyn AuthorityServerLink>.link_router(posthaste-authority-server/src/link_wire.rs) — the far-node HTTP/SSE surface serving the link wire; the far node owns the surface it serves (posthaste-serveronly mounts it).ReadCache(posthaste-runtime/src/read.rs) — the read-through cache, policy-parameterized.- The runtime near node (
posthaste-runtime) —AuthorityServerPendingSet(over aMessageReplica) +posthaste-replica-projector::MailListReplicafolded over served reads. The near node lives incrates/posthaste-runtime— the runtime's own crate, not the far node's — which also implements the client-facing surfaces split out ofRuntimeCore:posthaste-runtime-api(typed wire-free domain RPC) andposthaste-client-link(the client-link ops).
2. AuthorityServerLink implementations (LocalAuthorityServer, RemoteAuthorityServer)¶
LocalAuthorityServer calls the co-located AuthorityServer far node directly — zero serialization, synchronous confirmation; the behavior-preserving default. RemoteAuthorityServer is a real client: the up-channel POSTs the MutationRequest (the typed MailOperation), the down-channel opens an SSE stream and parses data: frames into AuthorityServerFrames (a pure parse_sse_frame mapper), and the read channel POSTs/GETs the read endpoints. The wire paths (LINK_FORWARD_MUTATION_PATH, LINK_SUBSCRIBE_PATH, the read paths) live in posthaste-authority-server-link so client and far node cannot drift.
There is no separate LinkTransport trait: the read channel lives on AuthorityServerApi and the up/down channels on AuthorityServerLink (ReadSource was folded in; RFC D33 split the fused trait), with LocalAuthorityServer/RemoteAuthorityServer implementing both. A transport override that affects only writes is a composing decorator over a read-capable base.
3. The link wire (link_router)¶
The authority server's link_router(transport) (posthaste-authority-server/src/link_wire.rs) is the far-node HTTP surface that serves the link endpoints (POST up-channel, SSE down-channel, read endpoints) over any AuthorityServerLink. A split-authority-server host mounts it over the authority server's in-process link (exposed on AuthorityServerBuild::authority_server_link). The real RemoteAuthorityServer client and the real link_router are proven to meet over loopback HTTP with no mock on either side (crates/posthaste-server/tests/authority_server_link_wire.rs). In a multi-runtime mount the link_router authenticates each runtime with a distinct credential, derives its AuthorityServerLinkId, and threads it into the far node's runtime registry so forward_mutation dedups by (AuthorityServerLinkId, ClientMutationId) and AuthorityServerFrame::Settlement routes onto that runtime's down-stream (runtime-credential-per-runtime, settlement-routed-to-origin-runtime).
4. The read-through cache (ReadCache)¶
ReadCache wraps an AuthorityServerLink read surface with a policy:
- Passthrough (co-located default) — every read delegates straight through; no storage, no copy, behavior-preserving.
- Retaining (remote) — a message-summary cache warmed by both point reads and query pages serves point reads (detail, undo-history) locally. Coherence is the down-channel: a background task evicts a message's entry on any base assertion, so a cached summary is never stale (the next read re-fetches) — not TTL. Mail-list pages are not cached (the authority owns membership/order; a list is a fresh read-through that warms the message cache).
5. The runtime near node (read replica + pending set)¶
The runtime holds an AuthorityServerPendingSet of forwarded-but-unconfirmed mutations and folds it over every mail-list recompute through posthaste-replica-projector::MailListReplica (apply_pending_set_overlay, crates/posthaste-runtime/src/near_node.rs): served rows are the base, the pending set folds over them, the projection is the optimistic result. The near node lives in the runtime's own crate, posthaste-runtime — the same crate that implements the posthaste-runtime-api + posthaste-client-link surfaces toward the client (the RuntimeCore split) — not in the far node's posthaste-authority-server. The runtime runs the same posthaste-replica-projector crate the WASM client runs, natively — one replica, two consumers (one-replica). A no-op short-circuit when the pending set is empty keeps the in-process default byte-for-byte unchanged.
6. Transport selection and config¶
AuthorityServerTransportConfig (InProcess default | Remote { base_url }) is threaded through RuntimeBuildConfig; select_authority_server_link builds the AuthorityServerLinkHandle over the config-chosen transport, not at build time (transport-selected-by-config). select_read_source picks the read path from the same config (Remote → read-through, InProcess → local). Switching a link to remote is a config change, not a rebuild.
7. The build seam and role binaries¶
build_authority_runtime is split so the authority-server far node and runtime near node compose independently (authority-server-builds-standalone):
build_authority_server(config) -> BackendBuild— the far node alone, without the runtime.build_runtime(BackendBuild | remote link, config) -> RuntimeHandle— the runtime over an authority-server link.
The lean role binaries compose these (separate-role-binaries): posthaste-authority-server (far node + link_router, no renderer), posthaste-runtime (runtime over a remote authority-server link), posthaste-authority-runtime-server (authority server + runtime in-process, one HTTP server). The bundled control app composes the all-in-one server + renderer. The first dogfoodable split (authority server on one host, runtime on another) is proven.
8. Assertions¶
| ID | Sev. | Assertion |
|---|---|---|
| one-authority-server-link | MUST | The seam is exactly two traits — AuthorityServerApi (typed request surface, incl. the read channel) and AuthorityServerLink (up/down link mechanics) — both implemented by LocalAuthorityServer/RemoteAuthorityServer; there is no separate transport or read-source trait. |
| one-replica | MUST | Both near nodes hold a read-model replica from one implementation — posthaste-replica-projector over posthaste-replica-core — run natively (runtime) or as WASM (browser client); the runtime does not hand-write a second replica. |
| link-wire-shared-paths | MUST | The remote wire paths live in posthaste-authority-server-link so the RemoteAuthorityServer client and the link_router far node cannot drift; they are proven to meet over loopback HTTP with no mock. |
| authority-server-builds-standalone | MUST | build_authority_server produces the far node without the runtime; build_runtime consumes an authority-server link (local or remote); the two compose independently. |
| separate-role-binaries | MUST | Each deployment role (authority server, runtime, all-in-one server) is a thin binary composing only the libraries it needs; a headless install carries no renderer/Tauri/webview code. |
| authority-server-runtime-registry | MUST | The authority-server far node maintains a registry of connected runtimes (AuthorityServerLinkId → mutation-id pairing + settlement sink); forward_mutation dedups by (AuthorityServerLinkId, ClientMutationId) and AuthorityServerFrame::Settlement routes to the originating runtime's down-stream. In-process the registry is a single trivial entry. |