diff --git a/PARITY.md b/PARITY.md index 818c6c6..ba25675 100644 --- a/PARITY.md +++ b/PARITY.md @@ -461,3 +461,44 @@ section and a tab bar. A DM run takes 20-40 minutes per side. The group phase has never completed inside a sitting. **Budget hours, not minutes** — or give the pair a trimmed screen to work against before running it. + +### 🔴 REPRODUCED CHEAPLY — and the retired-session fix does NOT close it + +2026-08-25, two `:interop:peer` accounts against `relay1`, no simulators, no UI. +Both had the retired-session fix compiled in. + +``` +p1 send p2 first-from-P1 {"delivered":1,"failed":0,"to":408} +p2 send p1 first-from-P2 {"delivered":1,"failed":0,"to":407} # neither had polled +p1 poll {"messages":[{"text":"first-from-P2",...}]} ✅ +p2 poll {"messages":[{"text":"first-from-P1",...}]} ✅ +p1 send p2 second-from-P1 {"delivered":1,"failed":0,"to":408} +p2 send p1 second-from-P2 {"delivered":1,"failed":0,"to":407} +p1 poll {"messages":[]} ❌ +p2 poll {"messages":[]} ❌ +``` + +**First messages cross. The second exchange is lost in both directions, silently, +with the relay reporting `delivered:1, failed:0`.** + +This is the same failure seen between two simulators, with every iOS variable +removed — two Kotlin clients and a live relay. **Reproduce it in about two +minutes** rather than the 20-40 the simulator pair costs: + +``` +./gradlew -q :interop:peer -Pargs="p1.json create

" +./gradlew -q :interop:peer -Pargs="p2.json create

" +# add both ways, then send both ways WITHOUT polling, then poll, then send again +``` + +⚠️ **Retaining the retired session is necessary but NOT sufficient**, which the +commit that added it does not say clearly enough. The receive side can now open +the old chain; what this shows is that the loop still does not close. The +likely remaining gap is on the SEND side — after adopting the peer's chain, +each client encrypts on the adopted one while the peer is still reading the one +it kept, so neither is listening where the other is talking. Resolving +simultaneous initiation properly means both sides converging on the SAME chain +by a deterministic rule (Signal breaks the tie on the identity keys), not each +adopting the other's. + +⚠️ Do not treat the ratchet-overwrite commit as having fixed this.