feat(daemon): Phase E — production hardening, complete
tests / build-and-test (push) Successful in 2m59s
tests / thread-sanitizer (push) Successful in 3m28s
tests / tshark-dissector (push) Successful in 2m22s
tests / secs4j-interop (push) Successful in 2m6s
tests / python-interop (push) Failing after 3m8s
tests / libfuzzer (push) Successful in 3m44s

Exposure: --grpc default flipped from 0.0.0.0 to 127.0.0.1 (the API is
unauthenticated by design; auth belongs to the transport), Unix-domain-
socket support (--grpc unix:///run/secs_gemd/api.sock = zero network
surface), SECURITY.md documents the contract and ch42 gained a "Running it
in production" section (which also documents the HSMS-SS single-session
assumption).

Graceful shutdown: SIGTERM/SIGINT land on an asio::signal_set on the io
thread, which nudges grpc Shutdown with a 2s deadline (cancels open
Subscribe/WatchHealth streams); Wait() returns on the MAIN thread, which
stops the engine (rt->stop() joins the io thread, so it must not run on
it). Exit 0, journal-safe, the in-code TODO is gone. --spool-dir added so
host-bound events survive daemon restarts.

Observability: --metrics serves Prometheus gauges secsgem_link_selected /
secsgem_control_state / secsgem_spool_depth, wired via the Phase-0
add_link_observer/add_control_state_observer hooks + io-thread sampling.

Deployment: deploy/secs_gemd.service — hardened systemd unit (DynamicUser,
ProtectSystem=strict, StateDirectory for the spool, UDS for the API,
TimeoutStopSec aligned with the graceful-shutdown window).

Enforcement: tools/check_daemon_ops.sh proves all three operational claims
(unix-socket gRPC accepts, all gauges present on /metrics, SIGTERM -> exit
0 + clean-stop log) — green; wired into tools/run_interop.sh (now 11
steps) and CI. CI python-interop lane also gained the pyclient and
spool-restart steps, so every harness now runs in CI.

TODO sweep: the shutdown TODO is fixed; the four remaining TODOs (nested
list formats, C2-as-text, U8>2^63, CONNECTED link state) are deliberate
deferred edge cases, each marked in code with context.

Daemon suite re-verified green (175 assertions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 00:07:37 +02:00
parent b1772cfefd
commit 54626ceb6a
8 changed files with 281 additions and 20 deletions
+31 -3
View File
@@ -39,11 +39,12 @@ drops; the daemon model covers the gap if *your software* drops.
Run it:
```sh
build/secs_gemd --port 5000 --grpc 0.0.0.0:50051 --config-dir data
build/secs_gemd --port 5000 --config-dir data # gRPC on 127.0.0.1:50051
build/secs_gemd --grpc unix:///run/secs_gemd/api.sock … # production: no TCP at all
```
One process, two faces: passive HSMS equipment on `--port`, the gRPC tool
API on `--grpc`.
API on `--grpc` (localhost by default — see §5 before exposing anything).
---
@@ -188,7 +189,34 @@ stream, so they never fight your application over the slot.
---
## 5. Which tier do I pick?
## 5. Running it in production
- **Exposure.** `--grpc` defaults to `127.0.0.1:50051`; the API is
unauthenticated by design (auth belongs to the transport), so it must
never face the equipment LAN. For same-host tool software use a Unix
domain socket — `--grpc unix:///run/secs_gemd/api.sock` — and there is
no network surface at all. The HSMS port faces the fab host; firewall
it to the host's address ([SECURITY.md](SECURITY.md) has the nftables
recipe).
- **Shutdown.** SIGTERM/SIGINT drain gracefully: open Subscribe/WatchHealth
streams are cancelled (2s deadline), the engine stops cleanly, the spool
journal is never cut mid-write, exit code 0. Safe under systemd and
`docker stop`.
- **Supervision.** [deploy/secs_gemd.service](../deploy/secs_gemd.service)
is a hardened systemd unit (DynamicUser, ProtectSystem, StateDirectory
for the spool, Restart=always). Pair with `--spool-dir` so host-bound
events survive daemon restarts too.
- **Metrics.** `--metrics 9091` serves Prometheus gauges:
`secsgem_link_selected`, `secsgem_control_state`, `secsgem_spool_depth`.
- **Sessions.** v1 runs one equipment identity per daemon (HSMS-SS). The
engine supports HSMS-GS multi-session, but the daemon doesn't surface it
yet — run one daemon per equipment identity.
- All of the above is enforced by `tools/check_daemon_ops.sh` (the
`daemon-ops` step of `tools/run_interop.sh`, also in CI).
---
## 6. Which tier do I pick?
| Your situation | Tier |
|---|---|