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-fuzz/
build-tsan/
*.o
*.obj
*.a
+10 -10
View File
@@ -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`. |
---
+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?
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
View File
@@ -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. |
+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
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
View File
@@ -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 ~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 |
| 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** |
+5 -6
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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,
+13 -7
View File
@@ -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