Build Diagnostics¶
Some compliance rules are checked by the build itself. When one fires, you get a diagnostic id — look it up here for what the build wants and how to satisfy it.
Build diagnostics cover only the technical requirements, the ones that protect the platform. Behavior checks, which describe how a device appears in PQ, are never enforced by the build.
These checks are a floor, not the whole rule. A clean build means the mechanical violations are absent; the rule's judgement still applies to everything a compiler cannot see.
PQA — the declared model¶
Reported while the YAML is read, before any code is generated. These are defects in what the adapter declares: its device tree, its access model, its events.
| Id | Rule | What it reports |
|---|---|---|
| PQA001 | Adapter configuration must be reachable | No adapter registration is visible to the generator |
| PQA002 | Adapter configuration must parse | The registration is malformed, or declares a rejected value |
| PQA003 | Identity fields are required | adapter_id, name, version, adapter_type, or a TCP frame_type is missing |
| PQA004 | Functions must exist | A device type declares a function that is neither a framework nor a custom function |
| PQA005 | Generated entry point is skipped | An executable project already declares Main |
| PQA006 | Function catalogue must be reachable | functions.yaml is in neither the additional files nor the framework assembly |
| PQA007 | Event ids carry the pq.event. prefix |
A declared event id is missing the prefix |
| PQA008 | Custom function overrides system function | A custom function shadows a framework function of the same name |
| PQA009 | Command ids carry the pq.command. prefix |
A declared command id is missing the prefix |
| PQA010 | Commands configuration must parse | pq-commands.yaml is malformed or empty |
| PQA012 | Model references must be acyclic | Access-model entities reference each other in a cycle |
| PQA013 | Allocated addresses need a range | address: uint without range: [min, max] |
| PQA014 | Device types declare a category | A non-derived device type has no category |
| PQA015 | One addressing strategy per entity | An entity declares both id and address |
| PQA016 | Natural key must name a property | id: names a property the entity does not declare |
| PQA017 | Inheritance must be acyclic | Device types form a cycle through extends: |
| PQA018 | Base device type must exist | extends: names a type this adapter does not declare |
| PQA019 | Abstract functions are not usable directly | A device type declares an abstract function |
| PQA021 | Update mode must be known | updatable: is neither inplace nor replace |
| PQA022 | Range requires an allocated address | range on an address that is not uint |
| PQA023 | Tracked addresses are uint | A tracked entity uses another numeric address type |
| PQA024 | Identity must name a property | identity: names a property the type does not have |
| PQA025 | Identity needs a resolvable parent | An identity-declaring type sits under a passthrough parent |
| PQA026 | Type identity requires a singleton | identity: type without max_siblings: 1 on a parent |
| PQA027 | Events must exist in the taxonomy | A declared event id is not in pq-events.yaml |
| PQA028 | Owner must be known | owner: is neither person nor shared |
| PQA029 | Natural-id entities have no owner | An entity keyed by id: declares owner: |
| PQA030 | One person-owned root | The access model infers more than one root |
| PQA031 | Parent references must exist | parents: names a type this adapter does not declare |
| PQA032 | Property types must resolve | A property type: matches no primitive, device type, or public enum |
Ids are allocated once and never reused; PQA011 and PQA020 are unassigned, so the sequence skips them.
PQC — the written code¶
Reported from the adapter's C# code. These are defects in how the declared model is implemented.
| Id | Rule | What it reports |
|---|---|---|
| PQC152 | Time sync capability and implementation must agree | capabilities.time_sync is set without ITimeSynchronized, or the reverse |
| PQC203 | Events must be declared in YAML, not built by hand | Adapter code builds an event with EventBuilder.Event(...) or a PqEvent.* builder |
| PQC201 | Status poll must not participate in event processing | A poll publishes events without declaring the exception, or touches the replay cursor |
| PQC209 | Initial state must use a snapshot, not events | A device event is published from OnConnected while reading initial state |
| PQC211 | Command handlers publish from the confirming event | A handler publishes a device event directly instead of from the ExecuteCommand callback |
| PQC213 | Blanket ignore hides unresolved device addresses | A route ignores every event of a type that is also routed by address |
| PQC251 | Poll must cover every status function it can | A status function the Thing declares is never set by the poll |
| PQC232 | Event publication must be encapsulated in the owning Thing | A class publishes an event through a reference to a Thing it does not own |
| PQC257 | Set the device clock from the wall clock, never a re-projected local time | GetLocalNow().LocalDateTime re-projects the device wall clock onto the host process zone |
| PQC302 | Follow-up factory must be pure | A followUpFactory callback does something other than build the trailing frame |
Other generator diagnostics¶
Reported by the generator's command and enrollment checks. They keep their own id bands.
| Id | Rule | What it reports |
|---|---|---|
| PQ0001 | Declared commands need a handler | A commands: entry has no handler in the code |
| PQ0002 | Handlers need a declared command | A handler handles a command no device type declares |
| TD001 | Template classes are partial | [BinarySerializedBlob] / [BiometricTemplate] class is not partial |
| TD002 | Template classes serialize something | The class has no public byte[], byte[][] or primitive property with a setter |
| TD003 | Biometric templates have no required properties | A [BiometricTemplate] class declares a required property |
Severity¶
Most PQA diagnostics are errors from the start: a model that contradicts itself has no correct interpretation to fall back on, so generating from it produces code that misbehaves rather than code that fails.
PQC diagnostics arrive as warnings while adapters are brought into line, then become errors. Treat a warning as a defect with a deadline, not as advice.
Suppression¶
Do not suppress a compliance diagnostic. If you believe a report is wrong, it is a bug in the check — say so, with the code that triggered it. Every rule here exists because the failure it prevents reached a customer at least once.