docs: customer-ready sweep + README restructure + tshark CI fix

Audit pass over the public-facing surface so a customer can read it
end-to-end without tripping on stale numbers or self-contradictions.

README + docs accuracy:
- Test counts 426 → 445, assertions 2 557 → 2 753 (verified via
  doctest run); E5 row was missing test_e5_kat (19 cases)
- Interop checks 24 → 31, COMPLIANCE.md message count 149 → 164,
  COMPLIANCE.md "291 cases / 1515 assertions" → 445 / 2 753
- README "60+ test IDs" for MES_INTEROP → actual 59
- PVD example counts: 32 SVIDs/17 CEIDs → 29/21, "~40 handlers
  in ~200 lines" → 51 in ~460, "~700 lines" → ~1,100; main.cpp
  header table-of-contents resynced with the actual 7 sections

Out-of-scope honesty (COMPLIANCE.md §8 + FAQ.md):
- Removed HSMS-GS (was both  implemented in §1 and "out of scope"
  in §8; INTEGRATION.md §7 documents using it)
- Removed multi-block SECS-I (split_message/assemble_message exist
  with 4 dedicated tests)
- Added serial-port wiring as the genuine open  item — FSM is
  tested end-to-end over TCP; only the asio serial_port glue is
  deferred
- COMPLIANCE.md intro now lists E42 and notes "E37 (SS + GS)"

README restructure:
- Moved the 8-command proof table and per-standard test-coverage
  table to a new PROOFS.md (72 lines)
- README now leads with what / Quick start / Documentation map,
  then a one-paragraph "How it's proved" linking to PROOFS.md
- Updated cross-refs in FAQ.md, GLOSSARY.md, VERIFICATION.md, and
  interop/README.md to point at PROOFS.md

CI fix — tshark-dissector job:
- interop/tshark_validate.sh hardcoded /app/build/secs_server etc.
  which only works inside the docker image.  Now derives ROOT from
  the script's own location and accepts BUILD/SERVER/CLIENT/DATA
  env overrides, so CI can run it from the workspace dir
- Verified still passes in docker (69 frames, 0 malformed)

.gitignore:
- Added build-fuzz/ and build-tsan/ (were showing as untracked)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 18:59:17 +02:00
parent 6aa4427186
commit b031f057af
11 changed files with 143 additions and 95 deletions
+2
View File
@@ -1,4 +1,6 @@
build/ build/
build-fuzz/
build-tsan/
*.o *.o
*.obj *.obj
*.a *.a
+10 -10
View File
@@ -1,12 +1,13 @@
# SECS/GEM Compliance # SECS/GEM Compliance
A per-capability accounting against the foundational SEMI standards A per-capability accounting against the foundational SEMI standards
**E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS)**, **E4 (SECS-I)**, plus **E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS, SS + GS)**, **E4 (SECS-I)**,
the full GEM 300 stack: **E40** (process jobs), **E94** (control jobs), plus the full GEM 300 stack: **E40** (process jobs), **E42** (formatted
**E87** (carriers), **E90** (substrates), **E116** (equipment process programs), **E94** (control jobs), **E87** (carriers), **E90**
performance tracking), **E120** (common equipment model), **E157** (substrates), **E116** (equipment performance tracking), **E120** (common
(module process tracking), **E84** (parallel I/O), **E148** (time equipment model), **E157** (module process tracking), **E84** (parallel
synchronization), **E39** (object services), plus **E5 §13** wafer maps. I/O), **E148** (time synchronization), **E39** (object services), plus
**E5 §13** wafer maps.
> **Status.** Every GEM Fundamental and every GEM Additional capability > **Status.** Every GEM Fundamental and every GEM Additional capability
> that E30 binds to a concrete SECS-II message set is implemented, and > that E30 binds to a concrete SECS-II message set is implemented, and
@@ -227,7 +228,7 @@ Legend:
## 5. Message coverage matrix ## 5. Message coverage matrix
149 SECS-II messages in the catalog, spanning streams 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 16. 164 SECS-II messages in the catalog, spanning streams 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 16.
| Pair | Direction | Status | Notes | | Pair | Direction | Status | Notes |
|------------------|-----------|--------|-------| |------------------|-----------|--------|-------|
@@ -345,7 +346,7 @@ walks ~20 SECS transactions end-to-end:
23. `S1F15`/`S1F16` Request Offline. 23. `S1F15`/`S1F16` Request Offline.
24. `Separate.req` → clean close on both sides. 24. `Separate.req` → clean close on both sides.
Unit tests: **291 cases / 1515 assertions pass** (`docker compose run --rm tests`). Unit tests: **445 cases / 2753 assertions pass** (`docker compose run --rm tests`).
The suite includes integration tests that drive a real `hsms::Connection` The suite includes integration tests that drive a real `hsms::Connection`
over a loopback socket pair to verify the E37 §7.2 / §7.4 / §7.7 over a loopback socket pair to verify the E37 §7.2 / §7.4 / §7.7
edge cases — not just the happy path. edge cases — not just the happy path.
@@ -398,9 +399,8 @@ compliance claim.
| Item | Why it's out of scope | | Item | Why it's out of scope |
|---------------------------------------|----------------------| |---------------------------------------|----------------------|
| Multi-block SECS-I transfers | Multi-block is a **SECS-I** concept for 244-byte serial frames. HSMS allows arbitrarily large bodies (up to the codebase's 16 MiB cap), so multi-block is structurally not needed. E37-based GEM equipment does not require it. |
| HSMS-GS (multi-session) | Out of scope — modern HSMS-SS covers virtually all current GEM equipment. |
| Equipment Processing States (concrete states) | E30 §6.3 says the specific states are tool-defined. We provide the engine (`ControlTransitionTable` + the YAML loader); equipment vendors load their concrete states (IDLE / SETUP / READY / EXECUTING / PAUSE / …) the same way `data/control_state.yaml` is loaded today. Spec-compliant either way. | | Equipment Processing States (concrete states) | E30 §6.3 says the specific states are tool-defined. We provide the engine (`ControlTransitionTable` + the YAML loader); equipment vendors load their concrete states (IDLE / SETUP / READY / EXECUTING / PAUSE / …) the same way `data/control_state.yaml` is loaded today. Spec-compliant either way. |
| Serial-port wiring for SECS-I | The SECS-I FSM (`secsi::Protocol`) is fully implemented and tested end-to-end over the asio TCP transport (`secsi::TcpTransport`). The serial-port driver (asio `serial_port` wrapper around the same FSM) is a few hundred lines of straightforward wiring that hasn't been written yet — most modern GEM equipment runs HSMS. Plug it in by mirroring `TcpTransport`. |
--- ---
+7 -5
View File
@@ -210,7 +210,7 @@ Both are necessary; neither replaces the other. See VERIFICATION.md.
## How do I bring this to a customer site? ## How do I bring this to a customer site?
Run through the five external proofs in Run through the five external proofs in
[README's proof table](README.md#proof-of-feature-completeness) at [the eight commands in PROOFS.md](PROOFS.md) at
the customer's network. Then walk MES_INTEROP.md against their the customer's network. Then walk MES_INTEROP.md against their
actual MES. Then deploy per [SECURITY.md](SECURITY.md) for the actual MES. Then deploy per [SECURITY.md](SECURITY.md) for the
nftables / stunnel / signing setup. Then page on the metrics from nftables / stunnel / signing setup. Then page on the metrics from
@@ -219,7 +219,9 @@ INTEGRATION.md §6.4.
## What's not implemented? ## What's not implemented?
See [COMPLIANCE.md](COMPLIANCE.md) §8 ("Explicitly out of scope") See [COMPLIANCE.md](COMPLIANCE.md) §8 ("Explicitly out of scope")
for the honest list. The short version: multi-block SECS-I for the honest list. The short version: tool-specific Equipment
transfers (irrelevant on HSMS), tool-specific Equipment Processing Processing States (the engine is there, vendors plug in their
States (the engine is there, vendors plug in their states), and states), the serial-port driver for SECS-I (the FSM is wired
GEM RTS certification (paid third-party gate, not a code feature). end-to-end over TCP, the asio `serial_port` glue is a deferred
follow-up), and GEM RTS certification (paid third-party gate, not
a code feature).
+1 -1
View File
@@ -149,7 +149,7 @@ TA3 (BUSY duration) live alongside the signals — see
| **The router** | `gem::Router``(stream, function) → handler` dispatch table. | | **The router** | `gem::Router``(stream, function) → handler` dispatch table. |
| **The codec** | `secs2::encode` / `secs2::decode` for the wire bytes. | | **The codec** | `secs2::encode` / `secs2::decode` for the wire bytes. |
| **The catalog** | `data/messages.yaml` — every SECS-II message we ship, codegen'd to `messages.hpp`. | | **The catalog** | `data/messages.yaml` — every SECS-II message we ship, codegen'd to `messages.hpp`. |
| **The proof** | The 8 commands in [README.md](README.md#proof-of-feature-completeness). | | **The proof** | The 8 commands in [PROOFS.md](PROOFS.md). |
| **The bench** | `apps/secs_bench.cpp` — single-threaded throughput / latency / memory harness. | | **The bench** | `apps/secs_bench.cpp` — single-threaded throughput / latency / memory harness. |
| **The fuzz** | `tests/test_robustness_fuzz.cpp` — randomized property test of the model. | | **The fuzz** | `tests/test_robustness_fuzz.cpp` — randomized property test of the model. |
+72
View File
@@ -0,0 +1,72 @@
# Proof of feature-completeness
"Feature-complete" is a claim that the code must prove, not the
README. These eight commands are the proof. If they all exit zero
on a fresh clone, the codebase implements what
[COMPLIANCE.md](COMPLIANCE.md) claims.
| # | Command | What it proves |
|---|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| 1 | `docker compose run --rm tests` | **445 test cases / 2 753 assertions** pass: every store, FSM, codec, parser, persistence path |
| 2 | `docker compose run --rm builder /app/build/secs_conformance --host server --port 5000` | **47 wire-level conformance checks** PASS against a live passive equipment |
| 3 | `docker compose run --rm interop python3 /app/interop/host_vs_cpp_server.py --host server` | **31 interop checks** PASS against secsgem-py 0.3.0 (the Python reference impl) |
| 4 | `SECSGEM_ROBUSTNESS_SOAK=1 docker compose run --rm builder /app/build/secsgem_tests -tc='*soak*'` | **100 000 random tool operations** execute with all invariants and persistence round-trips holding |
| 5 | `docker compose run --rm builder /app/build/secs_server --validate-config --config /app/data/equipment.yaml --state-table /app/data/control_state.yaml --pj-state-table /app/data/process_job_state.yaml --cj-state-table /app/data/control_job_state.yaml` | Every shipped YAML config passes structural + referential validation |
| 6 | `docker compose run --rm builder bash /app/interop/tshark_validate.sh` | **69 HSMS frames** dissected by Wireshark's HSMS dissector (independent third codec) with no malformed packets |
| 7 | `bash interop/secs4j_validate.sh` | **55 cross-validation checks** PASS against [secs4java8](https://github.com/kenta-shimizu/secs4java8) (independent Java implementation), covering S1/S2/S3/S5/S6/S7/S10/S14/S16, the full E40 PJ body, dynamic event reports + unsolicited S6F11 / S5F1 observation, alarm management, spool, PP management, terminal services, limits, trace, E39, and the GEM 300 streams secsgem-py couldn't easily drive |
| 8 | `cmake -B build-fuzz -DSECSGEM_FUZZ=ON && build-fuzz/fuzz_secs2_decode -max_total_time=60` | **200 000+ random inputs** through `secs2::decode`, **1.4 M+** through `try_parse_sml` per 60 s lane, ASan + UBSan + libFuzzer coverage, **0 crashes** |
Plus, on every push to `main`, [Gitea Actions](.gitea/workflows/ci.yml)
runs both a **Release build + full test suite** and a separate
**ThreadSanitizer lane** that builds with `-fsanitize=thread` and
fails on any race. All 445 cases / 2 753 assertions pass under TSan
clean.
## Per-standard test coverage
Every claimed standard has dedicated tests. Counts are
`grep -c TEST_CASE`; cross-cutting tests (e.g. `test_robustness_fuzz`,
`test_gem300_scenario`) exercise multiple standards in concert.
| Standard | Test files | Cases |
|-----------------------------------|-------------------------------------------------------------------------------------------|------:|
| **E5** — SECS-II encoding | `test_secs2`, `test_sml`, `test_messages`, `test_e5_kat`, `test_identifier_wildcards`, `test_fuzz` | 139 |
| **E5 §13** — exceptions | `test_exceptions`, `test_exception_persistence` | 16 |
| **E4** — SECS-I transport | `test_secsi`, `test_secsi_timers`, `test_secsi_tcp` | 27 |
| **E37** — HSMS (SS + GS) | `test_hsms`, `test_hsms_connection`, `test_hsms_timers`, `test_hsms_s9`, `test_hsms_gs`, `test_hsms_gs_integration`, `test_s9_fallback`, `test_concurrency` | 34 |
| **E30** — GEM core | `test_control_state`, `test_communication_state`, `test_host_handler`, `test_data_model`, `test_loader`, `test_config_validate` | 71 |
| **E40** — process jobs | `test_process_jobs` | 21 |
| **E94** — control jobs | `test_control_jobs` | 9 |
| **E42** — formatted PP | `test_e42_formatted_pp` | 6 |
| **E87** — carriers + load ports | `test_carriers`, `test_carrier_state`, `test_carrier_persistence`, `test_e87_wire_scenarios` | 27 |
| **E90** — substrate tracking | `test_substrates`, `test_substrate_persistence` | 21 |
| **E116** — EPT | `test_ept` | 7 |
| **E120 / E39** — common equip / object service | `test_cem_objects` | 3 |
| **E157** — module process tracking | `test_modules` | 5 |
| **E84** — parallel I/O + timers | `test_e84`, `test_e84_ports`, `test_e84_timers`, `test_e84_asio_timers` | 27 |
| Persistence + cross-cutting | `test_job_persistence`, `test_persistence_upgrade`, `test_wire_ceid_emission`, `test_gem300_scenario`, `test_live_gem300`, `test_thread_safety`, `test_metrics_prometheus`, `test_robustness_fuzz` | 32 |
| **Total** | | **445** |
A single command to see this live: `docker compose run --rm builder
/app/build/secsgem_tests --list-test-cases | wc -l` (currently 445).
## What each proof actually demonstrates
The eight commands above split into four kinds of evidence:
- **Internal** (#1, #2, #4, #5) — our code testing our code: unit
suite, conformance harness, soak property test, config validator.
Necessary but not independent.
- **External, second implementation** (#3, #7) — round-trip against
secsgem-py 0.3.0 (Python) and secs4java8 (Java). Two independent
SECS implementations must agree with us on every frame.
- **External, third codec** (#6) — Wireshark's HSMS dissector,
written by network-protocol authors who don't share code with
either of us. Catches framing bugs the implementations might both
share.
- **External, structural search** (#8) — libFuzzer + ASan + UBSan
exploring the decoder and SML parser surface for crashes, memory
errors, and UB.
See [VERIFICATION.md](VERIFICATION.md) for the full test plan and
the rationale for each external validator.
+24 -56
View File
@@ -13,67 +13,13 @@ E157**.
--- ---
## Proof of feature-completeness
"Feature-complete" is a claim that the code must prove, not the
README. These five commands are the proof. If they all exit zero on
a fresh clone, the codebase implements what
[COMPLIANCE.md](COMPLIANCE.md) claims.
| # | Command | What it proves |
|---|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| 1 | `docker compose run --rm tests` | **426 test cases / 2 557 assertions** pass: every store, FSM, codec, parser, persistence path |
| 2 | `docker compose run --rm builder /app/build/secs_conformance --host server --port 5000` | **47 wire-level conformance checks** PASS against a live passive equipment |
| 3 | `docker compose run --rm interop python3 /app/interop/host_vs_cpp_server.py --host server` | **24 interop checks** PASS against secsgem-py 0.3.0 (the Python reference impl) |
| 4 | `SECSGEM_ROBUSTNESS_SOAK=1 docker compose run --rm builder /app/build/secsgem_tests -tc='*soak*'` | **100 000 random tool operations** execute with all invariants and persistence round-trips holding |
| 5 | `docker compose run --rm builder /app/build/secs_server --validate-config --config /app/data/equipment.yaml --state-table /app/data/control_state.yaml --pj-state-table /app/data/process_job_state.yaml --cj-state-table /app/data/control_job_state.yaml` | Every shipped YAML config passes structural + referential validation |
| 6 | `docker compose run --rm builder bash /app/interop/tshark_validate.sh` | **69 HSMS frames** dissected by Wireshark's HSMS dissector (independent third codec) with no malformed packets |
| 7 | `bash interop/secs4j_validate.sh` | **55 cross-validation checks** PASS against [secs4java8](https://github.com/kenta-shimizu/secs4java8) (independent Java implementation), covering S1/S2/S3/S5/S6/S7/S10/S14/S16, the full E40 PJ body, dynamic event reports + unsolicited S6F11 / S5F1 observation, alarm management, spool, PP management, terminal services, limits, trace, E39, and the GEM 300 streams secsgem-py couldn't easily drive |
| 8 | `cmake -B build-fuzz -DSECSGEM_FUZZ=ON && build-fuzz/fuzz_secs2_decode -max_total_time=60` | **~70 000 random inputs** through `secs2::decode`, **~285 000** through `try_parse_sml`, ASan + UBSan + libFuzzer coverage, **0 crashes** |
Plus, on every push to `main`, [Gitea Actions](.gitea/workflows/ci.yml)
runs both a **Release build + full test suite** and a separate
**ThreadSanitizer lane** that builds with `-fsanitize=thread` and
fails on any race. All 426 cases / 2 557 assertions pass under TSan
clean.
### Per-standard test coverage
Every claimed standard has dedicated tests. Counts are
`grep -c TEST_CASE`; cross-cutting tests (e.g. `test_robustness_fuzz`,
`test_gem300_scenario`) exercise multiple standards in concert.
| Standard | Test files | Cases |
|-----------------------------------|-------------------------------------------------------------------------------------------|------:|
| **E5** — SECS-II encoding | `test_secs2`, `test_sml`, `test_messages`, `test_identifier_wildcards`, `test_fuzz` | 120 |
| **E5 §13** — exceptions | `test_exceptions`, `test_exception_persistence` | 16 |
| **E4** — SECS-I transport | `test_secsi`, `test_secsi_timers`, `test_secsi_tcp` | 27 |
| **E37** — HSMS (SS + GS) | `test_hsms`, `test_hsms_connection`, `test_hsms_timers`, `test_hsms_s9`, `test_hsms_gs`, `test_hsms_gs_integration`, `test_s9_fallback`, `test_concurrency` | 34 |
| **E30** — GEM core | `test_control_state`, `test_communication_state`, `test_host_handler`, `test_data_model`, `test_loader`, `test_config_validate` | 71 |
| **E40** — process jobs | `test_process_jobs` | 21 |
| **E94** — control jobs | `test_control_jobs` | 9 |
| **E42** — formatted PP | `test_e42_formatted_pp` | 6 |
| **E87** — carriers + load ports | `test_carriers`, `test_carrier_state`, `test_carrier_persistence`, `test_e87_wire_scenarios` | 27 |
| **E90** — substrate tracking | `test_substrates`, `test_substrate_persistence` | 21 |
| **E116** — EPT | `test_ept` | 7 |
| **E120 / E39** — common equip / object service | `test_cem_objects` | 3 |
| **E157** — module process tracking | `test_modules` | 5 |
| **E84** — parallel I/O + timers | `test_e84`, `test_e84_ports`, `test_e84_timers`, `test_e84_asio_timers` | 27 |
| Persistence + cross-cutting | `test_job_persistence`, `test_persistence_upgrade`, `test_wire_ceid_emission`, `test_gem300_scenario`, `test_live_gem300`, `test_thread_safety`, `test_metrics_prometheus`, `test_robustness_fuzz` | 32 |
| **Total** | | **426** |
A single command to see this live: `docker compose run --rm builder
/app/build/secsgem_tests --list-test-cases | wc -l` (currently 426).
---
## Quick start ## Quick start
Everything runs in Docker — no compiler or build tools on the host. Everything runs in Docker — no compiler or build tools on the host.
```bash ```bash
docker compose run --rm builder # configure + compile docker compose run --rm builder # configure + compile
docker compose run --rm tests # 426 cases / 2 557 assertions docker compose run --rm tests # 445 cases / 2 753 assertions
docker compose up --no-deps server client # live two-container demo docker compose up --no-deps server client # live two-container demo
``` ```
@@ -89,9 +35,10 @@ through the data model. Watch the logs interleave.
| [COMPLIANCE.md](COMPLIANCE.md) | Per-capability audit against every SEMI standard implemented | | [COMPLIANCE.md](COMPLIANCE.md) | Per-capability audit against every SEMI standard implemented |
| [INTEGRATION.md](INTEGRATION.md) | Vendor-side tutorial: YAML → callbacks → production deploy | | [INTEGRATION.md](INTEGRATION.md) | Vendor-side tutorial: YAML → callbacks → production deploy |
| [ARCHITECTURE.md](ARCHITECTURE.md) | How the pieces fit + how to extend (new store / FSM / message) | | [ARCHITECTURE.md](ARCHITECTURE.md) | How the pieces fit + how to extend (new store / FSM / message) |
| [PROOFS.md](PROOFS.md) | The eight commands that prove the feature-completeness claim |
| [VERIFICATION.md](VERIFICATION.md) | Test plan for the external validators behind the proof table | | [VERIFICATION.md](VERIFICATION.md) | Test plan for the external validators behind the proof table |
| [BENCHMARKS.md](BENCHMARKS.md) | Performance envelope (throughput, latency, memory) + how to re-run | | [BENCHMARKS.md](BENCHMARKS.md) | Performance envelope (throughput, latency, memory) + how to re-run |
| [MES_INTEROP.md](MES_INTEROP.md) | Day-1 punch list to run against your commercial MES (60+ test IDs) | | [MES_INTEROP.md](MES_INTEROP.md) | Day-1 punch list to run against your commercial MES (59 test IDs) |
| [SECURITY.md](SECURITY.md) | Concrete configs: nftables, stunnel, minisign, SIEM audit-log schema | | [SECURITY.md](SECURITY.md) | Concrete configs: nftables, stunnel, minisign, SIEM audit-log schema |
| [GLOSSARY.md](GLOSSARY.md) | SEMI vocabulary: SVID, CEID, PPID, ALCD, HCACK, T-timers, … | | [GLOSSARY.md](GLOSSARY.md) | SEMI vocabulary: SVID, CEID, PPID, ALCD, HCACK, T-timers, … |
| [FAQ.md](FAQ.md) | Common questions and their canonical answers | | [FAQ.md](FAQ.md) | Common questions and their canonical answers |
@@ -100,6 +47,24 @@ through the data model. Watch the logs interleave.
--- ---
## How it's proved
"Feature-complete" is a claim that the code must prove, not the
README. On a fresh clone, **eight commands** demonstrate it:
unit + integration suite (445 cases / 2 753 assertions), a live
conformance harness (47 wire-level checks), interop against
secsgem-py (31 checks) and secs4java8 (55 checks), a 100 000-op
soak property test, YAML config validation, Wireshark's HSMS
dissector on a recorded pcap (69 frames, 0 malformed), and libFuzzer
(ASan + UBSan, 0 crashes). Each command, exit code, and the
external-vs-internal breakdown live in [PROOFS.md](PROOFS.md).
CI runs the full suite plus a separate ThreadSanitizer lane on
every push to `main` ([Gitea Actions](.gitea/workflows/ci.yml));
all 445 cases pass clean under `-fsanitize=thread`.
---
## Architecture ## Architecture
The project is **spec-as-data**: the SEMI behavioural rules live in The project is **spec-as-data**: the SEMI behavioural rules live in
@@ -142,6 +107,9 @@ YAML; the C++ is the engine that reads them.
secsgem::metrics Prometheus exporter (Registry + HTTP server). secsgem::metrics Prometheus exporter (Registry + HTTP server).
``` ```
See [ARCHITECTURE.md](ARCHITECTURE.md) for how to extend it (new
store / FSM / message).
--- ---
## Adding a capability ## Adding a capability
+4 -5
View File
@@ -1,13 +1,12 @@
# External verification plan # External verification plan
The five proofs in [README.md](README.md#proof-of-feature-completeness) The proofs in [PROOFS.md](PROOFS.md) are mostly **us testing us**:
are mostly **us testing us**:
| Proof | Independence | | Proof | Independence |
|--------------------------------|--------------------------------------------------------------| |--------------------------------|--------------------------------------------------------------|
| 426 unit/integration tests | Internal — our code testing our code | | 445 unit/integration tests | Internal — our code testing our code |
| 47 conformance harness checks | Internal — our host driving our server | | 47 conformance harness checks | Internal — our host driving our server |
| 24 secsgem-py interop checks | **External**, but covers ~1520 % of the claimed wire surface | | 31 secsgem-py interop checks | **External**, but covers ~1520 % of the claimed wire surface |
| 100 k random tool ops | Internal — property test of our model | | 100 k random tool ops | Internal — property test of our model |
| YAML validation | Internal — our validator on our YAML | | YAML validation | Internal — our validator on our YAML |
@@ -273,7 +272,7 @@ After all four:
| Proof channel | Independence | | Proof channel | Independence |
|--------------------------------|------------------------------------------------------| |--------------------------------|------------------------------------------------------|
| 426 unit/integration tests | Internal | | 445 unit/integration tests | Internal |
| 47 conformance harness checks | Internal | | 47 conformance harness checks | Internal |
| **SEMI E5 KAT** | **External — standards body's own encoding rules** | | **SEMI E5 KAT** | **External — standards body's own encoding rules** |
| **tshark dissector** | **External — independent network-protocol authors** | | **tshark dissector** | **External — independent network-protocol authors** |
+5 -6
View File
@@ -3,8 +3,8 @@
A fictional Physical Vapor Deposition tool, end-to-end. This is what A fictional Physical Vapor Deposition tool, end-to-end. This is what
a real tool integrator's deployment looks like: a real tool integrator's deployment looks like:
- `equipment.yaml` — the tool's data dictionary (32 SVIDs, 5 DVIDs, - `equipment.yaml` — the tool's data dictionary (29 SVIDs, 5 DVIDs,
7 ECIDs, 17 CEIDs, 12 alarms, 3 recipes, 9 host commands) 7 ECIDs, 21 CEIDs, 12 alarms, 3 recipes, 9 host commands)
- `main.cpp` — the vendor application: sensor simulator, recipe - `main.cpp` — the vendor application: sensor simulator, recipe
runner, alarm threshold monitor, EPT cycling, metrics exporter, runner, alarm threshold monitor, EPT cycling, metrics exporter,
Router handlers wiring it all to the wire. Router handlers wiring it all to the wire.
@@ -21,9 +21,8 @@ customize. They're written to be a template, not an abstract demo.
| §3 Recipe runner | Driving a PJ through SettingUp → Processing → ProcessComplete by walking the recipe body, with per-step CEID emission | | §3 Recipe runner | Driving a PJ through SettingUp → Processing → ProcessComplete by walking the recipe body, with per-step CEID emission |
| §4 Alarm threshold monitor | Continuous threshold-based alarm logic (chamber pressure, cleaning interval) with set/clear emission | | §4 Alarm threshold monitor | Continuous threshold-based alarm logic (chamber pressure, cleaning interval) with set/clear emission |
| §5 EPT cycling | E116 state transitions driven by PJ state + safety alarms | | §5 EPT cycling | E116 state transitions driven by PJ state + safety alarms |
| §6 Metrics | Prometheus exporter on `:9090` with per-CEID counters and gauge updates | | §6 Router handlers | Every SECS/GEM message a host might send to a PVD tool, 51 handlers in ~460 lines |
| §7 Router handlers | Every SECS/GEM message a host might send to a PVD tool, ~40 handlers in ~200 lines | | §7 main() | Loading YAML → validating → composing → running, including the Prometheus exporter on `:9090` (§7.3) |
| §8 main() | Loading YAML → validating → composing → running |
## Running it ## Running it
@@ -138,7 +137,7 @@ from `main.cpp` directly — each section is independently usable.
defined and you'll need them all in production. defined and you'll need them all in production.
That's it. No framework, no DI container, no abstract base That's it. No framework, no DI container, no abstract base
classes. ~700 lines of vendor code on top of the library. classes. ~1,100 lines of vendor code on top of the library.
## Cross-references ## Cross-references
+3 -3
View File
@@ -10,10 +10,10 @@
// §3. Recipe runner (drives PJ FSM through Processing → Complete) // §3. Recipe runner (drives PJ FSM through Processing → Complete)
// §4. Alarm threshold monitor (pressure-based) // §4. Alarm threshold monitor (pressure-based)
// §5. EPT cycling (Standby ↔ Productive ↔ UnscheduledDowntime) // §5. EPT cycling (Standby ↔ Productive ↔ UnscheduledDowntime)
// §6. Metrics (Prometheus exporter on :9090) // §6. Router handlers (the minimum set; mostly copied from
// §7. Router handlers (the minimum set; mostly copied from
// apps/secs_server.cpp which has the full catalogue) // apps/secs_server.cpp which has the full catalogue)
// §8. main() — wires everything together // §7. main() — wires everything together, including the
// Prometheus metrics exporter on :9090 (§7.3)
// //
// This file is deliberately self-contained — no pvd_internal/ helper // This file is deliberately self-contained — no pvd_internal/ helper
// headers, no factored-out "framework." Customers should be able to // headers, no factored-out "framework." Customers should be able to
+2 -2
View File
@@ -125,8 +125,8 @@ is consistent:
non-Python validators). non-Python validators).
2. Wired into `.gitea/workflows/ci.yml` as a separate job. 2. Wired into `.gitea/workflows/ci.yml` as a separate job.
3. Listed in this README's table + in `../VERIFICATION.md`. 3. Listed in this README's table + in `../VERIFICATION.md`.
4. Surfaced in the README's proof-of-feature-completeness table if 4. Surfaced in [`../PROOFS.md`](../PROOFS.md) if it adds a
it adds a meaningful new dimension. meaningful new dimension.
Bug reports from a new validator → file at Bug reports from a new validator → file at
`raphael@maenle.net` with the wire trace, the validator's output, `raphael@maenle.net` with the wire trace, the validator's output,
+13 -7
View File
@@ -9,7 +9,10 @@
# both our internal tests and the secsgem-py interop path. # both our internal tests and the secsgem-py interop path.
# #
# Usage: tshark_validate.sh [--port PORT] # Usage: tshark_validate.sh [--port PORT]
# Run inside the builder image (which has tshark + tcpdump). # Run inside the builder image (which has tshark + tcpdump), or on
# any host with tshark + tcpdump installed. Resolves $ROOT from the
# script's own location, so /app/... and any out-of-source checkout
# both work without env overrides.
# #
# Exit codes: # Exit codes:
# 0 — tshark dissected every HSMS frame without errors # 0 — tshark dissected every HSMS frame without errors
@@ -17,9 +20,12 @@
# 2 — script error (binary missing, capture failed, etc.) # 2 — script error (binary missing, capture failed, etc.)
set -euo pipefail set -euo pipefail
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
PORT=${PORT:-5099} PORT=${PORT:-5099}
SERVER=/app/build/secs_server BUILD=${BUILD:-$ROOT/build}
CLIENT=/app/build/secs_client SERVER=${SERVER:-$BUILD/secs_server}
CLIENT=${CLIENT:-$BUILD/secs_client}
DATA=${DATA:-$ROOT/data}
[ -x "$SERVER" ] || { echo "FAIL: $SERVER missing — rebuild first"; exit 2; } [ -x "$SERVER" ] || { echo "FAIL: $SERVER missing — rebuild first"; exit 2; }
[ -x "$CLIENT" ] || { echo "FAIL: $CLIENT missing — rebuild first"; exit 2; } [ -x "$CLIENT" ] || { echo "FAIL: $CLIENT missing — rebuild first"; exit 2; }
@@ -44,10 +50,10 @@ sleep 0.5
echo "starting secs_server on 127.0.0.1:$PORT" echo "starting secs_server on 127.0.0.1:$PORT"
$SERVER --port "$PORT" --device 0 \ $SERVER --port "$PORT" --device 0 \
--config /app/data/equipment.yaml \ --config "$DATA/equipment.yaml" \
--state-table /app/data/control_state.yaml \ --state-table "$DATA/control_state.yaml" \
--pj-state-table /app/data/process_job_state.yaml \ --pj-state-table "$DATA/process_job_state.yaml" \
--cj-state-table /app/data/control_job_state.yaml \ --cj-state-table "$DATA/control_job_state.yaml" \
> "$SERVER_LOG" 2>&1 & > "$SERVER_LOG" 2>&1 &
SERVER_PID=$! SERVER_PID=$!
sleep 0.5 sleep 0.5