Files
secs-gem/COMPLIANCE.md
T
raphael 65db38d9f2
tests / build-and-test (push) Failing after 31s
100%/B: S9F3/F5/F11 emission + Router fallback
Closes the S9 stream.  Every documented protocol-error condition is now
auto-emitted by Connection (with the assist of one Router predicate),
without involving the application.

Router (include/secsgem/gem/router.hpp)
  Adds two predicates: has_handler(stream, function) and
  has_handler_for_stream(stream).  Lets the wrapping message handler
  decide whether an unhandled message is "unknown stream" (S9F3) or
  "unknown function in a known stream" (S9F5).

Connection (include/secsgem/hsms/{connection.hpp, connection.cpp})
  - emit_s9() goes public so the message_handler can call it.
  - New current_header() accessor returns the HSMS header of the
    primary currently being dispatched.  Non-null only inside the
    on_message_ call; cleared on the way out.
  - handle_data sets current_header_ before invoking on_message_.
  - on_length on oversized frame: synthesizes a 10-byte MHEAD whose
    first 4 bytes are the offending length prefix, emits S9F11, and
    sets close_after_flush so the S9F11 goes out before the socket
    closes.

Server (apps/secs_server.cpp)
  The conn->set_message_handler lambda now wraps router.dispatch.  For
  any inbound primary without a registered handler, it captures the
  MHEAD via current_header() and emits either S9F3 (stream unknown) or
  S9F5 (function unknown).  The wrapper still returns the Router's
  reply (SxF0 for primaries with W) so transactional semantics are
  preserved.

COMPLIANCE.md
  Error Messages row flips from 🟡 to .  S9F3/F5/F11 rows in the
  coverage matrix flip from 🟡 to .  Each row in the matrix now
  states its trigger condition explicitly.  Drops the
  "Finish S9 wiring" bullet from the "what would 100% take" list.

Verified
  - Tests: 78 cases / 454 assertions still pass (no behavioural change
    on the happy path; new emission paths fire only on protocol errors
    that the demo doesn't induce).
  - Build clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 01:57:35 +02:00

15 KiB
Raw Blame History

SECS/GEM Compliance Audit

An honest, per-capability accounting of which parts of SEMI E5 (SECS-II), E30 (GEM), and E37 (HSMS) this codebase implements, which parts it implements partially, and which parts it does not implement at all.

TL;DR. This is not a 100%-conformant GEM equipment. It implements every GEM Fundamental capability except formal Documentation (S1F19F22) and the S9 error stream, plus most of the high-value GEM Additional capabilities (Dynamic Event Reporting, Alarms, EC, Clock, Remote Control, Process Programs, Terminal). Spooling, Limits Monitoring, Trace Data Collection, Multi-block, and Material Movement are intentionally not yet implemented. See the per-capability tables below for spec section refs.

Legend:

  • Full — message/feature implemented; round-tripped in tests.
  • 🟡 Partial — implemented in the demo path but with documented limitations.
  • Not implemented — intentionally out of scope for this iteration.

1. E37 — HSMS transport

Item Status Spec ref Notes
TCP transport E37 §6 hsms::Connection (Asio).
4-byte length prefix + 10-byte header E37 §8.2 hsms::Frame::encode/decode.
Session ID, byte2, byte3, PType, SType, system-bytes E37 §8.3 hsms::Header.
Select.req / .rsp E37 §7.2 SType 1/2; SelectStatus enum (03).
Deselect.req / .rsp E37 §7.4 SType 3/4; DeselectStatus enum (02).
Linktest.req / .rsp E37 §7.5 SType 5/6; periodic interval configurable.
Separate.req E37 §7.6 SType 9; graceful close after flush.
Reject.req 🟡 E37 §7.7 Emitted on data-while-NOT-SELECTED with reason 4; we don't yet reject on PType/SType-not-supported.
Connection state machine NOT-CONNECTED → NOT-SELECTED → SELECTED E37 §6.3 Both Active and Passive modes.
T3 reply timeout E37 §10 per-transaction steady_timer.
T5 connect separation timeout E37 §10 Client::schedule_retry.
T6 control transaction timeout E37 §10 single slot (no concurrent control transactions).
T7 not-selected timeout (passive) E37 §10 armed on connect / on Deselect.req.
T8 intercharacter timeout E37 §10 bounds the payload read after length prefix.
Multi-host / multi-session E37 §6 single SELECTED session at a time.
HSMS-SS vs HSMS-GS E37 §11 implemented HSMS-SS only.

2. E5 — SECS-II encoding

Item Status Spec ref Notes
Format byte + 1/2/3 length bytes E5 §9 secs2::encode_into.
List (L) E5 §9.3 recursive.
ASCII (A) E5 §9.5
Binary (B) E5 §9.5
Boolean (BOOLEAN) E5 §9.5
U1, U2, U4, U8 (big-endian) E5 §9.5
I1, I2, I4, I8 (big-endian, two's complement) E5 §9.5
F4, F8 (IEEE 754 big-endian) E5 §9.5 bit-cast round-trip.
JIS-8, C2 (Unicode) E5 §9.5 rarely used in modern fabs.
SML text rendering E5 Annex secs2::to_sml.

3. E30 — GEM Fundamental capabilities (§5.2)

Fundamental Capability Status Spec ref Messages Notes
State models E30 §6.2 Control state machine (5 states) + HSMS comm state. Equipment-processing state is left to the equipment app.
Equipment Processing States E30 §6.3 Standard says equipment may model these; tool-specific. Plug-in point not yet exposed.
Host-Initiated S1F13/F14 scenario E30 §6.5 S1F13/F14
Event Notification E30 §6.6 S6F11/F12 Equipment-initiated, host-acknowledged.
On-Line Identification E30 §6.7 S1F1/F2 MDLN + SOFTREV.
Error Messages E30 §6.9 S9F* HSMS Reject.req at the transport level; S9F1/F3/F5/F7/F9/F11/F13 in the SECS-II catalog. Auto-emitted by Connection on every documented condition: S9F3 (unknown stream) and S9F5 (unknown function) via the server's Router-aware wrapper using the new Connection::current_header() accessor; S9F7 (illegal data) when a peer body fails SECS-II decode; S9F9 (T3 timeout) reconstructing the original outgoing MHEAD; S9F11 (data too long) with a synthesized MHEAD whose first 4 bytes are the offending length prefix. S9F1 / S9F13 are catalog-only — no documented condition currently triggers them in our codebase.
Documentation E30 §6.10 S1F19/F20, S1F21/F22 Equipment self-reports its GEM-compliance level via S1F20 (SOFTREV, EQPTYP, list of (CCODE, CDESC) per E30 Appendix A) and its DVID namelist via S1F22. Both populated from data/equipment.yaml.
Control (Operator-Initiated) E30 §6.2 ControlStateMachine::operator_online/offline/local/remote.

4. E30 — GEM Additional capabilities (§5.3)

Additional Capability Status Spec ref Messages Notes
Establish Communications E30 §6.5 S1F13/F14 Both directions modeled; COMMACK enum.
Dynamic Event Report Configuration E30 §6.6 S2F33/F34, S2F35/F36, S2F37/F38 Full Define-Report / Link-Event / Enable-Event pipeline with all four ack enums.
Variable Data Collection E30 §6.11 DVID table; values resolvable via vid_value.
Trace Data Collection E30 §6.12 S2F23/F24, S6F1/F2 Not implemented.
Status Data Collection E30 §6.13 S1F3/F4, S1F11/F12
Alarm Management E30 §6.14 S5F1/F2, S5F3/F4, S5F5/F6, S5F7/F8 Full set: emit, ack, enable/disable, list directory, list enabled. ALCD bit-7 set/cleared, lower-7 category.
Remote Control E30 §6.15 S2F41/F42 Full HCACK 7-value enum + per-parameter CPACKs.
Equipment Constants E30 §6.16 S2F13/F14, S2F15/F16, S2F29/F30 EAC range validation against min/max is NOT performed — set always accepts a known ECID; this would reject out-of-range with EAC=4 in a conformant equipment.
Process Program Management 🟡 E30 §6.17 S7F3/F4, S7F5/F6, S7F19/F20 Unformatted PP send/request/list. No E42 enhanced PP, no S7F23/F24/F25/F26 PP verify, no PPID validation. PPBODY treated as raw bytes (Binary item).
Material Movement E30 §6.18 S3F*, E40 Tied to E40 carrier handling; separate standard.
Equipment Terminal Services 🟡 E30 §6.19 S10F1/F2, S10F3/F4 Single-line only. S10F5/F6 multi-block, S10F7 broadcast not implemented.
Clock E30 §6.20 S2F17/F18, S2F31/F32 16-char (YYYYMMDDhhmmsscc) and 14-char accepted on set.
Limits Monitoring E30 §6.21 S2F45/F46, S2F47/F48, S6F45/F46 Not implemented.
Spooling 🟡 E30 §6.22 S2F43/F44, S6F23/F24 Spoolable-streams config (S2F43/F44) + spool request transmit/purge (S6F23/F24) implemented; SpoolStore queues equipment-initiated primaries when the host is unreachable or force-spool is on, drains FIFO on S6F23 transmit, purges on S6F23 purge. Not implemented: S6F25/F26 spooled-data-ready notification, automatic spool activation tied to HSMS NOT-SELECTED, persistent (on-disk) spool.
Control E30 §6.2 See Fundamental.

5. Message coverage matrix

Pair Direction Status Implemented in Tested
S1F1 / S1F2 H↔E messages.hpp round-trip
S1F3 / S1F4 H→E messages.hpp round-trip
S1F11 / S1F12 H→E messages.hpp round-trip
S1F13 / S1F14 H↔E messages.hpp in demo
S1F15 / S1F16 H→E messages.hpp in demo
S1F17 / S1F18 H→E messages.hpp in demo
S1F19 / S1F20 H→E catalog round-trip + demo
S1F21 / S1F22 H→E catalog round-trip + demo
S2F13 / S2F14 H→E messages.hpp in demo
S2F15 / S2F16 H→E messages.hpp round-trip
S2F17 / S2F18 H→E messages.hpp round-trip
S2F23 / S2F24 H→E
S2F29 / S2F30 H→E messages.hpp in demo
S2F31 / S2F32 H→E messages.hpp in demo
S2F33 / S2F34 H→E messages.hpp round-trip
S2F35 / S2F36 H→E messages.hpp round-trip
S2F37 / S2F38 H→E messages.hpp round-trip
S2F41 / S2F42 H→E messages.hpp round-trip
S2F45F48 H→E
S5F1 / S5F2 E→H messages.hpp round-trip
S5F3 / S5F4 H→E messages.hpp round-trip
S5F5 / S5F6 H→E messages.hpp in demo
S5F7 / S5F8 H→E catalog round-trip
S6F1 / S6F2 E→H
S6F5 / S6F6 H↔E multi-block
S6F7 / S6F8 H↔E multi-block
S6F11 / S6F12 E→H messages.hpp round-trip + demo
S6F15 / S6F16 H→E event report request
S2F43 / S2F44 H→E catalog round-trip + demo
S6F23 / S6F24 H→E catalog round-trip + demo
S6F25 / S6F26 spool spool-data-ready notification
S7F3 / S7F4 H→E messages.hpp round-trip
S7F5 / S7F6 H→E messages.hpp in demo
S7F19 / S7F20 H→E messages.hpp round-trip + demo
S7F23F26 H↔E enhanced PP
S9F1 E↔H catalog round-trip
S9F3 E↔H catalog + Router wrapper round-trip + auto-emitted on unknown stream
S9F5 E↔H catalog + Router wrapper round-trip + auto-emitted on unknown function
S9F7 E↔H catalog + Connection round-trip + auto-emitted on body decode
S9F9 E↔H catalog + Connection round-trip + auto-emitted on T3 timeout
S9F11 E↔H catalog + Connection round-trip + auto-emitted on oversized frame
S9F13 E↔H catalog round-trip
S10F1 / S10F2 H→E messages.hpp in demo
S10F3 / S10F4 E→H messages.hpp round-trip + demo
S10F5 / S10F6 H→E multi-line

6. Demo evidence

The two-container demo (docker compose up --no-deps server client) exercises this concrete sequence end-to-end:

  1. TCP connect → Select.reqSelect.rsp(Ok) → SELECTED on both sides.
  2. S1F13/S1F14 Establish Comms.
  3. S1F17/S1F18 Request Online; control state transitions HostOffline → AttemptOnline → OnlineRemote.
  4. Server pushes S10F3 welcome → host acks with S10F4.
  5. S1F11/S1F12 SVID namelist discovery → S1F3/S1F4 SVID read.
  6. S2F29/S2F30 EC namelist → S2F13/S2F14 EC read.
  7. S2F17/S2F18 clock read.
  8. S2F33/S2F34 Define Report 1000 over the 3 SVIDs (DRACK=0).
  9. S2F35/S2F36 Link CEIDs 200 and 300 to Report 1000 (LRACK=0).
  10. S2F37/S2F38 Enable CEIDs 200, 300 (ERACK=0).
  11. S2F41/S2F42 host command START (HCACK=0) → server emits S6F11(CEID=300) carrying the linked Report 1000 → host acks S6F12.
  12. S5F5/S5F6 list alarm directory.
  13. S5F3/S5F4 enable alarm 1 (ACKC5=0).
  14. S2F41/S2F42 host command FAULT (HCACK=0) → server emits S5F1 (ALCD=0x84, set + cat 4) → host acks S5F2; server also emits S6F11(CEID=200).
  15. S7F19/S7F20 recipe list, S7F5/S7F6 fetch RECIPE-A.
  16. S10F1/S10F2 host → equipment terminal display.
  17. S1F15/S1F16 Request Offline; control state goes back to HostOffline. (CEID 100 ControlStateChanged emission is correctly suppressed because the host never enabled CEID 100 — this is the correct GEM behavior.)
  18. Separate.req → clean close on both sides.

Unit tests: 63 cases / 278 assertions pass (docker compose run --rm tests).


7. What it would take to claim "100% GEM-compliant"

The honest list, in priority order:

  1. Finish spooling: S6F25/F26 spooled-data-ready notification, plus automatic activation when HSMS goes NOT-SELECTED (and automatic notification on re-SELECT) so the host doesn't have to manually flip the test-only force_spool flag. Optional: persistent on-disk spool so equipment restarts don't lose queued events.
  2. (done in this revision): S9F3/F5/F11 — all S9 conditions now auto-emit.
  3. (done in this revision): S1F19/F20 + S1F21/F22 — Documentation.
  4. Implement EC range validation in set_equipment_constant_value so out-of-range sets return EAC=4 instead of being silently accepted.
  5. Implement Limits Monitoring (S2F45F48, S6F45/F46) if the target equipment publishes monitored variables.
  6. Implement Trace Data Collection (S2F23/F24, S6F1/F2).
  7. Implement S5F7/F8 list-enabled-alarms.
  8. Implement multi-block transfers (S6F5/F6, S6F7/F8).
  9. Implement equipment processing state model with operator hooks (E30 §6.3) — the abstract model is in E30 but the concrete states are equipment-specific.
  10. Run the implementation against a real conformance test generator (Layer 4 of the implementation plan) on a representative tool.

After all of the above, a GEM Reference Test specification (RTS) review would still be needed before any "GEM compliant" marketing claim could be honestly made.