E1: SubstrateStateMachine + SubstrateStore (E90 §6)

Per-substrate dual FSM with two orthogonal axes:

  Location (STS):
    AtSource -> AtWork (Acquire) -> AtDestination (Release)
    AtWork  -> AtSource (Return; processing aborted before completion)

  Processing:
    NeedsProcessing -> InProcess (Start) -> Processed (End)
    InProcess -> {Aborted, Stopped, Rejected, Lost} terminal
    NeedsProcessing -> {Skipped, Lost} terminal

Wire-byte values pinned via static_assert to E90-0716 §10.3.

SubstrateStore mirrors the CarrierStore pattern: non-movable, per-row
SubstrateStateMachine heap-allocated with handlers dispatching through
the store's location/processing callbacks; fire_location_event accepts
an optional new_location string so the application can carry
equipment-specific module names alongside the FSM state.

Joins EquipmentDataModel alongside carriers / load_ports.  9 test
cases cover initial state, full location lifecycle, all five
processing exits, and store-level dual-axis observer firing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 00:49:31 +02:00
parent ff1a6b3726
commit 7c726ed9ba
6 changed files with 435 additions and 0 deletions
+2
View File
@@ -10,6 +10,7 @@
#include "secsgem/gem/store/host_commands.hpp"
#include "secsgem/gem/store/limits.hpp"
#include "secsgem/gem/store/process_jobs.hpp"
#include "secsgem/gem/store/substrates.hpp"
#include "secsgem/gem/store/recipes.hpp"
#include "secsgem/gem/store/spool.hpp"
#include "secsgem/gem/store/status_variables.hpp"
@@ -39,6 +40,7 @@ struct EquipmentDataModel {
ExceptionStore exceptions;
CarrierStore carriers;
LoadPortStore load_ports;
SubstrateStore substrates;
// Convenience: VID -> value lookup spanning SVIDs and DVIDs.
std::optional<s2::Item> vid_value(uint32_t vid) const {