Skip to content

Wraith coordinator roster is one node in production, so the election is vacuous #708

Description

@defenwycke

Measured on the live fleet, 2026-08-20. Not a code bug — a deployment fact that makes the decentralisation claim currently false in practice.

What is running

vm4 is serving a Wraith coordinator right now: ghost-pool is listening on 0.0.0.0:9100, and /api/v1/pool/coordinator reports

{"enabled":true,"epoch":6689,"seats":1,"my_seat":0,
 "elected":["9fe860bd…4d1b38"],
 "coordinators":[{"endpoint":"95.111.221.169:9100","seat":0,"node_id":"9fe860bd…4d1b38"}]}

One seat, and the sole candidate is vm4 itself.

Why the roster has one member

node coordinator_enabled coordinator_role_enabled wraith_election_enabled
vm1 false false false
vm2, vm3 (no [coordinator] keys → default false)
vm4 true true true
vm5–vm8 (no [coordinator] keys → default false)

Only opted-in nodes advertising a reachable endpoint enter the roster, and exactly one node has opted in. The draw is then trivial: with |roster| == 1, elect_coordinators can only return that node, every epoch, for ever. Rotation, fairness and no-self-nomination are all vacuous at this size — they are properties of a draw over a set, and the set has one element.

So the answer to "no single party is the operator" is, in production today, a single party. #697 was right about the conclusion and wrong about the cause: the code is wired (see the correction on that issue), the roster is empty except for one node.

This is not a bug to fix in code

Nothing here is malfunctioning. The gate is opt-in by design, and no operator has opted in besides vm4. What it means is that the sortition machinery cannot deliver its property until more nodes set coordinator_enabled = true and advertise an endpoint — and that any claim about decentralised coordination should say "one seat, one candidate" until they do.

Worth deciding:

  • Which nodes should opt in? vm5–vm8 run ghost-pool but not ghost-pay; check whether a coordinator seat needs the L2 services co-located before enabling them.
  • What is the minimum roster size below which the election should refuse to seat anyone, or at least report itself as degraded? Publishing seats: 1 as though it were an election invites the reader to assume a draw happened.
  • seats_for_demand sized this at 1. Confirm that is demand-driven and not a floor.

Related, found at the same time

The deployed election view carries no beacon, roster or per-seat rank — it predates fa8ed99c0, which publishes them and has wallets verify the draw. Until vm4 is redeployed, a wallet on that commit will refuse this election as unverifiable and fall back to a manually configured coordinator. That is the intended direction of failure, but it is a deploy-ordering note: nodes upgrade before wallets rely on verification.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions