Ownership and routing
Each stream is served by exactly one node at a time. Single ownership is what makes the rest of the design simple: offsets are assigned in one place, the tail caches are coherent because only the owner writes, and appends never coordinate across nodes. The work is then split into two problems, deciding who owns a stream and getting requests to that node.
Node identity
A node has a stable id and a fresh epoch for every process start, taken from the wall clock in milliseconds. On startup the node registers itself through the metadata log with its id, epoch, advertised HTTP address, and slot count. Registration at a lower epoch than the recorded one is rejected, so a replaced instance cannot re-register.
The epoch is also carried by every metadata command the node proposes. After a restart the new epoch invalidates everything the old instance had in flight, and the old instance, if it is still running somewhere, finds all of its proposals rejected. Two processes claiming the same node id resolve cleanly: the log orders their registrations and the later epoch wins.
Placement
A stream needs an owner the first time something has to be done to it. Placement is a metadata command like everything else, and applying it is deterministic: the stream goes to the registered node with the lowest ratio of assigned streams to slots. Slots are a capacity weight, 1 by default, so a node with 4 slots takes four times the streams of a node with 1. Slots can be changed at runtime through the admin API, which shifts where future placements land without moving anything already placed.
Because the choice is a pure function of the replicated state, every node computes the same answer. Two nodes racing to place the same stream propose two commands, the log orders them, and the second is a no-op.
Routing
Any node accepts any request. The receiving node resolves the name to a stream id and checks its local view, in order.
A name that is not registered yet is served locally, which is how creates land wherever the client happens to connect. A stream with a pending transfer routes to the transfer target, covered in Transfers. A stream that is opened, or placed but never opened, routes to its owning node, as a 307 redirect to the owner's advertised address. A closed stream is served locally, so any node can revive one whose previous owner is gone. The next open re-places it and routing converges on the new owner.
Why a stale view is safe
Routing reads the node's local view, which can lag the log by a moment. That is fine because routing is only a performance decision. Correctness comes from fencing: opening a stream bumps its epoch through the log, and a node that is not the current owner cannot commit anything to it. The worst a stale view produces is an extra redirect hop while the views catch up. It can misdirect a request, it cannot produce two writers.