Skip to content

PQA025 — Identity scope broken by passthrough parent

A type that declares identity sits under a parent that has neither identity nor the ability to be a root.

An identity key is unique within its parent, not globally: input 1 under module 3 is a different device from input 1 under module 7. The reconciler therefore needs to identify the parent before it can re-pair the child, which requires the parent to be identifiable — it declares its own identity:, or it is root-capable (declares no parents:) and is therefore reachable without one.

A parent that is neither is a passthrough sitting in the middle of the chain: it is re-created on every discovery, and there is no way to say which one of them the child belongs to.

- type_id: Bus              # no identity, and not root-capable
  parents:
    Panel:

- type_id: Input
  identity: [port]          # scoped to a parent nobody can name
  parents:
    Bus:

Why the build refuses this

The scope silently collapses. Without a resolvable parent, identity port: 1 matches every input on every bus. Re-pairing then either attaches devices to the wrong parent or imports the whole subtree again.

How to fix it

Give the intervening type an identity. A bus has a number, a port has an index — whatever the protocol uses to tell two of them apart. If the type is genuinely a singleton under its parent, identity: type says exactly that (see PQA026).

Or remove the intervening level. A passthrough type that carries no hardware distinction is often modelling noise; attaching the child directly to the identifiable ancestor makes the scope explicit.

What is not reported

A root-capable parent. A type with no parents: block anchors the chain by itself.

A parent whose identity comes from extends:. Identity inherited through the chain counts as declared.

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.