# Conflict Replay & CRDT Sync

> Audience: operators running multi-tab or multi-device Mirror sessions, and anyone auditing how concurrent edits to a signal get reconciled.

Mirror Mode's Live layer produces a stream of `mirror_signals`. Once two surfaces (two tabs, a phone + a laptop, a human + an agent revision) can touch the same signal at the same time, "who wins" stops being obvious. The **Conflict Replay panel** and the underlying **CRDT sync layer** make that arbitration visible, filterable, and reversible.

## CRDT sync

MIRARI now converges concurrent edits to a signal without a server round-trip on the hot path.

* **Last-writer-wins per field** with a Lamport-style logical clock, so clock skew between devices doesn't decide the winner.
* **Tombstone bias** — a delete on one tab beats a stale local edit on another, but a fresh edit beats a stale tombstone. The bias direction is recorded in the replay row.
* **Concurrent tiebreak** — when two writes share a logical timestamp, the tiebreak is deterministic (origin id hash), and the loser is preserved as a `shadow_value` so nothing is silently dropped.
* **No server round-trip** — convergence happens in the browser via the realtime channel. The server only persists the converged state and the arbitration record.

Open two tabs, edit the same signal in both, and the panel resolves live. The arbitration record is what powers the Replay panel.

## Conflict Replay panel

A dedicated panel under Mirror Mode that scrubs through every arbitration MIRARI performed on your signals.

### Filters

* **Race type** — `LWW overwrite`, `tombstone bias`, `concurrent tiebreak`.
* **Search by signal id or diff field** — jump straight to the contested field (e.g. `severity`, `summary`, `payload.prompt_seal`).
* **Isolate prompt-seal or judge-score changes** — two of the highest-stakes fields get a one-click filter, because a stale prompt seal or a regressed judge score is the kind of conflict you want to catch fast.

### Row shape

Each row in the panel is one arbitration:

```
 signal_id   field          race_type            winner    loser (shadow)   at
 sig_8b…     judge_score    concurrent_tiebreak  4         3                12:04:51.221
 sig_8b…     prompt_seal    lww_overwrite        v3:abc…   v2:de1…          12:04:51.244
 sig_2c…     summary        tombstone_bias       <deleted> "draft text"     12:05:02.018
```

Clicking a row opens the full before/after diff plus the Lamport clocks that decided it. You can promote any losing value back to current with one click — the promotion itself is recorded as a new arbitration, so the audit chain stays unbroken.

### Why this matters

Live Mirror signals are the substrate Reflection runs on. If a concurrent edit silently overwrote a judge score or a prompt seal, every downstream reflection inherits a lie. Conflict Replay makes that class of bug observable and reversible without leaving the app.

## Server-side shape

```ts
// Stream arbitrations for a signal (or all signals in scope)
const stream = useServerFn(streamConflictReplay);
await stream({ data: { signalId, raceTypes: ['concurrent_tiebreak'] } });

// Restore a shadow value as the current value
const restore = useServerFn(restoreShadowValue);
await restore({ data: { arbitrationId } });
```

Arbitrations live in `mirror_signal_conflicts` and are RLS-scoped to the signal's owner. The realtime channel that drives the CRDT also drives the panel, so the replay updates without a refresh.

## Pairs with

* [Mirror Mode](/entermirari-docs/the-six-rites/mirror-mode.md) — the source of the signals being arbitrated.
* [Observatory & Tasks](/entermirari-docs/the-six-rites/observatory-tasks.md) — surfaces unresolved conflicts as triage items.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://entermirari.gitbook.io/entermirari-docs/the-six-rites/conflict-replay.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
