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:
@@ -6,7 +6,7 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "equipment_service.hpp"
|
||||
#include "secsgem/daemon/equipment_service.hpp"
|
||||
#include "secsgem/gem/default_handlers.hpp"
|
||||
#include "secsgem/gem/messages.hpp"
|
||||
|
||||
@@ -220,8 +220,14 @@ TEST_CASE("GetVariables round-trip under run_async (production threading mode)")
|
||||
pb::VariableQuery req;
|
||||
pb::VariableSnapshot resp;
|
||||
REQUIRE(stub->GetVariables(&ctx, req, &resp).ok());
|
||||
const auto expected = rt.model().svids.size() + rt.model().dvids.all().size();
|
||||
CHECK(resp.values().size() == expected);
|
||||
// The io thread is live here — model reads must go through read_sync
|
||||
// (the first violation of that contract was caught by the TSan lane in
|
||||
// exactly this line).
|
||||
auto expected = rt.read_sync([&rt] {
|
||||
return rt.model().svids.size() + rt.model().dvids.all().size();
|
||||
});
|
||||
REQUIRE(expected.has_value());
|
||||
CHECK(resp.values().size() == *expected);
|
||||
}
|
||||
|
||||
SUBCASE("unknown name is INVALID_ARGUMENT, naming the offender") {
|
||||
|
||||
Reference in New Issue
Block a user