From 3a8918fb0edd2d05512f8c820cca40c3f7920a75 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Tue, 12 May 2026 09:25:12 -0600 Subject: [PATCH] spec(multipart): document plain-ACK finalizer after MULTIPART chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify that the MULTIPART ACK chain terminates with a plain PAYLOAD_TYPE_ACK (not a MULTIPART with remaining=0). For K extra copies, the wire sequence is: MULTIPART(remaining=K), MULTIPART(remaining=K-1), ..., MULTIPART(remaining=1), then PAYLOAD_TYPE_ACK (plain). All copies share the same ack_crc. Receivers MUST dedup at the application layer by ack_crc, since each packet's hash differs. Validated against upstream meshcore-dev/MeshCore @ 1a7b361 (Mesh::routeDirectRecvAcks, src/Mesh.cpp:362 — while-loop emits MULTIPART(remaining=extra...1), then createAck(crc) plain ACK). Co-Authored-By: Claude Opus 4.7 (1M context) --- spec/11-payload-multipart.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/11-payload-multipart.md b/spec/11-payload-multipart.md index 374c798..967db5a 100644 --- a/spec/11-payload-multipart.md +++ b/spec/11-payload-multipart.md @@ -57,7 +57,13 @@ The only currently defined multipart sub-type is ACK (sub_type = 0x03): Total payload: 5 bytes (1 byte header + 4 byte CRC). Multipart ACKs are used to send additional ACK retransmissions for reliability. -The `remaining` field indicates how many more ACK packets follow this one. +The `remaining` field indicates how many more ACK packets follow this one, +counting down: a chain of K extra copies is emitted as MULTIPART with +`remaining = K, K-1, …, 1`, followed by exactly one final plain +`PAYLOAD_TYPE_ACK` packet (NOT a MULTIPART with `remaining = 0`). All copies +in the chain carry the same `ack_crc`. Receivers MUST treat the first copy +received as the authoritative ACK and dedup subsequent copies by `ack_crc` +at the application layer. ### Multipart ACK Usage Constraints