# Twin declarations start beside the co-located host

Status: Accepted. Date: 2026-10-01. Card t_94bcd252, task t_6e9e0b5f.
Amends ADR 0011's ordering of later declarations after the co-located host.

A World that co-locates its twins in one host can still declare a twin as its own process. Dub's planetscale-mysql
is one: a MySQL frontend over the planetscale twin's state. The runtime started such a declaration only after the
host had published its receipt and every co-located port was admitted. So the frontend's whole process start and
readiness sat after the host on every boot.

A co-located twin's address is fixed when its port is allocated, before the host starts. The environment a later
declaration consumes, the twin's URL and its templates, is known then. A twin serves: it answers requests and calls
no other service while it starts. The planetscale frontend reads its upstream URL from that environment and fetches
it per query.

So the runtime records the host's twins and merges their environment as soon as the host is spawned. A later
declaration of type `twin` starts then, beside the host's startup. Any other declaration (an application process,
a control-plane service) first waits for the host to be ready, then for every earlier service, as before. `up` still
returns only after the host's receipt and port admission (ADR 0012, ADR 0014) and every declared service's own
readiness. A host failure still rolls back every service started so far, including a twin that started beside it.

Measured on Dub's World (32 services), native Node, published runtime 2.0.31 against this branch (with ADR 0014):
`up` took 2.31 and 2.63 s against 1.51, 1.46 and 1.54 s. In the browser tab, probe-instrumented, the time from host
admission to the World's env being published was 1.28–5.42 s before and 0.00 s after (the frontend was already
ready), in three runs each at load 25–50 (task-evidence/t_94bcd252/f3-diagnostic/final-run/c{0,1,2}-*).

## Boundary

The rule rests on a contract of the `twin` type: a twin declared outside the host may read a co-located twin's
address from its environment, but contacts it only to answer a request, never while it starts. The runtime does not
check this. A twin that breaks it finds its upstream's port closed while it starts. If that ends its process, `up`
fails, names the service and rolls back. If it retries until the host is ready, it only starts later. Nothing waits
silently on a twin that is not serving. A service that must reach a co-located twin while it starts is declared
`process`, with its own command (for a package twin, the package's bin), and starts after the host is ready.

Evidence boundary: the contract was checked for every twin declared outside a host that this work could find. Dub's
World has one, planetscale-mysql. Twin's own example Worlds have none. Planetscale's descriptor names it the twin's
`nativeTransport`, the one such frontend in the catalog. Its server listens without contacting its upstream, and it
fetches the upstream per query (read in `volter-ai/twin`'s planetscale package; the planetscale pack this
repository runs declares no native frontend). That other twin packages do not
call another service while they start is extrapolated from the twin role, not checked package by package.

