Conflict resolution
Every device holds its own complete library. When two of those meet in one session, it has to be clear who is right.
Why conflicts happen
The usual cases:
- One person edited a song at home, another still has the original
- Two people added the same song independently and slightly differently
- A setlist was renamed on only one device
- Someone was offline while editing
Songs: your copy wins
When the leader switches songs, members do not receive lyrics to display — they receive an identification of the song. The member matches it against its own library:
- First by
syncId, if both sides have one - Then by a key composed of title, artist and variant
This rule is called "local wins". It means your lyric edits, your transposition and your notes never disappear just because the leader changed song.
Shared fields are overwritten only when you ask for it — either by explicitly merging with the leader's version, or by importing it as a new copy. The app also reports back which version of a song you hold, so the leader can see whose copy is older.
What is never overwritten
Personal fields simply are not in the transferred payload — there is no way for them to be overwritten:
- private notes
- chord and MusicXML transposition
- font size and auto-scroll speeds
- default display mode and PDF settings
- hand-drawn annotations
Setlists: you decide
Setlists do not use "local wins", because a setlist is the whole band's working document. When an incoming setlist matches an existing one, a dialog offers a choice:
| Choice | Result |
|---|---|
| Keep mine | The incoming setlist is discarded |
| Take the leader's | The local setlist is replaced with the leader's version |
Nothing changes without your decision.
Missing content
- On — the member requests the song itself and receives its shared fields
- Off — a button appears so you can request the download by hand
Connection loss
When the connection drops, the member retries on a growing schedule:
1 s → 2 s → 4 s → 8 s → 16 s → 32 s → 60 s → 60 s → 60 s → 60 s
Once the attempts are exhausted, reconnection stops and an error is shown. You can then reconnect by hand.
Other behaviour on connection loss:
- Returning from the background — on wake the app re-checks its own IP address and the state of the socket, because the phone may have hopped to a different network
- In-flight transfer — if the connection drops mid-download, the transfer is aborted so no corrupted file is left behind
- Kicked by the leader — the member gets a clear message and pending transfers are cleaned up
A single member dropping does not affect the leader. It plays on, the member disappears from the list after 25 seconds of silence and returns on reconnect.
Error states
Sync works with named errors, so the message tells you what actually broke:
| Error | Meaning |
|---|---|
| Could not resolve IP address | The device has no usable local network address |
| Port collision | None of the ports 8765–8769 could be bound |
| Session full | The leader already has 50 members |
| Wrong password | The session PIN does not match |
| Join failed | The /join call did not go through |
| Invalid server response | Whatever answered is not Eutepio |
| Leader disconnected | The leader ended the connection |
| Reconnect failed | All retry attempts exhausted |
| Invalid QR | The code is not an Eutepio pairing link |
Known limitations
Further:
- There is no version history. Once you overwrite shared fields with the leader's version, the previous content is gone. The only safety net is a backup.
- Deletion is soft, but does not propagate. A deleted song stays in the database flagged as deleted; the deletion itself does not sync to other devices.
- There is no merge of two differently edited lyrics. You either keep yours or take theirs — nothing in between.