secsi: T3 / T4 enforcement moved into the FSM
The SECS-I Protocol FSM now enforces T3 (reply timeout) and T4
(inter-block timeout) directly, instead of leaving them as
upper-layer hooks.
T3: on complete_send, if the block we just acked had W=1, record its
system_bytes in awaiting_reply_sys_ and emit ActionStartTimer{T3}.
deliver_recv cancels T3 when a block arrives whose system_bytes
match the outstanding request. EventTimeout{T3} aborts the FSM with
"T3 reply timeout".
T4: deliver_recv emits ActionStartTimer{T4} whenever the delivered
block has end_block=false. The next block's deliver_recv cancels
the timer; EventTimeout{T4} aborts with "T4 inter-block timeout".
abort() now also cancels T3/T4 and clears the tracking state.
Test changes:
- Old "T3/T4 are FSM-level no-ops" test → REPLACED by four new
tests: T3 arm+expire, T3 arm+matching-reply cancels, T4
arm+expire, T4 arm+next-block cancels.
- Two new observer accessors on Protocol (awaiting_reply,
awaiting_next_block) so the tests can assert tracking state
without poking internals.
COMPLIANCE.md §1a: T3 + T4 rows go ⬜ → ✅.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,11 @@ class Protocol {
|
||||
// Test-only: peek the queue of blocks waiting to send.
|
||||
std::size_t pending_send_size() const { return send_queue_.size(); }
|
||||
|
||||
// Test/observer: whether we're currently awaiting a reply (T3 arm)
|
||||
// or the next block of a multi-block recv (T4 arm).
|
||||
bool awaiting_reply() const { return awaiting_reply_sys_.has_value(); }
|
||||
bool awaiting_next_block() const { return awaiting_next_block_; }
|
||||
|
||||
private:
|
||||
// Start of one send transaction (when send_queue_ non-empty and we're Idle).
|
||||
void begin_send(std::vector<Action>& out);
|
||||
@@ -122,6 +127,18 @@ class Protocol {
|
||||
// --- receive-side state ---
|
||||
std::vector<uint8_t> recv_buf_; // bytes collected since EOT
|
||||
std::size_t recv_expected_ = 0; // length byte + payload + checksum
|
||||
|
||||
// --- transaction-level state (T3 / T4) ---------------------------------
|
||||
// T3: when we send a block with W=1, we expect a reply block whose
|
||||
// system_bytes match. We track the outstanding system_bytes and arm
|
||||
// T3 in complete_send; deliver_recv cancels it when the matching reply
|
||||
// arrives, or T3 expires and we raise an error.
|
||||
std::optional<uint32_t> awaiting_reply_sys_;
|
||||
// T4: when a recv block delivers with end_block=false we expect at
|
||||
// least one more block in the same message. We arm T4 in
|
||||
// deliver_recv and cancel when the next block arrives (or T4 expires
|
||||
// and we abort).
|
||||
bool awaiting_next_block_ = false;
|
||||
};
|
||||
|
||||
const char* state_name(Protocol::State s);
|
||||
|
||||
Reference in New Issue
Block a user