review: the batch-2 gate closed — the assembly layer verified, R-1/R-2 fixed
Review checkpoint closing batch 2 (the assembly layer). The gate opens: the never-binds posture, seam contracts, door fidelity, the bind-first graduation, feature-gate hygiene, and POC fidelity all verify clean; two findings were corrected in the review change. Findings corrected: - R-1 (major): the UDP front door's in-band decode created a fresh DatagramReader per call and kept only the first frame of a batch — POC #2's first-cut bug (reader state must persist across calls; batched datagrams were silently dropped, mid-frame EOF was silent). Fix: an owning InbandBridge (persistent reader + pending queue + fail-loud mid-frame EOF, the AssociateSession shape) threaded through the channel->socket pump; pinned by three bridge unit tests (which fail against the per-call reader) and an end-to-end doubled-echo door-udp test. - R-2 (convention 2): seven non-test expects -> typed errors — DoorBuildError (both door builders' .build() is now Result), ProducerDoorBuildError/ProducerDoorError (the bind decision is serve's typed error), the composed table invariant as an egress error, register_forwarded_serving -> Result (the alkcall diagnostic surfaced), TokenClientError (wrap on a spent client). New error types re-exported; test call sites updated. - R-3/R-4 (doc residues): producer.md's local-backend section described a channel pipe — the landed ProducerDoor serves serve_socks5_over on the accepted socket directly; associate_with_token's doc (the TCP door refuses ASSOCIATE, never calls it); SessionOwner's doc (the accept uses SyncHalves/ OwnedWrite). Verification: cargo test (default) green; cargo test --all-features green; cargo clippy --all-targets [--all-features] -- -D warnings clean; cargo fmt --check clean; both wasm checks clean (default + composed); local-on-wasm fails at mio as designed; cargo doc --no-deps clean. Task: tasks/implementation/review-assembly-layer.md (status: completed; the batch-2 gate opens release polish).
This commit is contained in:
1 parent
1addedfdd0
commit
04c76e3a41
15 files changed
+767
-133
No files matched your search
+79
-6
@@ -100,7 +100,10 @@ async fn udp_door_vanilla_client_round_trip_and_empty_datagram() {
|
||||
let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
|
||||
let relay_addr = relay.local_addr().expect("relay addr");
|
||||
let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
|
||||
let door = UdpFrontDoor::builder().bind(relay_addr).build();
|
||||
let door = UdpFrontDoor::builder()
|
||||
.bind(relay_addr)
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let _serve = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move { door.serve_on(relay, client).await.expect("the door serves") }
|
||||
@@ -165,6 +168,65 @@ async fn udp_door_vanilla_client_round_trip_and_empty_datagram() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The reader-state pin through the door's bridge (review 003 R-1,
|
||||
/// the POC #2 finding carried to the doors): two replies arriving
|
||||
/// back-to-back (the doubled echo — both frames ride the producer's
|
||||
/// frame writer; the door's channel read may batch them into one
|
||||
/// chunk) both reach the vanilla client. A bridge that re-created
|
||||
/// its decoder per read lost the second datagram.
|
||||
#[tokio::test]
|
||||
async fn batched_in_band_replies_both_reach_the_vanilla_client() {
|
||||
let echo_addr = udp_echo_server().await;
|
||||
let topo = harness::wire_consumer_side_with(
|
||||
echo_dial(),
|
||||
Some(harness::doubled_echo_egress_factory()),
|
||||
None,
|
||||
Some(harness::consumer_identity()),
|
||||
)
|
||||
.await;
|
||||
|
||||
let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
|
||||
let relay_addr = relay.local_addr().expect("relay addr");
|
||||
let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
|
||||
let door = UdpFrontDoor::builder()
|
||||
.bind(relay_addr)
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let _serve = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move { door.serve_on(relay, client).await.expect("the door serves") }
|
||||
});
|
||||
|
||||
// One datagram in → two echo datagrams out (both from the relay
|
||||
// socket, both carrying the target as their source address — the
|
||||
// bridge's pending queue drained in order, none lost).
|
||||
client
|
||||
.send_to(&rfc_datagram(echo_addr, b"once"), relay_addr)
|
||||
.await
|
||||
.expect("send");
|
||||
let mut rx = vec![0u8; 65535];
|
||||
for _ in 0..2 {
|
||||
let (n, from) = timeout(BOUND, client.recv_from(&mut rx))
|
||||
.await
|
||||
.expect("reply within bound")
|
||||
.expect("recv");
|
||||
assert_eq!(from, relay_addr, "the reply comes from the relay socket");
|
||||
let (addr, payload) = parse_rfc_datagram(&rx[..n]);
|
||||
assert_eq!(addr, echo_addr);
|
||||
assert_eq!(payload, b"once");
|
||||
}
|
||||
|
||||
// No third reply: exactly the two echoes arrived (the burst was
|
||||
// queued, not duplicated).
|
||||
let mut probe = vec![0u8; 65535];
|
||||
assert!(
|
||||
timeout(Duration::from_millis(300), client.recv_from(&mut probe))
|
||||
.await
|
||||
.is_err(),
|
||||
"exactly two replies arrived"
|
||||
);
|
||||
}
|
||||
|
||||
/// FRAG ≠ 0 is refused at the door (the v1 posture): the fragment is
|
||||
/// dropped — nothing is egressed — and the association stays healthy
|
||||
/// (a following normal datagram round-trips).
|
||||
@@ -182,7 +244,10 @@ async fn frag_nonzero_refused_and_association_stays_healthy() {
|
||||
let relay = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay");
|
||||
let relay_addr = relay.local_addr().expect("relay addr");
|
||||
let client = UdpSocket::bind("127.0.0.1:0").await.expect("client socket");
|
||||
let door = UdpFrontDoor::builder().bind(relay_addr).build();
|
||||
let door = UdpFrontDoor::builder()
|
||||
.bind(relay_addr)
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let _serve = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move { door.serve_on(relay, client).await.expect("the door serves") }
|
||||
@@ -253,7 +318,8 @@ async fn idle_bound_closes_an_idle_association_and_a_fresh_one_succeeds() {
|
||||
let door = UdpFrontDoor::builder()
|
||||
.bind(relay.local_addr().unwrap())
|
||||
.idle(Duration::from_millis(300))
|
||||
.build();
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let serve = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move { door.serve_on(relay, client).await.expect("the door serves") }
|
||||
@@ -285,7 +351,10 @@ async fn idle_bound_closes_an_idle_association_and_a_fresh_one_succeeds() {
|
||||
// is healthy — the POC's strongest observable).
|
||||
let relay2 = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay 2");
|
||||
let relay2_addr = relay2.local_addr().unwrap();
|
||||
let door2 = UdpFrontDoor::builder().bind(relay2_addr).build();
|
||||
let door2 = UdpFrontDoor::builder()
|
||||
.bind(relay2_addr)
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let _serve2 = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move {
|
||||
@@ -332,7 +401,8 @@ async fn fresh_association_succeeds_after_teardown() {
|
||||
let door = UdpFrontDoor::builder()
|
||||
.bind(relay_addr)
|
||||
.idle(Duration::from_millis(200))
|
||||
.build();
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let serve = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move { door.serve_on(relay, client).await.expect("the door serves") }
|
||||
@@ -358,7 +428,10 @@ async fn fresh_association_succeeds_after_teardown() {
|
||||
// A fresh association on the same topology succeeds end to end.
|
||||
let relay2 = UdpSocket::bind("127.0.0.1:0").await.expect("bind relay 2");
|
||||
let relay2_addr = relay2.local_addr().expect("relay2 addr");
|
||||
let door2 = UdpFrontDoor::builder().bind(relay2_addr).build();
|
||||
let door2 = UdpFrontDoor::builder()
|
||||
.bind(relay2_addr)
|
||||
.build()
|
||||
.expect("the door builds");
|
||||
let serve2 = tokio::spawn({
|
||||
let client = Arc::clone(&topo.consumer);
|
||||
async move {
|
||||
|
||||
Reference in new issue
Block a user