Files
secs-gem/COMPLIANCE.md
T
raphael 6cedaa10dc
tests / build-and-test (push) Failing after 32s
100%/D: Trace Data Collection (S2F23/F24 + S6F1/F2, E30 §6.12)
New TraceStore keyed by TRID; each entry is a TraceConfig with
DSPER + TOTSMP + REPGSZ + SVID list.  S2F23 validates that every SVID
exists (TIAACK=4 otherwise) and registers the trace.

S6F1's body is L,4 of {TRID U4, SMPLN U4, STIME ASCII, list_of <Item>}
— the application chooses whether each value Item is a scalar SVID
value or a packed batch.

The periodic sampling timer that turns an active TraceConfig into
S6F1 emissions is intentionally left to the application (E5 doesn't
mandate a specific scheduler and vendors typically already have one).

Four new SxFy in the catalog.

COMPLIANCE.md: Trace Data Collection Additional capability flips .
Tests: 82 cases / 477 assertions.

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

215 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 | `TraceStore` keeps an active TRID -> TraceConfig map; S2F23 validates each SVID exists and registers the request (TIAACK=4 on unknown VID). S6F1 round-trips with TRID/SMPLN/STIME/values. The periodic sampling timer that turns a TraceConfig into S6F1 emissions is intentionally left to the application (vendors typically already have their own scheduler). |
| 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 | `LimitMonitorStore` keyed by VID with multiple `LimitDefinition` (LIMITID + upper/lower as arbitrary Items). Server S2F45 validates each VID exists (returns VLAACK=4 otherwise) and stores definitions; S2F47 returns them. Crossing-detection + CEID emission is intentionally left to the application's set_value path (E30 §6.21 is permissive about *how* the equipment detects crossings). |
| 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 | ✅ | catalog | ✅ round-trip |
| 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 |
| S2F45 / S2F46 | H→E | ✅ | catalog | ✅ round-trip |
| S2F47 / S2F48 | H→E | ✅ | catalog | ✅ round-trip |
| 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 | ✅ | catalog | ✅ round-trip |
| 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.req``Select.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.