A large gap had opened between the docs and the code: the README and
INTEGRATION guide did not mention the gRPC daemon or the Python client at
all (the entire vendor surface), ARCHITECTURE still described secs_server
as the ~1200-line canonical wiring example (it is a ~110-line thin main
over EquipmentRuntime), and test counts across six files were stale
(445/2753 -> 473/3087 core + the separate 125-assertion daemon suite).
- README: new "Integrating your tool (pick a tier)" section — Python
client / any-language gRPC / embedded C++ — plus daemon tests and
tools/run_interop.sh in the Testing section.
- ARCHITECTURE: layer diagram gains the vendor-surface and
EquipmentRuntime/default_handlers tiers; stale wiring row fixed.
- INTEGRATION: three-tier chooser up front (this guide = the C++ tier).
- ch30 tour: secs_gemd + secs_gemd_tests in the binaries table.
- ch31: example alarm used a nonexistent `alcd:` field with bit 7 set
(which the validator forbids) -> real `category:`/`name:` fields, and
the roles: block documented.
- ch35: handler-location note now points at default_handlers.cpp's 15
per-capability register_* functions.
- ch40: built-artifacts list + sample output counts.
- ch50: secsgem::gem runtime/default_handlers/handler_slot/name_index
includes + new secsgem::daemon namespace section.
- PROOFS: test-count table gains the runtime/handlers/daemon row so the
tally adds up; daemon suite noted. VERIFICATION/COMPLIANCE counts.
- interop/README: the one-command runner + the two daemon-track harnesses
(daemon_interop, pyclient_interop).
Audited via a docs-vs-code sweep (the audit itself under-reported: it
validated counts textually; reality was 473/3087).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An audit of doc code blocks against the real headers found APIs that do
not exist in the codebase, presented as authoritative walkthroughs:
- ch35 (dispatch): an entirely fabricated callback architecture —
HostCommandRegistry::set_emit_ceid_handler, CommandOutcome, emit_ceids.
Rewritten to the real Spec/Result/dispatch + the new set_handler hook.
- ch13 (E30): wrong store names — EventStore/ReportStore -> EventReportSubscriptions,
SvidStore -> StatusVariableStore, AlarmStore/AlarmDispatcher -> AlarmRegistry,
ClockStore -> Clock, TerminalServiceStore -> (no store), in both the
capability tables and the worked S2F33 example.
- ch17 (E116): EptStore/seconds/bucket_ -> EptStateMachine/milliseconds/buckets_.
- ch51 (extending): stale host-command handler -> the real set_handler signature.
Verified clean by grep: no fabricated symbols remain in docs/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Seven chapters walking the implementation top-to-bottom.
30 — Repository tour. Top-level layout, directory by directory.
The eight built binaries. The dependency graph from TCP socket
up through EquipmentDataModel. CMake's role. Test layout.
31 — Spec-as-data and codegen. Why the design choice fits SECS/
GEM specifically. The five YAML files: messages catalog,
control/PJ/CJ transition tables, equipment dictionary. How
tools/gen_messages.py turns messages.yaml into typed C++ at build
time. The --validate-config multi-error validator. How to add a
new SVID / CEID / host command / state / message without C++.
32 — Stores and the data model. What a store IS (records + API +
change handler + optional persistence). Every store in the
codebase mapped to the SEMI standard it serves (table of 21).
EquipmentDataModel as plain composition + cross-store convenience
methods (vid_value, compose_reports_for). The no-locks single-
threaded contract. How to add a new store.
33 — Transport. hsms::Connection read path (length+payload async
chain), write path (queue + one outstanding write), timer model
(5 steady_timers + per-request T3). The asio executor / strand
model and why it's the right shape. secsi::Protocol as the IO-
free FSM with Action / Event variants; secsi::TcpTransport as the
asio adapter. Pattern repeats for E84 + GEM comm-state.
34 — Codec and SML. The four files (170 + 30 + 52 + 32 lines of
header, 229 + 220 lines of impl). Item variant storage layout
(11 alternatives, 16 formats, shared storage where E5 permits).
encode_into recursion; decode_at with bounds checks throwing
CodecError. Message wrapper. SML printer + try_parse_sml +
why SML round-trips Items but not necessarily bytes.
35 — State machines and dispatch. gem::Router as a typed
(stream, function) dispatch table. How an S2F41 round-trip walks
through parser → store dispatch → side-effect → CEID emission →
S6F11 build → spool-aware deliver. The 11 FSMs all sharing the
same three-property shape (pure data table + pure FSM + observer
pattern). CEID cascading from FSM transitions to wire bytes.
36 — Persistence, validation, metrics. Which 7 stores have file
journals + why the others don't. Per-record file pattern (atomic
rename, partial-write safe). Schema versioning + multi-version
read. Multi-error YAML validator (--validate-config) + cross-file
reference checks. Prometheus registry + HTTP exporter + worked
metric patterns from the PVD example.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>