Chapter 14 deterministic selective-repeat teaching simulation, 2026-09-20 Run: python3 arq.py Standard library only. This is not TCP, TFTP or an implemented network protocol. No sockets, threads, wall-clock sleeps, checksum, serialization or external I/O. Six immutable ASCII blocks: block-0; through block-5;. Sender window width3 is anchored at the earliest unacknowledged block base; next cannot exceed base+3. A block acknowledged out of order does not itself open a slot beyond that edge. Each sent block has a separate deadline at current_tick+4. At expiration, its retry count is checked before sending; maximum4 transmissions includes first. DATA/ACK normal delivery takes one simulated tick. Due events are processed before timeout checks at the same tick. Events at equal tick retain insertion order through a monotonically increasing serial. These are modeling rules, not measured network RTT, recommended RTO or a congestion-control algorithm. Combined case: first DATA1 dropped, first ACK1 and ACK5 dropped, first DATA2 duplicated (second copy one tick later), first DATA0 delayed three ticks. Every DATA event carries immutable payload bytes; ACK events carry empty bytes. The receiver caches event payloads by block number and delivers their contiguous prefix, and ACKs duplicates even after receiving all blocks. Final sender confirmation is tick16; attempts [1,3,1,1,1,2]. Application bytes equal concatenated originals, and delivery order is [0,1,2,3,4,5]. receiver_complete means every unique block number has been received; application_matches separately compares actual delivered bytes with the source bytes. Receiver completeness and sender success are recorded separately in result.json; the receiver becomes complete earlier. Permanent-loss case drops every DATA2. At tick16, four sends have exhausted its allowance: explicit attempt-limit-block-2. Attempts [1,2,4,1,1,0]; only [0,1] is delivered to the application. Cached later blocks are not silently called delivered. Both sender success and receiver completeness are false. Deduplication counterexample uses the same ACK-loss-only trajectory for both receivers: first ACK1 and ACK5 dropped, no DATA reordering or DATA drop. The sender transmissions and received ACK events are asserted identical. Protected application delivery is [0,1,2,3,4,5]. Unprotected delivery directly appends every DATA arrival, giving [0,1,2,3,1,4,5,5]. Its output bytes are built from the actually received and delivered payload bytes, never reconstructed from source BLOCKS or a final deduplicating dictionary. Both senders see all ACKs at tick12, but unprotected application content is wrong. Bounds: six blocks, sender window3, receiver cache<=3, maximum4 sends/block, queue<=64, processed events<=200, simulated tick<=100. Queue/event overrun raises an assertion instead of unbounded work; tick exhaustion is a failed result. These limits are resource guards for this selected finite trace, not a proof of convergence or reliable completion under arbitrary loss. Receiver stop is coordinated by this in-process simulator; no distributed close/linger handshake, session identity, sequence-number wrap or stale cross-session packet is modeled. Verified default run, byte-identical repeat, --help exit0 and --bad exit2. Python no-excuse checker zero violations. No public/production end-to-end or real retransmission timing, fairness, throughput or congestion claim is made.