chore(phase0): name validation, golden frames, daemon into library tree, TSan daemon lane
Item 8a — ConfigValidator warns on non-identifier variable/event/alarm/ command names ([A-Za-z_][A-Za-z0-9_]*): language bindings expose names as kwargs/attributes, so 'Chamber Pressure' would be unusable in the planned Python client. Warning not error — the wire doesn't care. Tested (4 warning sites + good-name negative). Item 4 tail — golden frames for S5F1 (Binary ALCD / U4 ALID / ASCII ALTX) and a composed S6F11 (the production-critical report shape), bytes hand- computed from E5 encoding rules: external pins on message composition. Item 7 — equipment_service.hpp moved to include/secsgem/daemon/ (apps/ include-path hack removed) and a TSan daemon lane added locally + in CI. tools/tsan.supp suppresses races whose accesses sit entirely inside the UNinstrumented system libgrpc/libgpr/libabsl (epoll wakeups, absl Mutex GraphCycles bookkeeping); our frames stay fully checked. The lane earned its keep on first run: it caught a REAL threading-contract violation — a daemon test reading model stores from the test thread while the io thread serviced posted writes — fixed to use read_sync, exactly per the documented contract. Now TSan-clean under halt_on_error=1 in the full production threading shape. Suites: core 470/3068, daemon Release+TSan 125/125 each. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+18
-16
@@ -48,8 +48,9 @@ host and stays conformant while the tool software restarts/upgrades/crashes.
|
||||
- ✅ ~~**Interop harnesses are manual.**~~ `tools/run_interop.sh` runs all nine
|
||||
validation steps with one command (verified green); CI lanes added, pending
|
||||
first-push verification (Phase 0 item 2).
|
||||
- ⬜ **TSan lane doesn't cover the daemon.** `secs_gemd_tests` should also be
|
||||
built/run under `-DSECSGEM_TSAN=ON` once the control-state mirror lands.
|
||||
- ✅ ~~**TSan lane doesn't cover the daemon.**~~ Covered locally + in CI
|
||||
with `tools/tsan.supp` (third-party-only suppressions). Caught + fixed a
|
||||
real test-side contract violation on its first run.
|
||||
- ⚠️ **macOS bind-mount staleness can break Docker builds mid-edit** (a build
|
||||
reading a half-synced source file). Not a product bug; re-run the build.
|
||||
|
||||
@@ -101,12 +102,10 @@ debts tax every later phase, and the most valuable tests aren't automated.
|
||||
localhost, no docker-in-docker). ⬜ Verify the lanes on the first push.
|
||||
3. ✅ **Fix `CompleteCommand` proto comment** — it described the rejected
|
||||
blocking model; now states the HCACK-4 contract.
|
||||
4. 🚧 **Table-driven handler conformance test** — ✅
|
||||
`tests/test_handler_conformance.cpp`: one ordered scenario drives 53 of the
|
||||
56 handlers through `router.dispatch` in-process (236 assertions), asserting
|
||||
paired replies, control-state landings, and the SxF0 abort fallback.
|
||||
Message-level golden frames: seeded with a hand-computed (E5-rules, not
|
||||
codec-derived) S1F13 pin — ⬜ extend to S5F1 + composed S6F11 (TODO in file).
|
||||
4. ✅ **Table-driven handler conformance test** — one ordered scenario
|
||||
drives 53 of the 56 handlers through `router.dispatch` (236 assertions).
|
||||
Golden frames: S1F13, S5F1, and a composed S6F11, all hand-computed from
|
||||
E5 rules (external pins, not codec-derived).
|
||||
5. ⬜ **Decompose `register_default_handlers` per GEM capability** (it is a
|
||||
relocated main(), not a designed component) and replace magic constants
|
||||
(SVIDs 1/2 `refresh()`, CEIDs 400/401) with YAML role bindings
|
||||
@@ -115,14 +114,17 @@ debts tax every later phase, and the most valuable tests aren't automated.
|
||||
6. ✅ **Standardize the mutable-read pattern** — `EquipmentRuntime::read_sync`
|
||||
(post-to-io + future with deadline; nullopt => UNAVAILABLE at the RPC edge).
|
||||
Precedent set by `GetVariables`; every future mutable read copies it.
|
||||
7. ⬜ Move `apps/equipment_service.hpp` into the library tree
|
||||
(`include/secsgem/daemon/`) once Phase B grows it; add a TSan-built
|
||||
`run_async` + concurrent-RPC daemon test (today's daemon tests only poll()).
|
||||
8. 🚧 Validate names are identifier-safe in `ConfigValidator` (the Python
|
||||
client's kwargs API depends on it) — ⬜. Generalized format-compliance
|
||||
property test (iterates ALL configured variables via gRPC, asserts each
|
||||
keeps its declared wire format) — ✅, plus an unset-`Value` guard at the
|
||||
RPC edge (was silently writing ASCII "").
|
||||
7. ✅ `equipment_service.hpp` moved to `include/secsgem/daemon/` (apps/
|
||||
include-path hack removed). TSan daemon lane added locally + in CI
|
||||
(`tools/tsan.supp` suppresses UNinstrumented system libgrpc/libabsl
|
||||
internals only — our frames stay checked). The lane caught a real
|
||||
contract violation on its first run (a test reading the model from the
|
||||
test thread under run_async — fixed to read_sync); now TSan-clean with
|
||||
halt_on_error=1.
|
||||
8. ✅ Identifier-safe name validation: `ConfigValidator` warns (not errors)
|
||||
on non-identifier variable/event/alarm/command names — bindings expose
|
||||
names as kwargs/attributes. Format-compliance property test ✅; unset-
|
||||
`Value` guard ✅.
|
||||
|
||||
### Phase A — finish the universal daemon surface (small, unblock vendors)
|
||||
1. ✅ `GetVariables` — `from_item` reverse conversion (scalar for 1-element
|
||||
|
||||
Reference in New Issue
Block a user