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:
@@ -1,4 +1,6 @@
|
||||
build/
|
||||
build-fuzz/
|
||||
build-tsan/
|
||||
*.o
|
||||
*.obj
|
||||
*.a
|
||||
|
||||
+10
-10
@@ -1,12 +1,13 @@
|
||||
# SECS/GEM Compliance
|
||||
|
||||
A per-capability accounting against the foundational SEMI standards
|
||||
**E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS)**, **E4 (SECS-I)**, plus
|
||||
the full GEM 300 stack: **E40** (process jobs), **E94** (control jobs),
|
||||
**E87** (carriers), **E90** (substrates), **E116** (equipment
|
||||
performance tracking), **E120** (common equipment model), **E157**
|
||||
(module process tracking), **E84** (parallel I/O), **E148** (time
|
||||
synchronization), **E39** (object services), plus **E5 §13** wafer maps.
|
||||
**E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS, SS + GS)**, **E4 (SECS-I)**,
|
||||
plus the full GEM 300 stack: **E40** (process jobs), **E42** (formatted
|
||||
process programs), **E94** (control jobs), **E87** (carriers), **E90**
|
||||
(substrates), **E116** (equipment performance tracking), **E120** (common
|
||||
equipment model), **E157** (module process tracking), **E84** (parallel
|
||||
I/O), **E148** (time synchronization), **E39** (object services), plus
|
||||
**E5 §13** wafer maps.
|
||||
|
||||
> **Status.** Every GEM Fundamental and every GEM Additional capability
|
||||
> that E30 binds to a concrete SECS-II message set is implemented, and
|
||||
@@ -227,7 +228,7 @@ Legend:
|
||||
|
||||
## 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 |
|
||||
|------------------|-----------|--------|-------|
|
||||
@@ -345,7 +346,7 @@ walks ~20 SECS transactions end-to-end:
|
||||
23. `S1F15`/`S1F16` Request Offline.
|
||||
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`
|
||||
over a loopback socket pair to verify the E37 §7.2 / §7.4 / §7.7
|
||||
edge cases — not just the happy path.
|
||||
@@ -398,9 +399,8 @@ compliance claim.
|
||||
|
||||
| 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. |
|
||||
| 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`. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ Both are necessary; neither replaces the other. See VERIFICATION.md.
|
||||
## How do I bring this to a customer site?
|
||||
|
||||
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
|
||||
actual MES. Then deploy per [SECURITY.md](SECURITY.md) for the
|
||||
nftables / stunnel / signing setup. Then page on the metrics from
|
||||
@@ -219,7 +219,9 @@ INTEGRATION.md §6.4.
|
||||
## What's not implemented?
|
||||
|
||||
See [COMPLIANCE.md](COMPLIANCE.md) §8 ("Explicitly out of scope")
|
||||
for the honest list. The short version: multi-block SECS-I
|
||||
transfers (irrelevant on HSMS), tool-specific Equipment Processing
|
||||
States (the engine is there, vendors plug in their states), and
|
||||
GEM RTS certification (paid third-party gate, not a code feature).
|
||||
for the honest list. The short version: tool-specific Equipment
|
||||
Processing States (the engine is there, vendors plug in their
|
||||
states), the serial-port driver for SECS-I (the FSM is wired
|
||||
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
@@ -149,7 +149,7 @@ TA3 (BUSY duration) live alongside the signals — see
|
||||
| **The router** | `gem::Router` — `(stream, function) → handler` dispatch table. |
|
||||
| **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 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 fuzz** | `tests/test_robustness_fuzz.cpp` — randomized property test of the model. |
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
Everything runs in Docker — no compiler or build tools on the host.
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
@@ -89,9 +35,10 @@ through the data model. Watch the logs interleave.
|
||||
| [COMPLIANCE.md](COMPLIANCE.md) | Per-capability audit against every SEMI standard implemented |
|
||||
| [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) |
|
||||
| [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 |
|
||||
| [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 |
|
||||
| [GLOSSARY.md](GLOSSARY.md) | SEMI vocabulary: SVID, CEID, PPID, ALCD, HCACK, T-timers, … |
|
||||
| [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
|
||||
|
||||
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).
|
||||
```
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for how to extend it (new
|
||||
store / FSM / message).
|
||||
|
||||
---
|
||||
|
||||
## Adding a capability
|
||||
|
||||
+4
-5
@@ -1,13 +1,12 @@
|
||||
# External verification plan
|
||||
|
||||
The five proofs in [README.md](README.md#proof-of-feature-completeness)
|
||||
are mostly **us testing us**:
|
||||
The proofs in [PROOFS.md](PROOFS.md) are mostly **us testing us**:
|
||||
|
||||
| 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 |
|
||||
| 24 secsgem-py interop checks | **External**, but covers ~15–20 % of the claimed wire surface |
|
||||
| 31 secsgem-py interop checks | **External**, but covers ~15–20 % of the claimed wire surface |
|
||||
| 100 k random tool ops | Internal — property test of our model |
|
||||
| YAML validation | Internal — our validator on our YAML |
|
||||
|
||||
@@ -273,7 +272,7 @@ After all four:
|
||||
|
||||
| Proof channel | Independence |
|
||||
|--------------------------------|------------------------------------------------------|
|
||||
| 426 unit/integration tests | Internal |
|
||||
| 445 unit/integration tests | Internal |
|
||||
| 47 conformance harness checks | Internal |
|
||||
| **SEMI E5 KAT** | **External — standards body's own encoding rules** |
|
||||
| **tshark dissector** | **External — independent network-protocol authors** |
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
A fictional Physical Vapor Deposition tool, end-to-end. This is what
|
||||
a real tool integrator's deployment looks like:
|
||||
|
||||
- `equipment.yaml` — the tool's data dictionary (32 SVIDs, 5 DVIDs,
|
||||
7 ECIDs, 17 CEIDs, 12 alarms, 3 recipes, 9 host commands)
|
||||
- `equipment.yaml` — the tool's data dictionary (29 SVIDs, 5 DVIDs,
|
||||
7 ECIDs, 21 CEIDs, 12 alarms, 3 recipes, 9 host commands)
|
||||
- `main.cpp` — the vendor application: sensor simulator, recipe
|
||||
runner, alarm threshold monitor, EPT cycling, metrics exporter,
|
||||
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 |
|
||||
| §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 |
|
||||
| §6 Metrics | Prometheus exporter on `:9090` with per-CEID counters and gauge updates |
|
||||
| §7 Router handlers | Every SECS/GEM message a host might send to a PVD tool, ~40 handlers in ~200 lines |
|
||||
| §8 main() | Loading YAML → validating → composing → running |
|
||||
| §6 Router handlers | Every SECS/GEM message a host might send to a PVD tool, 51 handlers in ~460 lines |
|
||||
| §7 main() | Loading YAML → validating → composing → running, including the Prometheus exporter on `:9090` (§7.3) |
|
||||
|
||||
## Running it
|
||||
|
||||
@@ -138,7 +137,7 @@ from `main.cpp` directly — each section is independently usable.
|
||||
defined and you'll need them all in production.
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
// §3. Recipe runner (drives PJ FSM through Processing → Complete)
|
||||
// §4. Alarm threshold monitor (pressure-based)
|
||||
// §5. EPT cycling (Standby ↔ Productive ↔ UnscheduledDowntime)
|
||||
// §6. Metrics (Prometheus exporter on :9090)
|
||||
// §7. Router handlers (the minimum set; mostly copied from
|
||||
// §6. Router handlers (the minimum set; mostly copied from
|
||||
// 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
|
||||
// headers, no factored-out "framework." Customers should be able to
|
||||
|
||||
+2
-2
@@ -125,8 +125,8 @@ is consistent:
|
||||
non-Python validators).
|
||||
2. Wired into `.gitea/workflows/ci.yml` as a separate job.
|
||||
3. Listed in this README's table + in `../VERIFICATION.md`.
|
||||
4. Surfaced in the README's proof-of-feature-completeness table if
|
||||
it adds a meaningful new dimension.
|
||||
4. Surfaced in [`../PROOFS.md`](../PROOFS.md) if it adds a
|
||||
meaningful new dimension.
|
||||
|
||||
Bug reports from a new validator → file at
|
||||
`raphael@maenle.net` with the wire trace, the validator's output,
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
# both our internal tests and the secsgem-py interop path.
|
||||
#
|
||||
# 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:
|
||||
# 0 — tshark dissected every HSMS frame without errors
|
||||
@@ -17,9 +20,12 @@
|
||||
# 2 — script error (binary missing, capture failed, etc.)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
PORT=${PORT:-5099}
|
||||
SERVER=/app/build/secs_server
|
||||
CLIENT=/app/build/secs_client
|
||||
BUILD=${BUILD:-$ROOT/build}
|
||||
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 "$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"
|
||||
$SERVER --port "$PORT" --device 0 \
|
||||
--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 \
|
||||
--config "$DATA/equipment.yaml" \
|
||||
--state-table "$DATA/control_state.yaml" \
|
||||
--pj-state-table "$DATA/process_job_state.yaml" \
|
||||
--cj-state-table "$DATA/control_job_state.yaml" \
|
||||
> "$SERVER_LOG" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
sleep 0.5
|
||||
|
||||
Reference in New Issue
Block a user