Skip to content

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 in posthaste-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.
  • AuthorityServer far node (posthaste-authority-server/src/authority_server.rs) — the single owner of authority-server store access (the MailService + store + mail_queries); LocalAuthorityServer delegates 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 own mutations_by_client_id one level down. Trivial (one entry, no identity) in-process.
  • AuthorityServerLinkHandle (posthaste-authority-server-link) — the runtime's typed handle over Arc<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-server only mounts it).
  • ReadCache (posthaste-runtime/src/read.rs) — the read-through cache, policy-parameterized.
  • The runtime near node (posthaste-runtime) — AuthorityServerPendingSet (over a MessageReplica) + posthaste-replica-projector::MailListReplica folded over served reads. The near node lives in crates/posthaste-runtime — the runtime's own crate, not the far node's — which also implements the client-facing surfaces split out of RuntimeCore: posthaste-runtime-api (typed wire-free domain RPC) and posthaste-client-link (the client-link ops).

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.

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.