K2: SubstrateIDStatus (third E90 axis)
Adds the substrate-ID verification FSM that E90 §6.4.6 calls for: NotConfirmed initial; equipment hasn't read the ID yet WaitingForHost ID has been read; awaiting host accept/reject Confirmed host confirmed (or force-bound) Mismatched host rejected — recoverable via Bind Events: Read NotConfirmed -> WaitingForHost Confirm WaitingForHost -> Confirmed Mismatch WaitingForHost -> Mismatched Bind any -> Confirmed (force-bind) Reset any -> NotConfirmed Wire-byte values pinned via static_assert. The third axis is now exposed on SubstrateStateMachine alongside location_state() and processing_state(); set_id_handler() observes transitions. Existing two-axis API is unchanged. 4 new test cases cover the happy path, Mismatch+Bind recovery, Reset from any state, and same-state event handler suppression. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,48 @@ TEST_CASE("SubstrateStore: create + dedup + location update") {
|
||||
CHECK(s.get("W-001")->fsm->location_state() == SubstrateState::AtWork);
|
||||
}
|
||||
|
||||
// ---- Substrate ID Status (E90 §6.4.6) -----------------------------------
|
||||
|
||||
TEST_CASE("Substrate IDS: NotConfirmed -> WaitingForHost -> Confirmed") {
|
||||
SubstrateStateMachine s;
|
||||
CHECK(s.id_state() == SubstrateIDStatus::NotConfirmed);
|
||||
CHECK(s.on_id_event(SubstrateIDEvent::Read));
|
||||
CHECK(s.id_state() == SubstrateIDStatus::WaitingForHost);
|
||||
CHECK(s.on_id_event(SubstrateIDEvent::Confirm));
|
||||
CHECK(s.id_state() == SubstrateIDStatus::Confirmed);
|
||||
}
|
||||
|
||||
TEST_CASE("Substrate IDS: Mismatch + Bind recovers") {
|
||||
SubstrateStateMachine s;
|
||||
s.on_id_event(SubstrateIDEvent::Read);
|
||||
CHECK(s.on_id_event(SubstrateIDEvent::Mismatch));
|
||||
CHECK(s.id_state() == SubstrateIDStatus::Mismatched);
|
||||
CHECK(s.on_id_event(SubstrateIDEvent::Bind));
|
||||
CHECK(s.id_state() == SubstrateIDStatus::Confirmed);
|
||||
}
|
||||
|
||||
TEST_CASE("Substrate IDS: Reset from any state returns to NotConfirmed") {
|
||||
SubstrateStateMachine s;
|
||||
s.on_id_event(SubstrateIDEvent::Read);
|
||||
s.on_id_event(SubstrateIDEvent::Confirm);
|
||||
CHECK(s.on_id_event(SubstrateIDEvent::Reset));
|
||||
CHECK(s.id_state() == SubstrateIDStatus::NotConfirmed);
|
||||
}
|
||||
|
||||
TEST_CASE("Substrate IDS: change handler observes transitions only") {
|
||||
SubstrateStateMachine s;
|
||||
int calls = 0;
|
||||
s.set_id_handler([&](SubstrateIDStatus, SubstrateIDStatus, SubstrateIDEvent) {
|
||||
++calls;
|
||||
});
|
||||
s.on_id_event(SubstrateIDEvent::Read);
|
||||
s.on_id_event(SubstrateIDEvent::Confirm);
|
||||
CHECK(calls == 2);
|
||||
// Re-confirming from Confirmed: no row, no call.
|
||||
s.on_id_event(SubstrateIDEvent::Confirm);
|
||||
CHECK(calls == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("SubstrateStore: history records every transition") {
|
||||
SubstrateStore s;
|
||||
s.create("W-H", "CAR-X", 3);
|
||||
|
||||
Reference in New Issue
Block a user