A seat is handed over as one act, and the holder is on record #91

Merged
jschoubben merged 1 commits from feat/seat-handover into main 2026-09-27 21:22:50 +00:00
Owner

Design 28 task 5.3, under hq ADR 0131. Pairs with hq#153 (design 26).

seat <name> --to <node>/<module> makes one assignment the holder of a seat in the same write that replaces the previous one. The row is new (migration 0039). Without a row the resolver derives the holder exactly as before — the sole eligible assignment holds, two are refused — so a mesh that has never handed a seat over is unchanged. With a row, the recorded assignment holds and any other whose module could hold the seat is eligible and silent: neither refused nor holding. That is what lets the next holder run beside the current one until the switch.

Why it exists: the controller finds its own bus through a seat, and tonight that seat was left with nobody in it — two eligible holders could not coexist, and the old one's claim was removed — so the control plane looped for two hours while every service stayed up. A handover that is never empty in between is the fix.

CanHold is now the single judgement of whether a module may hold a seat, shared by registration and the handover and read against the store's row, so the two cannot drift. A holding belongs to its assignment and is removed with it.

Tests: resolver with and without a record, same machine, other machine, former seat name; the store row replaced not added, refused for an unassigned target, gone with its assignment; CanHold's four answers following the store. Full suite green on a real NATS and store.

Design 28 task 5.3, under hq ADR 0131. Pairs with hq#153 (design 26). `seat <name> --to <node>/<module>` makes one assignment the holder of a seat in the same write that replaces the previous one. The row is new (migration 0039). Without a row the resolver derives the holder exactly as before — the sole eligible assignment holds, two are refused — so a mesh that has never handed a seat over is unchanged. With a row, the recorded assignment holds and any other whose module could hold the seat is **eligible and silent**: neither refused nor holding. That is what lets the next holder run beside the current one until the switch. Why it exists: the controller finds its own bus through a seat, and tonight that seat was left with nobody in it — two eligible holders could not coexist, and the old one's claim was removed — so the control plane looped for two hours while every service stayed up. A handover that is never empty in between is the fix. `CanHold` is now the single judgement of whether a module may hold a seat, shared by registration and the handover and read against the store's row, so the two cannot drift. A holding belongs to its assignment and is removed with it. Tests: resolver with and without a record, same machine, other machine, former seat name; the store row replaced not added, refused for an unassigned target, gone with its assignment; `CanHold`'s four answers following the store. Full suite green on a real NATS and store.
jschoubben added 1 commit 2026-09-27 21:22:39 +00:00
`seat <name> --to <node>/<module>` makes one assignment the holder of a seat in
the same write that removes the previous one. The row is new (migration 0039);
without one, the resolver derives the holder as it always did — the sole eligible
assignment, two refused — so nothing changes for a mesh that never hands a seat
over. With one, the recorded assignment holds and any other whose module could
hold the seat is eligible and silent: not refused, not holding. That is what lets
the next holder run beside the current one until the switch (hq design 26, design
28 task 5.3, ADR 0131).

Why: the controller finds its own bus through a seat, and the day that seat was
left with nobody in it — because two eligible holders could not coexist and the
old one's claim was taken away — the control plane looped for two hours while
every service stayed up. A handover that is never empty in between is the fix,
not a workaround for it.

`CanHold` is the one judgement of whether a module may hold a seat — claims it at
its scope, provides what it delivers, against the store's row — shared by
registration and the handover so they cannot drift apart. The holding belongs to
the assignment and goes when it does, so a seat never points at nothing running.

Tests: the resolver with and without a record, on the same and another machine,
under a former name; the store's row replaced not added, refused for an
unassigned target, removed with its assignment; CanHold's four answers and that
they follow the store. Full suite green against a real NATS and store.
jschoubben merged commit 33c4e4be34 into main 2026-09-27 21:22:50 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-controller#91