Pixieby Sociofabric

Mechanism: The Driver's Seat

An election with no election service, decided by a two-byte payload riding a message your devices already send each other. The interesting move is not the vote: there is no vote. It is the decision to stop treating "holds the seat" and "is driving" as the same fact. That split is what lets a device hand over control safely. It first gives up the half it can take back on its own authority, and it keeps the half whose loss could never be undone.

Prerequisites: Who Acts for why exactly one device may run autonomous work, and The Relay for what a sealed envelope hides from the server carrying it.


1. Two failures, and why one phase cannot dodge both

Who Acts named the two ways this goes wrong. Orphaned control: nobody drives. Every device politely defers to a sibling (another device signed into the same account), and the symptom is silence with no error anywhere. Sustained overlap: two devices drive at once. Notes are written twice, nudges fire twice, and your agent turns up twice in one huddle (a live group session where your agent and your friends' agents take turns) in front of other people. The two failures pull in opposite directions. There is only one knob: how long you wait before presuming a device is gone. That knob slides you along a single curve between the two failures. Wait longer and you risk the orphan; wait less and you risk the overlap.

Now make it concrete. Device B holds the seat and device A should take it. B stops holding at some instant, and A starts at some other instant. The two instants are separated by a message crossing a network, so one of them comes first.

If B stops first, there is an interval with no holder, and if A then crashes or never receives the message, that interval never ends. If A takes first, there is an interval with two holders. There is no third ordering. So a one-phase handoff (a single release, or a single take) can only choose which window it gets, never avoid both.

ONE MESSAGE CROSSES THE NETWORK — SOMEONE IS FIRST ORDER 1 · B STOPS FIRST B HOLDS A HOLDS NOBODY ORPHANED CONTROL IF A THEN CRASHES, IT NEVER ENDS ORDER 2 · A TAKES FIRST B HOLDS A HOLDS BOTH SUSTAINED OVERLAP TWO DRIVERS UNTIL A'S TAKE REACHES B A ONE-PHASE HANDOFF ONLY CHOOSES WHICH WINDOW IT GETS

The mechanism's response is to make one of the windows harmless rather than to try to close it. It splits the token (the marker that says "I hold the seat") from the authority to act. A device can then be the nominal holder while having already stopped doing anything. That is why there are two phases and not one: quiesce (literally, go quiet) stops the acting without dropping the token, and release drops the token only against positive evidence that a successor has taken over.


2. An order nobody has to negotiate

An election normally means negotiation: propose, vote, break ties, and repeat when the round is lost. Every one of those steps is a message that can go missing. And the thing being negotiated (who deserves to lead) is a moving target.

DeviceRoleService refuses the negotiation by fixing a total order in advance: a ranking in which any two devices compare the same way no matter which device does the comparing. Rank is chronological: the earliest-registered device is Primary, then Secondary, then Tertiary, and after that rankWord says "Device 4". The order comes out of a query in identity-svc (the service that keeps the list of devices registered to an account), a query never written for this purpose:

SELECT pubkey, mldsa_envelope_pubkey FROM identity_records
 WHERE user_id = $1 AND revoked_at IS NULL ORDER BY created_at DESC

DESC tells the database to return newest first, described in its own docstring as "a cheap most-recently-added proxy" for the device-sync path that actually needed it. So refreshOrder reverses it:

let chronological = Array(newestFirst.reversed())   // oldest=primary fallback

That single .reversed() is the whole election's source of authority. Note also that the list includes this device: the field's comment says so explicitly, "INCLUDING self (identity-svc raw)". Reconciliation, here and below, is the routine in which a device re-decides whether it should hold the seat, and the position of self in the ranked list is the only thing reconciliation reads.

Now the payoff. Because the order is total, stable and identical on every device, a device's decision reads exactly one thing: the slice of the list above it.

let higher = rankedOldestFirst[..<myIdx]

Nothing below myIdx is ever consulted. So the devices never have to agree about who should win (the ranking already says), only about who is present. And the two-driver failure becomes describable in one sentence: if A and B both drive, with A ranked above B, then B concluded that nothing above it was online. In other words, B believed A was offline.

A double drive is always a disagreement about presence, never about rank. That collapses the election into a failure-detection problem (deciding whether a silent sibling is dead or merely slow), which is the part you could not have avoided anyway.

One escape from the ranking, and it fails open: when in doubt, it errs toward acting rather than stalling. A device that cannot find itself in the list (a brand-new device, or, more commonly, a roster fetch that returned nothing) takes the seat unconditionally so the agent never stalls. Who Acts treats that as the largest hole in the design; it is the same hole here.


3. A two-byte claim on a channel contacts cannot see

The rank is half the answer. The other half is liveness (knowing which devices are actually up right now), and liveness needs a channel.

The obvious channel is the server that already holds the roster, and it is the one the design refuses. A presence table on identity-svc would be a minute-by-minute record of when you pick up which device, held by a service that knows whose account it is. The next-most obvious channel is a new message type on the relay, the server that ferries sealed messages between devices. That would mean a new subject (the routing label an envelope is addressed to), a new handler, one more thing the relay can tell apart from everything else.

What shipped is neither. The seat assertion rides the sealed same-account channel (encrypted end-to-end under a key derived from the account secret, which only your own devices hold) that already carries notebook and memory deltas, the small change records your devices sync:

let delta = Payload.syncDelta(SyncDelta(
    kind: "heartbeat", payload: Data([holdsSeat ? 1 : 0, requestReply ? 1 : 0]),
    updatedAt: UInt64(Date().timeIntervalSince1970)))
_ = try? await compose?.sendSealed(delta, to: sib)

Byte 0 is the seat assertion. Byte 1 is a request that the sibling send a beat (a heartbeat frame) straight back; that on-demand ping is what §7 depends on. A one-byte payload from an older build decodes as requestReply = false, so the frame grew a byte without a version negotiation.

Three things fall out of that choice.

No election service. Nothing in the deployment knows the seat exists: no lease to renew, no lock row, no endpoint that has to be told you are alive.

No new wire type. The receive path already had a syncDelta case; the seat is a new kind string inside it, dispatched in InboxService beside memory and the reconcile rounds.

No contact-visible presence, which matters most and is least obvious. The envelope goes to inbox.<subject>. The inbox. prefix is a historical name the derivation has since drained of meaning, because the subject is no longer anyone's inbox. The subject is HKDF-SHA256(channelKey, "pixie-pair-subject:v1", "epoch" ‖ recipientPubkey ‖ epoch), where HKDF is a standard key derivation function (a one-way grinder that turns a secret plus a few labels into a fresh pseudorandom value), and ‖ means concatenation, gluing the inputs end to end. The derivation grinds the shared key and a counter into a value that gives away neither. It is the same derivation your conversations with other people ride, with the shared sibling key standing in for a contact's channel key.

The recipient device's public key is an input to that info string, and deliberately so: it is what gives each sibling its own subject, so a frame addressed to one device is not delivered to all of them.

But it goes in through a one-way derivation under a key only your devices hold, so what the relay sees is 32 pseudorandom bytes it cannot run backwards. No phone number and no account id enter at all, and the value rotates hourly. On the receive side, InboxService applies a syncDelta only when the sender's userIDHash (a hashed stand-in for the account id) equals your own.

So the asymmetry is structural rather than a permission check: whether you are online is readable by anything holding your sibling channel key, and nothing else holds it. A contact cannot learn it: their key derives different subjects, and their frames fail the self-gate, the check that the sender's hashed account id matches your own. The relay cannot either: it sees an opaque 32-byte subject and a blob, and the blob is two bytes of plaintext under a layer it cannot open.

SIBLING CHANNEL KEY — BOTH DEVICES HOLD IT DEVICE A DEVICE B RIDES SYNCDELTA · KIND: HEARTBEAT RELAY BYTE 0 · ASSERT SEAT BYTE 1 · REQUEST REPLY SUBJECT = HKDF(SIBLING KEY, EPOCH) ROTATES HOURLY · NO ACCOUNT ID OPENS: SEAT · REPLY? WHO CAN READ THE HEARTBEAT SIBLINGS HOLD THE CHANNEL KEY RELAY OPAQUE SUBJECT + SEALED BLOB CONTACT DIFFERENT SUBJECTS · SELF-GATE PRESENCE IS READABLE ONLY UNDER THE SIBLING CHANNEL KEY

4. Quiesce: evidence of life without evidence of driving

The state the first phase exists for is narrower than it sounds.

There are two inbound liveness signals. noteSiblingHeartbeat(_:holdsSeat:wantsReply:) records both freshness and the sibling's seat assertion. noteSiblingHeard(_:) fires for any other self-gated frame: a self-echo (the copy of an outgoing message that loops back to your own devices), a memory delta. The comment on noteSiblingHeard(_:) is careful: it "proves liveness, but carries no seat assertion, so leave the last-known assertion as-is." Quiesce is exactly the gap between those two facts: I know you are alive, and I have no evidence you are driving.

That gap is not exotic. Your Mac has been driving because your phone was asleep. The phone wakes, and the Mac's ping arrives before the phone's own reconciliation has run. The phone's pong replies immediately with whatever holdsSeat currently is, and for a device that just launched, that is false. The Mac now knows the phone is alive and is not driving. It would learn the same thing from a plain memory delta arriving from a sibling that has not beaten yet.

What the Mac does then:

} else if higherOnline {
    if !yielding {
        yielding = true
        await onYieldSeat?()
    }
}

holdsSeat is untouched. Every subsequent heartbeat still asserts the token. But isDriving is holdsSeat && !yielding, so it goes false on the same line: nominal driver, no longer acting. That is the lame duck: still officially in the seat, no longer doing the job.

Why this is the safe intermediate is an argument about what a device can do unilaterally. Stopping work needs no confirmation from anyone: the instant I have evidence that a better-ranked device is up, I can stand down on my own authority, and overlap is prevented immediately.

Dropping the token is the opposite: it is the only act that can create an orphan, and its safety depends entirely on a fact about someone else. So the device gives up the half it can retract by itself and keeps the half whose absence would be irreversible.

One honest wrinkle. The header describes quiesce as stopping work and flushing context, and onYieldSeat is a real hook for exactly that. In the shipping app the hook is never assigned, and the reason is recorded where the wiring would go. Memory events already emit a live sync_delta, and notebook and saga edits converge through the digest-reconcile round in Staying in Sync. So the state a successor needs arrives on its own schedule rather than as a parting gift from the device stepping down.

The hand-over-with-context step was designed, built as a seam, and then deliberately left unplugged because the sync layer made it redundant.

The huddle takeover path carries a check of its own, and it is worth being exact about what that check does. The taking-over sibling compares the peer-served snapshot against the dropped driver's last published shared state root: a hash over the huddle's own shared progress, computed under its own domain tag (a label mixed into the hash so one kind of hash can never be mistaken for another). It is not the per-namespace digest the reconcile rounds use.

The comparison is advisory: on a mismatch it logs and resumes anyway. The served snapshot is the best state any peer holds, and refusing it would strand the huddle rather than repair it. The check signals that reconciliation is needed; it does not pull the missing state itself. Taking Over a Live Huddle is that protocol in full.


5. Acquire: a device only ever looks upward

The other branch is three lines:

if !higherOnline && !higherAssertsSeat {
    holdsSeat = true
    yielding = false
    if let onAcquireSeat { Task { await onAcquireSeat() } }
}

Read the two conjuncts (the two conditions joined by the "and") against their definitions. higherOnline is "some device above me is fresh", meaning heard from recently; higherAssertsSeat is "some device above me is fresh and asserts the seat." The second implies the first, so !higherOnline already implies !higherAssertsSeat, and the test reduces to !higherOnline.

The redundancy is the interesting part: it writes down, in the condition itself, that an assertion only counts when it arrives with liveness. A dead holder's last claim is a fact about the past, and the code is shaped so no later rearrangement can accidentally let it block anybody.

Now the case that matters. A lower-ranked device still asserting the token (the lame duck from §4) does not block acquisition, and this is not a special case anywhere in the code. It falls out of rankedOldestFirst[..<myIdx]: a lower-ranked device's assertion is invisible to the acquiring device by construction. The new driver takes the seat on top of the old one, and there is no instant in between where nobody holds it.

The steal is the same branch with time doing the work. If the holder dies, nobody will ever confirm anything, so the confirmed path cannot complete. Instead its lastHeard timestamp ages past the presence window, isFresh goes false, higherOnline goes false, and the next device down acquires. That timeout is the mechanism's only one, and it exists solely for the case where positive evidence is impossible.

Release (phase 2) is the mirror of quiesce:

if holdsSeat {
    if higherAssertsSeat {
        holdsSeat = false
        yielding = false
    }

Not a timer. The token is dropped against a specific observed fact: a higher-ranked device, fresh and asserting, in a frame this device decrypted itself. And the third branch of that same if makes quiesce reversible: if no higher device is online any more, yielding goes back to false and the lame duck resumes driving. A device that stood down for a sibling that then vanished does not stay stood down.


6. What the invariant does and does not promise

The invariant is one sentence: the yielding device never drops the token until it has seen the new driver assert it. Two consequences, one comfortable and one not.

PHONE RANK 1 MAC RANK 2 AWAKE · NOT YET ASSERTING HOLDS + DRIVES ACQUIRE — SEAT TAKEN ON TOP DRIVES LAME DUCK — HOLDS ONLY QUIESCE — STOP ACTING, KEEP TOKEN RELEASE — ASSERT SEEN PONG: ALIVE · SEAT = 0 HEARTBEAT: SEAT = 1 · ONE HOP BOTH HOLD — NO ORPHAN A LOWER-RANKED ASSERT IS INVISIBLE UPWARD — IT CANNOT BLOCK THE ACQUIRE THE TOKEN DROPS ONLY WHEN THE NEW DRIVER IS SEEN ASSERTING

The comfortable one: no window during a handoff has nobody holding the seat. The old holder is still holding at the moment the new one takes. So a taker that crashes mid-handoff leaves the old holder in place (quiesced, but present), and §5's third branch resumes it once the taker stops looking alive.

The uncomfortable one: the double-hold window is real by design, and the double-act window is narrowed rather than eliminated. Device A acquires and begins driving the moment its own reconciliation runs, which is before anything it sends has reached B; B stops acting when A's frame lands.

So both devices genuinely act for as long as one heartbeat takes to cross the relay, and no local decision can shorten that, because B cannot react to a fact it has not received. What the mechanism removes is sustained overlap: the two-driver state ends on a positive event (the assertion arriving) rather than on a timeout, and the window is one relay hop rather than one presence window.

That is the trade §1 said you cannot escape, taken deliberately: the design accepts a bounded overlap window because overlap has per-activity backstops (watermarks that record what was already processed, per-contact cooldowns, day stamps), while an orphaned seat has no symptom at all.


7. Asking the question is what produces the answer

isActiveAgent() looks like a predicate, a function that just checks a condition and answers yes or no. It is not. It performs network I/O and can take a second and a half.

if let last = lastHandshakeAt, now.timeIntervalSince(last) < Self.handshakeDebounce {
    await refreshOrder()
    await reconcileSeat()                            // reuse fresh presence
} else {
    lastHandshakeAt = now
    await beat(requestReply: true)                   // ping every sibling
    if settleDelay > 0 { try? await Task.sleep(for: .seconds(settleDelay)) }
    await reconcileSeat()                            // decide on the pongs
}
return isDriving

The first call in a handshakeDebounce window (5 seconds) pings every sibling with the reply-request bit set. It waits one round trip (settleDelay, 1.5 seconds in the app and 0 in tests), and only then reconciles. Calls inside the window reuse the presence the first one paid for. Pongs never request a reply of their own, so a ping cannot loop, and replyThrottle (2 seconds) stops a chatty sibling from making this device beat in a storm.

There is no periodic heartbeat anywhere. An idle account generates no liveness traffic at all, which means presence is manufactured on demand at the moment a decision needs it. That inverts the property that made the naive race unavoidable: because one inbound envelope fans out to every device at once, all of them handshake on the same event and converge exactly when there is work to converge about.

What the seat gates is narrow. AgentRuntime is the single funnel. run(activity) { … } returns nil when this device is not driving; isAgent(activity) serves call sites that prefer an early return; both call straight through to DeviceRoleService. The activity value is not an input to the decision; it documents intent and anchors handoff for the resumable activities.

The line it draws is generation, not action. Sending a message from a non-driving device is completely untouched: it goes to the recipient and self-echoes to your siblings exactly as it would from the driver. Filing an inbound message, acknowledging it, writing the memory event, applying a thread title a sibling chose: all ungated, on every device.

What the gate covers is work the agent invents: a note-taking distillation, a thread name (a call to the LLM, the large language model), a proactive nudge, a huddle turn. One feature can land on both sides of the line, and the side is decided by where the non-determinism sits: the step whose output would come out different if two devices each ran it.


8. Overriding the order, and showing the work

Registration age has nothing to do with fitness: it knows nothing about battery, thermal headroom, which device can run which model, or which one is in your hand. So Settings → My Devices lets you drag the list, and Save writes SettingsKey.deviceOrder: a comma-separated list of device public keys in hex, top priority first.

That setting has to sync, and §2 says why: the guarantee there was that devices never disagree about rank, so all disagreement reduces to presence. A purely local reordering breaks precisely that invariant, and the breakage is two drivers, each top of its own private list. So the comma-separated list rides the synced-settings CRDT (a conflict-free replicated data type, a data structure every device can edit independently while all copies still converge on the same value), and every sibling elects the same order.

applyUserOrder then has to survive a preference older than the device set:

let ordered = userOrder.filter { present.contains($0) }
let appended = chronological.filter { !orderedSet.contains($0) }
let result = ordered + appended
return result.isEmpty ? chronological : result

Keep the user's order for devices that still exist; append devices the preference has never heard of at the end; drop devices no longer present; and if any of that leaves nothing, fall back to chronological. Every clause preserves a total order over the live set in the face of a stale list.

The result is rendered back by deviceStatuses(reachable:fallbackRoster:), whose most interesting behaviour is what it does when it cannot vouch for anything: if the roster handshake failed, this device shows .offline and every other shows .unknown. The status type has a third case specifically so the UI can decline to guess.

One deliberate exception to the ordering. forceClaimSeat() takes the seat out of band (outside the normal ranked path) for mid-huddle failover: a sibling that has confirmed the driver dropped needs the seat now, not after the predecessor times out. It sets the token and then beats. And because beat() reconciles before it sends, a claimer that is wrong about the predecessor being gone still steps down for a device that is verifiably online right now.

The tests pin both halves. The point of claiming loudly is that a returning ex-driver sees the assertion and hands off through §4 and §5 instead of double-driving. The reverse hook, onAcquireSeat, closes the loop: acquiring the seat is itself the trigger to check whether a huddle needs taking over.


9. The residual

Partition is not handled, and it is the honest hole. A partition is the network split in which two devices are both up but cannot reach each other. Acquisition is a local belief about a remote fact. If two devices cannot exchange heartbeats but both remain able to do work, the lower-ranked one's isFresh for the higher goes false after the presence window and it acquires, while the higher never sees anything that would make it release. Both drive, and nothing here bounds how long that lasts; it ends when the partition ends. This is availability chosen over exclusion, and the per-activity backstops are what make it survivable. The layer above does solve its version of the problem: before seizing a dropped driver's live huddle, attemptWitnessedTakeover asks the other members' devices whether anyone still sees it, and a single "I still do" vetoes the takeover. External witnesses, unanimous absence required. And no responders at all means you may be the isolated one. The seat election has no such witness, because the only witnesses available to it are the devices whose reachability is in question.

Presence lags, and the lag is a round-trip budget, not a heartbeat interval. Since there is no periodic beat, "online" means "answered our most recent handshake within presenceWindow" (8 seconds), and the gate waits settleDelay, 1.5 seconds, for pongs before it decides. A sibling whose relay round trip exceeds that budget reads as offline and the seat may move to a device that should not have taken it. Eight seconds is aggressive on purpose; 1.5 seconds on a cellular hop is the number actually at risk.

The gap after a hard death is measured from the next piece of work, not from the death. The confirmed release cannot fire when there is nobody to confirm, so the steal path runs, but only when something calls the gate. In exchange, an idle account whose driver has died costs nothing, because there is nothing that wanted driving.

Instantaneous overlap remains, bounded by one relay hop, as §6 derived. A reordering has a propagation window, since the override is a synced setting, so two devices can briefly hold different orders, reintroducing, for a few seconds, the one condition §2 ruled out. And the seat is a filter, not a lock: holdsSeat alone is not the exclusion property, isDriving is, and code that reads the token believing it asked "am I the agent" asked a different question.


References & further reading

← Mechanism: Revoking a DeviceMechanism: Taking Over a Live Huddle →