Authority and conflicts

The moment a project exists on more than one machine, something has to decide what order things happened in. mcue answers that with an explicit sequence and typed conflicts — never with a clock comparison.

Before you publish

There is no question to answer. Your machine holds the state, your machine is authoritative, and nothing else can write to it.

After you publish

Publishing changes the authority model for that project. Hub orders accepted operations; every mcue installation becomes an offline-capable replica of that ordering.

Each accepted operation gets a monotonically increasing per-project sequence. That sequence — not a timestamp — is what "after" means. Wall-clock time is recorded as evidence and is never the arbiter, because two machines disagreeing about the time is a normal condition, not an exceptional one.

The four fields that make it work

Every operation carries:

  • operation_id — unique per operation. Retries are safe: replaying an operation id returns the original result rather than appending a second copy. This is what makes a dropped response harmless.
  • base_entity_revision — what the operation was written against. If the entity has moved on, the write is stale.
  • project_event_sequence — assigned on acceptance. Your sync cursor.
  • entity_revision — assigned on acceptance. Detects the next stale write.

Pending work

A local mutation applies locally first, then goes into a durable outbox. Until Hub accepts it, it is pending and mcue says so:

mcue sync status payments-api

That command makes no network request. It reads your cursor and your outbox and tells you what has not been accepted yet. Pending work is never silently discarded — not on reconnect, not on conflict, not on unlink.

What happens on reconnect

mcue sync exchanges pending operations and pulls events after your cursor, then rebuilds the accepted base and replays anything still pending on top.

SituationResult
the same operation_id arrives twiceoriginal result returned; nothing appended twice
two append-only writes to one laneboth accepted; the lane becomes divergent and needs reconciliation
a mutable write against a stale revisionrejected with the current revision and a typed conflict
a delete against a changed entityrejected; never cascades from stale state
an accepted remote write while you were offlineapplied on your next pull
an invalid operation from any sourcerejected by the shared validator

Divergence is not failure

Append-only writes — checkpoints, perspectives — never conflict in the destructive sense. Both survive. The lane is marked divergent, and:

mcue reconcile payments-api

is how you resolve it. Reconciliation is a human judgement about which perspective is right, so mcue asks rather than guesses. That is the whole reason there is no last-write-wins: the later write is not more correct, it is just later.

Why no automatic merge

An automatic merge of operating state would have to decide that one person's account of what happened supersedes another's. It cannot know that. The honest options are to keep both and ask, or to reject the stale one and say why — which is exactly what the table above describes.

The cost is that you occasionally have to reconcile by hand. The benefit is that mcue never quietly loses the record of what you were doing.

Revocation is not deletion

Revoking a device or an OAuth client stops further access. It does not delete project state, on Hub or locally. Similarly, mcue unlink removes only this machine's link and outbox — the local state and the Hub project both remain.