How Can Two Offline Teams Keep Both Inspection Counts?
Choosing the last arriving total can lose someone’s work. Give each replica an owned contribution and derive a merge whose repeated delivery does not inflate the count.
14 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Choosing Merge Rules That Fit the Operation
BOTIE
Our counter is a teaching instance of a state-based grow-only counter. We derive its merge from ownership and monotonic updates. It is suitable for accumulated inspections under those assumptions, not for every mutable document or bounded stock balance.
East and West Both Counted Inspections While the Link Was Down
Each maintenance team finishes inspections while disconnected. When their tablets reconnect, replacing one total with the other loses work. Adding the two totals can also count shared history twice.
We need to preserve enough information to tell which contribution belongs to which writer. A grow-only counter gives each replica its own component. That small change lets us derive a repeatable merge instead of guessing which total to trust.
Invented maintenance records. These deterministic local models expose a storage decision; they do not run a distributed database or establish its guarantees.
Step 1 of 1
Each component belongs to one writer
The replicas hold different observations of the same component map.
| Component owner | Copy A | Copy B | Meaning |
|---|---|---|---|
| east | 3 | 2 | East has advanced beyond the state B last saw |
| west | 1 | 4 | West has advanced beyond the state A last saw |
east
- Copy A
- 3
- Copy B
- 2
- Meaning
- East has advanced beyond the state B last saw
west
- Copy A
- 1
- Copy B
- 4
- Meaning
- West has advanced beyond the state A last saw
Choose a merge from the meaning of the operation
The merge preserves each writer’s greatest observed contribution and does not count a replay as new work.
Combine replica contributions without adding a replay twice
Merge each component with maximum, then compute the total from the merged component map.
BOTIE
Merged components and total
{
"components": {
"east": 3,
"west": 4
},
"total": 7
}Follow the operations
1. First observed component map
{ "east": 3, "west": 1 }2. Second observed component map
{ "east": 2, "west": 4 }3. Keep each replica's largest component
{ "east": 3, "west": 4 }4. Sum the merged components
{ "components": { "east": 3, "west": 4 }, "total": 7 }5. Result
{ "components": { "east": 3, "west": 4 }, "total": 7 }
The toy state-based counter assumes unique owners, monotonic components and eventual exchange of valid states. It does not implement Redis or arbitrary document reconciliation.
1. A last-write rule chooses a winner, not a combined meaning
A last-write-wins policy uses an ordering, often involving a timestamp and a tie-breaker, to choose one value. It can be useful for a replaceable preference, but it can discard an independent update to an inspection total. Wall clocks can also disagree, so a later timestamp does not necessarily identify the later real-world action.
Different fields may need different treatment. A technician’s note should not automatically be merged with the same rule as a set of completed inspection IDs or a stock reservation.
Convergence describes agreement after merging. It does not establish that the chosen value preserves the application’s intent.
2. Keep one component per writer
The counter state is a dictionary from replica ID to its nonnegative count. East increments only east’s component; west increments only west’s component. A replica may copy the whole map, but it must not independently invent increments for another owner.
Counts only increase. A replica that loses its local state cannot safely reset its old component to zero and continue under the same identity. Recovery must restore that state or introduce a new unique writer identity under a documented policy.
The ownership and no-reset assumptions make maximum a meaningful merge.
Check yourself
Questions on Parts 1 to 2
Question 1 of 2
Which value preserves the known progress?
Use the information below.
East owns east’s component. A copy reports east=3 and another reports east=2. Components only increase.3. Derive the merge one component at a time
For each owner, the larger observed count includes at least the progress represented by the smaller one. Retain that maximum. A missing component represents zero progress in that snapshot. After merging all owners, sum their retained contributions.
Use a dictionary for named components rather than a list whose positions silently depend on the order writers joined. Sorting the names only gives a repeatable display; it does not change the mathematical state.
merged[owner] = max(left.get(owner, 0), right.get(owner, 0))
total = sum(merged.values())This formula performs a merge of states, not a replay of increment commands.
Replaying one component does not create another increment
Compare two observed values belonging to the same writer.
earlier = 2
later = 5
merged = max(earlier, later)
replayed = max(merged, earlier)
print(merged)
print(replayed)5
5The earlier observation adds no new progress after the later one is already retained.
4. Check the properties that permit reordering and replay
Merging a state with itself leaves it unchanged: idempotence prevents duplicate snapshots from inflating the result. Swapping the two inputs gives the same state: commutativity removes dependence on arrival order. Grouping successive merges differently also gives the same state: associativity allows intermediate replicas to combine updates.
Those properties help when valid states eventually reach the replicas that need them. They do not deliver messages, authenticate writers or guarantee that every offline device will reconnect. The application still has to satisfy the communication and identity assumptions.
The challenge tests these properties on concrete component maps instead of treating one displayed total as sufficient evidence.
5. A decrement needs a different representation
A grow-only counter cannot represent removing an inspection. One extension keeps separately owned positive and negative components and subtracts their totals, with its own rules. Sets with removal also need information about which additions were observed; deleting a value from a plain union can be undone by a delayed copy.
Do not implement removal by decreasing a component in this counter. A remote replica holding the previous larger value would restore it at the next maximum merge.
A new operation can require a new data type and a new proof of its merge behaviour.
6. Convergent counts do not reserve the last kit
Two disconnected teams can each decrement a local available-stock estimate and later agree on a negative total. The merge can be internally consistent while violating the business invariant that stock must never be oversold.
Coordination, preallocated spending rights or another specialised design is needed when the invariant requires it. Our earlier conditional write intentionally took a different approach for a single authoritative stock item.
Choose availability and merging only where the permitted outcomes match the maintenance task.
7. Keep conflict evidence when no safe merge is known
A document can contain two incompatible repair decisions that no automatic rule should erase. Retain the relevant versions, actors and source evidence, then route the conflict for reconciliation. The resolver’s decision becomes a new recorded action.
Choose a policy before an outage produces competing writes. A deterministic arbitrary winner makes failures reproducible, but it does not make a lost repair note acceptable.
Botie’s changed counter case tests repeated and older observations. It does not claim a universal conflict resolver.
Check yourself
Questions on Parts 1 to 7
Question 1 of 2
What does convergence fail to establish?
Use the information below.
Two disconnected teams spend stock independently, then merge to a negative available total.Try it with Botie
Build with Botie
Write and run Python