Skip to content

PQA012 — Circular dependency in model

Access-model entities reference each other in a cycle.

Synchronization writes records in dependency order. A card references an access level, an access level references a time zone, so time zones are written first — otherwise the panel receives a record pointing at a slot that does not exist yet.

That order comes from a topological sort of the reference graph, and a cycle has no topological order.

# A -> B -> A
- entity: AccessLevel
  properties:
    schedule:
      type: Schedule
- entity: Schedule
  properties:
    level:
      type: AccessLevel

Why the build refuses this

There is no correct write order, so any chosen order writes a dangling reference. Whichever entity goes first points at a slot the panel has not been told about.

A cycle in the model rarely exists in the protocol. Panel tables are layered — schedules, then levels, then cardholders. A cycle usually means a back-reference was modelled for convenience on the adapter side.

How to fix it

Delete the back-reference. Keep the direction the protocol writes in and resolve the reverse lookup in code where it is needed; the model only has to describe what goes on the wire.

Or split the entity. When both directions genuinely carry data, the pair is usually two tables in the protocol, and modelling them as two entities breaks the cycle.

If you disagree with a report

Do not suppress it. A wrong report is a bug in the check — report it with the YAML that triggered it.