Skip to content

20260906 - Give the fleet one order, the same on every node - #84

Merged
Purple10101 merged 1 commit into
mainfrom
20260906-fleet-tab-order
Sep 6, 2026
Merged

Purple10101 merged 1 commit into
mainfrom
20260906-fleet-tab-order

Conversation

@Purple10101

Copy link
Copy Markdown
Collaborator

The problem

Every node draws its own banner, and peers() sorted with not is_self first, so each node put itself at the head of the row. Node A served A, B, C; node B served B, A, C. Users reported the tabs being in a different order depending on which node they happened to be on, and a tab moving under the cursor as they clicked through the fleet.

Three smaller sources of drift sat behind it:

  • The friendly name was the primary key, and it reaches other nodes in a TXT record up to BROWSE_RESTART_SECONDS (60s) late, so during a rename the nodes genuinely disagree about the value they are sorting on.
  • An unnamed node sorted ahead of every named one ("" beats any name), then jumped elsewhere the moment somebody named it.
  • discovered_nodes() prepended this node when mDNS had not found it yet, so the seconds after boot used a different order again.

The change

Sort on the node_id alone, via a shared mdns_peers.sort_key. It is derived from the board serial: unique, fixed for the life of the board, and known to every node the moment it has seen the peer at all.

The sequence that produces is arbitrary rather than meaningful, and that is the trade. An arbitrary order that never changes can be learned; a meaningful one that differs per node cannot. Which node you are looking at is answered by the active tab, not by position, so pinning self to the front bought nothing.

discovered_nodes() now sorts its self-injection into place rather than prepending it, so the pre-discovery window matches what every other node is showing.

The Summary cards share discovered_nodes(), so they follow along.

Verification

Full suite green (881 passed), ruff clean.

Tests: the old test_this_node_sorts_first_then_by_name asserted exactly the behaviour being removed, so it is replaced by three that pin down the new guarantee: order is by node_id wherever you are standing, a rename does not move a tab (the TXT-lag case), and an unnamed node does not jump to the front. test_this_node_is_not_duplicated_once_discovery_finds_it was incidentally order-dependent and now compares sets; a new sibling asserts self lands in sorted position rather than first.

Live tested on owl-ded9 (ret824685c9) against owl-debb (ret4c844c20). Before, ded9 served ret824685c9 | Rooftop North while debb served the reverse. After, both the banner and the Summary cards read Rooftop North | ret824685c9 on both nodes, with only the "this node" marker moving.

Worth knowing

  • The tab sequence will look arbitrary the first time you see it, since it is hex-derived. The labels are still the friendly names.
  • This is fleet-wide only once every node runs it. A node on the old code still pins itself first, so a mixed fleet keeps disagreeing until they are all updated.
  • Membership divergence is untouched and not addressable here: if node B cannot probe node D, D is missing from B's bar entirely. The stable key means the remaining tabs at least keep their relative positions.
  • If you later want literal "Node 1, Node 2" in an owner-chosen sequence, that is an order=N TXT record in owl-mdns-identity plus a GUI field, sorting on (order, node_id). It layers on top of this without regressing it.

🤖 Generated with Claude Code

Each node draws its own banner, and the sort put this node first, so an
operator got a different row of tabs on every box and a tab moved under the
cursor as they clicked through the fleet.

Sort on the node_id alone. Everything else available drifts: the friendly
name rides in a TXT record that can be a browse interval out of date, so
during a rename the nodes genuinely disagree about the value they are
sorting on, and an unnamed node sorts ahead of every named one until
somebody names it, then jumps. The sequence node_id gives is arbitrary
rather than meaningful, and that is the trade. An arbitrary order that
never changes can be learned; a meaningful one that differs per node
cannot. Which node you are looking at is answered by the active tab.

The banner's self-injection, for the seconds before discovery populates,
now sorts into place rather than prepending, so that window matches too.

Verified on owl-ded9 against owl-debb: banner and Summary cards both read
"Rooftop North | ret824685c9" on both nodes, with only the active marker
moving. A mixed fleet still disagrees until every node has this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Purple10101
Purple10101 merged commit f42ee86 into main Sep 6, 2026
3 checks passed
@Purple10101
Purple10101 deleted the 20260906-fleet-tab-order branch September 6, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant