How folding works

What a hold does with commits while its link's window is full (two messages unacknowledged), and why folding needs no size measuring.

The rule

While the window is full, a hold keeps the ops of each new commit raw in a pending list. Before appending an op, it looks at the last pending op only:

last pendingnew opresult
a path "Hel"a path "lo"one a path "Hello" (text joined)
s path 41 or a path …s path 42one s path 42 (the set overwrites what came before)
anything on another pathanythingappended as it is

Applied in order, the folded list gives the same value as the unfolded one: only neighbours on the same path merge, so no op in between can see the difference. Cost: one path comparison per op. When an ack frees a slot, the pending list is encoded once into one message.

a = append texts = set valuep = insert into listsnapshot
link
window full: 2 unacked (tunnel)
commits
pending (raw)
sent
commits 0 pending ops 0 merged or dropped 0 encodes 0

What the four cases show

casepending after the stallwhy
streamed reply1 opevery token appends to the same path
counter, 100,000 sets1 opeach set overwrites the previous one
reply + status, interleavedgrowsthe neighbour is always on the other path: adjacent-only folding cannot merge
new list itemsgrowsinserts carry new data: nothing to fold, this is the real change

The last two cases are why a memory bound is still needed. It can be a plain count of pending ops after folding (say 1,000): past it the hold drops its list and marks “send the current value”, which then costs nothing more while the stall lasts.

Why not time since the last ack?

A time trigger (“no ack for T seconds: drop the list, send a snapshot later”) punishes the most common case: a phone in a tunnel while a reply streams into a long conversation. Folded, the 60 s stall costs one append of about 12 KB; a snapshot of the conversation costs its whole size (Astra's corpus: 4.6 KB of updates against 168 KB, recovery 0.2 s against 2.7 s). And before T, a fast producer on many paths still piles up rate × T ops: time bounds duration, not memory. With folding, the counter case (100,000 sets) is one op whatever the time, so time adds nothing there.