Adds a GPU target picker to the header: Local, or one of the machines you
enrolled. Exactly one is active at a time; other connected workers are
standby and receive nothing.
The selection is the user's, not the scheduler's. The engine underneath can
rank many workers and the hosted platform will need that, but a desktop app
is better served by a choice you can predict and explain: "your worker is
offline, this ran locally" is a sentence, "least-busy ranking preferred the
laptop" is not. Picking an offline machine is allowed on purpose — you
choose your desktop, then go and switch it on.
`routing.decide()` is the single answer to "where does the next job run",
shared by the badge and (soon) the generation path, so the badge cannot
claim something the router will not do. It shows the RESOLVED answer rather
than the stored choice: pick your desktop, let it sleep, and the chip reads
Local with the reason, while the menu still shows your desktop selected.
Connection latency is now real. `latency_ms` existed but nothing measured
it — the protocol had Ping with no reply — so it was always zero. Adds Pong
(additive, field 12) and times the round trip on the control plane's
MONOTONIC clock, so an NTP step or a sleep/wake cannot produce a nonsense
reading, and no worker timestamp is trusted. Reported as a median of five
samples and withheld until a second sample exists: the first round trip
after connect lands while the worker is still importing torch, which
measured 139 ms on loopback and, averaged, carried that for a minute.
This is CONNECTION latency, not time-to-result. It is shown as information,
never as a routing input — RTT is milliseconds where inference is seconds,
so ranking on it would optimise noise.
Also fixes a bug the picker exposed: worker config was read from the pool,
which caches the row handed to it at connect time. Renaming a CONNECTED
worker updated the database and the API kept serving the old name until it
reconnected — same for priority and enable/disable. Config now comes from
the database and liveness from the pool, never the reverse, and writers
refresh the live copy so the scheduler's logs do not use a stale name.
Adds worker rename (the backend already supported it; no UI called it),
worker address as seen by the control plane rather than self-reported, and
ready/busy/offline status behind the header dot.
Send individual jobs to GPUs on your other machines while everything else
stays local. Opt-in, off by default: with the toggle off there is no
listening socket, no certificate and no background loop.
Design follows remote/goal_v2.md, the council-revised goal doc. The
decisions that shaped the code, and why:
* A disconnect is an unknown outcome, not a failure. The original design
reassigned on disconnect while also describing the case where the worker
had already finished — following both guarantees duplicate execution. An
attempt now holds a grace window; a worker returning inside it commits
its result and no second attempt is ever made.
* At-least-once execution, exactly-once result commit. The result is
persisted BEFORE it is acknowledged, so a crash between the two cannot
silently lose a finished render.
* Deadlines are phased (accept -> model load -> execute -> deliver) and
liveness is a progress lease. The old fixed 30s execution budget was two
orders of magnitude below what this product actually does; silence is
the failure signal, not slowness.
* Capacity is derived from free VRAM, never configured: a static value
corrupts output under torch.compile thread affinity (#315) and aborts
the process on small cards (#567).
* A circuit breaker replaces the reliability-score/quarantine machinery,
which had no recovery path (no probation workload exists in a TTS
product) and penalised consumer networks for existing.
* Identity is a keypair the worker generates and never sends. A
server-assigned id is a name, not an authenticator, so revocation of one
would be theatre. Enrollment tokens are single-use and carry the control
plane's certificate fingerprint for pin-on-first-use.
Adds the domain core, scheduler, durable task store, gRPC transport,
worker agent, management API, Settings panel, and docs. Protobuf reserves
the tenant/trace/usage fields a hosted control plane would need, since
adding them later means upgrading a whole fleet.
Includes tests for the failure paths that matter: duplicate delivery,
stale-session fencing, reconnect reconciliation, grace expiry, breaker
attribution, and a real end-to-end TLS round trip.