Exchange::accept enqueued a pending ack whenever
!(duplicate && addressed && released) held, even when the backend
store.insert returned Err (store full / backend error). On Err the
released flag computed to false, so an ack was still enqueued: a
receiver that did not keep the message acked it. For an addressed
offer that releases the sender's custody for a message nobody holds;
for a broadcast it fires a false confidence event at the sender.
Gate the ack enqueue on res.is_ok(): enqueue only when the store
actually retained the observation. The existing released-holder
exception still applies among kept copies. No bounce is recorded on
Err (already the case).
Adds a unit test exercising a capped store (StoreError::Full) for
both a broadcast and an addressed offer, and a tines-sim property
that drives custody with CappedStore-backed nodes and asserts the
"at least one holder" invariant still holds when stores fill.
Revert on_ack release gating to release-on-any-ack (custody chain): release
custody on the first exact Ack from ANY peer the node dispatched the
observation to (relay or recipient), not just the recipient.
drain_ack_buffer send_n==0 bug: re-keep only the target addr's own pulled
entries instead of removing buffer.entries[0] (which dropped an unrelated
peer's oldest pending ack).
Rename the tines-sim addressed proptest to
addressed_always_held_by_carrier_or_recipient and reconcile its assertion to
the custody-chain holder invariant. Reword the misleading "Ids shrink
monotonically" comment. Add unit tests: ack_releases_custody_from_a_relay and
drain_ack_buffer_overflow_drops_only_target_peer.
Gate green: tines-core 106 lib tests, tines-sim suite, sh scripts/ci.sh.
Buffer pending acks (acks for addressed, bcast_acks for broadcast,
ACK_BUFFER_CAP=256, overflow drops oldest), skip a released-duplicate
offer in accept(), and emit Ack frames in next_frame after a due summary
and before addressed/broadcast traffic, draining up to ACK_IDS_CAP ids
per destination and splitting across frames to fit mtu.
Release custody on an Ack only when the Ack confirms delivery to the
intended recipient: an Ack from a peer that merely holds an
epidemic-forwarded copy no longer releases custody, so the local copy
stays available to forward toward the recipient once the only contact to
it closes.
- Add Store::for_each_addressed_id (default: every id; MemStore filters)
so custody selection no longer clones every broadcast observation on
each poll.
- Factor fragment sizing into frag::plan and MAX_FRAGMENTS, used by both
frag::fragment and the exchange, and by the reassembler's bounds.
- Document `to` in the Observation::id hash input, matching the
addressed-delivery plan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Cut every fragment of a stream from one encoding (age frozen at the
first fragment) and bounds-check the slice: re-encoding mid-stream
corrupted fragments and could panic when the tick went backwards.
- Fold the bloom summary to fit the MTU instead of sending a ~540-byte
frame that small-MTU links reject; drop the sim's summary MTU
exemption that hid this.
- Finish a peer's in-flight stream before starting another, and count
an addressed message as delivered only after its last fragment.
- Alternate custody and broadcast per peer, rotate through addressed
candidates, and evict the oldest bounce record when full, so neither
path starves.
- Add Exchange::on_send_error; Node::poll uses it so Busy/Unreachable
sends are retried rather than silently dropped.
- Clear bounce records per contact, record duplicates against their
sender, and skip addressed messages that cannot fit the MTU.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run clippy, docs and tests for tines-core with --no-default-features,
gating the MemStore-based tests on `alloc` so they compile there. Fail on
rustdoc warnings, pass --locked everywhere, and pin the toolchain to
1.99.0. In the workflow, use read-only permissions, cancel superseded
runs, add a 20-minute timeout, and pin actions to commit SHAs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>