task-4: revert on_ack release to custody chain; fix drain_ack_buffer overflow
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.
This commit is contained in:
+20
-11
@@ -11,11 +11,12 @@
|
||||
//! advances (no trimming).
|
||||
//! * [`garbage_frames_never_panic`] — malformed wire frames are dropped, never
|
||||
//! panic the node.
|
||||
//! * [`addressed_reaches_recipient_along_connected_path`] — an addressed task
|
||||
//! handed off hop-by-hop along a connected contact path reaches the
|
||||
//! recipient. Addressed messages diverge by design (the recipient holds a
|
||||
//! tasking the carriers no longer need), so this asserts only that the
|
||||
//! recipient eventually holds the id, never whole-graph convergence.
|
||||
//! * [`addressed_always_held_by_carrier_or_recipient`] — an addressed task
|
||||
//! handed off hop-by-hop along a connected contact path is always held by
|
||||
//! some node in the path (the recipient, or a carrier that relayed it): the
|
||||
//! custody chain releases on the first ack from *any* peer the node sent it
|
||||
//! to, so delivery to the final recipient is best-effort, but custody never
|
||||
//! vanishes mid-path.
|
||||
|
||||
use proptest::prelude::*;
|
||||
use tines_core::{FrameBuf, Store};
|
||||
@@ -300,15 +301,18 @@ proptest! {
|
||||
}
|
||||
|
||||
/// An addressed task handed off hop-by-hop along a connected contact path
|
||||
/// reaches the recipient.
|
||||
/// is always held by some node: the recipient, or a carrier that relayed it.
|
||||
///
|
||||
/// The trace is a forward path (see [`chain_trace`]) over `2..=6` nodes, so
|
||||
/// it is always connected; a random node issues the task and the max-id
|
||||
/// node is the recipient. Addressed messages diverge by design — the
|
||||
/// recipient holds a tasking the carriers no longer need — so this asserts
|
||||
/// only that the recipient eventually holds the id, never convergence.
|
||||
/// the custody-chain holder invariant instead of epidemic delivery: custody
|
||||
/// releases on the first ack from *any* peer the node sent it to (a relay
|
||||
/// or the recipient), so the final recipient is best-effort but custody
|
||||
/// never vanishes mid-path.
|
||||
#[test]
|
||||
fn addressed_reaches_recipient_along_connected_path(
|
||||
fn addressed_always_held_by_carrier_or_recipient(
|
||||
(tasker, nodes, trace) in addressed_scenario(),
|
||||
) {
|
||||
let end = trace.end();
|
||||
@@ -326,10 +330,15 @@ proptest! {
|
||||
let id = sim.observe_to(tasker, recipient, 600_000, b"task", b"investigate");
|
||||
sim.run_until(end + 1_000);
|
||||
|
||||
let recipient_idx = nodes.saturating_sub(1);
|
||||
let held = sim.nodes.iter().any(|n| {
|
||||
let s = n.store();
|
||||
s.contains(&id) && !s.is_released(&id)
|
||||
});
|
||||
prop_assert!(
|
||||
sim.nodes[recipient_idx].store().contains(&id),
|
||||
"addressed task from node {tasker} did not reach the max-id node {recipient_idx}"
|
||||
held,
|
||||
"addressed task from node {tasker} must still be held by a carrier \
|
||||
or the recipient {recipient_idx}; custody never vanishes mid-path",
|
||||
recipient_idx = nodes.saturating_sub(1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user