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>
Each Substrate now retains an append-only history of state transitions
(both location and processing axes), the triggering event captured as
a std::variant<SubstrateEvent, SubstrateProcessingEvent>, the location
label at the time, and a steady_clock timestamp.
E90 §6.6 requires the equipment to be able to report a wafer's
processing history — typically queried via S6F11 batched reports or
SVID reads. This commit lays the runtime substrate; wire query
plumbing is the natural follow-up.
set_history_limit(n) caps per-substrate retention (default 256, 0 =
unbounded). Oldest entries are dropped when the cap is reached;
vector-erase is fine at this scale (typical wafer lifecycle is a few
dozen transitions).
Two new test cases cover the recording invariants (every fire results
in one history entry on the right axis) and history_limit eviction.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>