Vocabulary

The types every stage speaks, and the two support modules that go with them: diagnostics, and the bus-kind naming rules the loader, the board reader and the analyzer each independently apply.

rigc.model

The rig model: syntax-free semantic representation of a rig, plus the shield-template model every instance’s shield: reference resolves against.

Instance.shield is a real, resolved Shield: loader/library.py builds the shield library and resolves every reference against it before an Instance ever exists, so nothing downstream carries an unresolved reference.

rigc.diag

Diagnostics core: diagnostics are DATA, returned upward.

No mutable accumulator threaded in and written to, no whole-model parameters where a value would do, no side channel: a function that finds something wrong RETURNS Diagnostic values (alone or beside its result); composition is list concatenation at the caller.

ONE renderer produces the frozen stderr format the goldens specify:

error[<code>]: <message first line>

<message continuation lines, four-space indented> at <path>:<line> (<key>)

Anchor-path rule, module-agnostic: if the path lies under a scripts/<module>/ component, it renders relative to that component; otherwise it renders absolute. anchor_path() is a pure function of the path value alone – deliberately no module-scope dirname(__file__) constant – so unit tests exercise it with synthetic roots.

rigc.buskind

Bus-kind matching: whether a bus name (a Device.bus value, or a shield group/proxy name authored in a .shield file) names a given socket bus KIND – bare (“spi”), or a named variant a multi-bus connector type suffixes with a role (“spi-sensors”). One shared implementation for every pass that gates behavior on which kind a qualified bus name is, rather than each duplicating the same kind-prefix match (or, worse, a literal three-name membership check that silently stops covering a role-suffixed name).

Also the one home for the two socket,* PROPERTY-NAME regexes every reader of a socket,* binding/node needs – loader/shields.py (exposed-socket parsing), board/project.py (board-side projection) and registry.py (connector-type binding facts) each read the identical two patterns off a different input (a dtlib node, an edtlib.EDT, a raw binding dict), so the patterns themselves belong here rather than as separate verbatim copies drifting apart one edit at a time.