config: multi-error YAML validator + --validate-config CLI flag
The existing loader throws ConfigError on the first problem it hits.
A customer with a tool-specific equipment.yaml that has six issues
sees one, fixes, restarts, sees the next, fixes, restarts — six
edit-restart cycles before the server even binds. Day-1 friction
is the top support ticket source in fab integrations.
This commit adds a parallel validator that does a separate read-only
pass and surfaces *every* issue at once:
$ secs_server --validate-config \
--config equipment.yaml \
--state-table control_state.yaml
[error] equipment.yaml:5 svids[0].type — unknown SECS-II type `WTF`
[error] equipment.yaml:7 alarms[0].category — value 200 out of range [0, 127]
[error] equipment.yaml:9 host_commands[0].emit_ceid — CEID 999 not declared in `ceids` section
3 error(s), 0 warning(s) across 4 files
What it catches:
- Missing required fields (device.model_name, .software_rev, …)
- Range violations (alarm category must be 0–127, spool streams 1–127,
device.id fits u16, etc.)
- Unknown enum values (SECS-II types, HCACK values, control/PJ/CJ
state and event names — using the right case + snake convention
the runtime parsers enforce)
- Duplicate IDs within svids / dvids / ecids / ceids / alarms,
duplicate PPIDs in recipes, duplicate command names in host_commands
- Referential integrity: host_commands[*].emit_ceid must exist in
ceids; host_commands[*].set_alarm must exist in alarms;
emit_on_control_change must exist in ceids
- PJ-table-specific: `NoState` sentinel rejected as `initial`,
`from`, or `to` (matches loader's existing runtime check)
- yaml-cpp Mark → 1-based line numbers when available
What it doesn't catch (out of scope this round):
- JSON Schema for editor red-squigglies (future)
- Deep semantic checks across state-table reachability
- ECID min/max value parsing (would need numeric type coupling)
Tests cover: clean file passes; multi-error YAML surfaces every issue
on a single pass; line numbers populate; control_state /
process_job_state / control_job_state casing conventions;
format_issues_to renders both severities; the shipped
data/equipment.yaml etc. validate cleanly (regression tripwire if
anyone breaks the demo configs).
INTEGRATION.md §2.3 calls out the flag and suggests CI use.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+24
-1
@@ -129,7 +129,30 @@ io.run();
|
||||
the start. The repo's `apps/secs_server.cpp` is a complete worked
|
||||
example — copy it verbatim, then customize the YAML to your tool.
|
||||
|
||||
### 2.3. Run it
|
||||
### 2.3. Validate before you run
|
||||
|
||||
YAML edits are easy to get wrong: an unknown SECS-II type, a
|
||||
duplicate ID, a `host_command` referencing a CEID you forgot to
|
||||
declare. The server has a `--validate-config` mode that reads every
|
||||
YAML, accumulates *every* problem it can find, prints them with file
|
||||
and line number, and exits 0 / 1 without binding the port:
|
||||
|
||||
```sh
|
||||
secs_server --validate-config \
|
||||
--config /etc/acme/equipment.yaml \
|
||||
--state-table /etc/acme/control_state.yaml \
|
||||
--pj-state-table /etc/acme/process_job_state.yaml \
|
||||
--cj-state-table /etc/acme/control_job_state.yaml
|
||||
# [error] equipment.yaml:5 svids[0].type — unknown SECS-II type `WTF`
|
||||
# [error] equipment.yaml:7 alarms[0].category — value 200 out of range [0, 127]
|
||||
# [error] equipment.yaml:9 host_commands[0].emit_ceid — CEID 999 not declared in `ceids` section
|
||||
# 3 error(s), 0 warning(s) across 4 files
|
||||
```
|
||||
|
||||
Run this in CI on every config change and you skip the slow
|
||||
load-fail-edit-restart loop the first deployment otherwise becomes.
|
||||
|
||||
### 2.4. Run it
|
||||
|
||||
```sh
|
||||
docker compose up server # or your own deployment
|
||||
|
||||
Reference in New Issue
Block a user