net.netclass
the tool-assigned net class a net belongs to (KiCad net_settings; not the derived semantic role)
What it is ¶
net.netclass(net, class) yields one row per net that the design tool put in a named class, with the
class string recorded verbatim: Default, Power, HighSpeed, whatever the project declares. A net
left in the tool’s implicit default carries no class and produces no row, so not net.netclass(?n, ?_)
reads as “unclassed”.
The name is deliberate. net.netclass is the tool-assigned label. It is not net.class, since
that name would belong to the derived semantic role space. net.ground and the ir.Net.roles
stamp (WS3-072) occupy that space. The two answer different questions. An engineer put a net in the
Power class by hand, while a net satisfies net.ground because the naming lexicon read it as
ground. A rule that conflated them would join against nothing and report clean.
For hardware engineers ¶
A net class is how you tell the layout tool that a group of nets shares rules: these are the high-speed pairs, these are the high-voltage nets, these carry more current than the default track width allows. Vendor rule decks usually scope a rule by net class. You already maintain the label in the project, and the engine does not guess it from a name.
Query it to confirm the engine sees the classes you assigned, and to scope a review question the way
you would scope a design rule: “which parts sit on an HV net”, “is any high-speed pair missing its
termination”. The class records an assignment rather than a measurement. A net in HighSpeed means
someone declared it high-speed, and the engine has not verified that it is routed that way.
A net can be in several classes at once, and the engine reports all of them. If you assigned VBUS
to both Power and HighCurrent, it shows up under both, and a query scoped to either one finds it.
When you check coverage and a net is missing from a scope you expected it in, that is a real
finding. The engine used to be able to lose the membership rather than report it.
For software engineers ¶
A filtered projection over Nets(), one row per class membership and none for an unclassed net. It
joins to everything else keyed by net name (component.net, pin.net, net.max_voltage), so it
composes as a scope filter on any existing question.
?net is NOT unique in this projection. Membership is a set, so a net in two classes emits two
rows and a join on ?net fans out, the same 1:many shape component.class has. Count rows and you
are counting memberships, not nets; net.netclass(?n, ?c) => ?n on a design where half the nets carry
two classes returns more results than the design has classed nets.
WS1-050 settled this against the formats rather than against our first reader. KiCad stores
map<netname, set<netclass>> and resolves a net’s membership by unioning its explicit assignment with
EVERY matching pattern, then cascades the per-class VALUES by priority to build one effective class.
Altium likewise lets a net join several classes, though its clearance matrix treats that as an
ambiguity to flag rather than a feature. The two tools share the data model and read it in
opposite ways. So the engine records the set as fact, and a rule decides whether a second class is a
problem.
Order is sorted, and that is a determinism guarantee only. It is NOT the tool’s precedence order.
KiCad’s precedence is a per-class priority. It lives with the class DEFINITIONS (clearance, track
width, via), and only the cascade behind net.declared_track_width and net.declared_via_drill
reads it (WS3-111). Precedence decides whose track width wins, never who is a member, so it cannot
change the answer to a membership question.
The value is a foreign label from the project file rather than a closed enum, so string comparisons are exact and case-sensitive, and two projects can use different vocabularies for the same intent. Do not treat an unrecognized class as an error, and do not derive meaning from the string beyond what the project declares.
Go projector ¶
netNetClassFacts in stdlib/relations/facts.go walks Model.Nets() and emits a row per entry of
each net’s NetClasses. The field is populated in the I/O layer rather than by any analysis.
readers/formats/registry.go reads net_settings.netclass_{assignments,patterns} out of the sibling
.kicad_pro and calls kicad.AnnotateNetClasses (WS1-037). It emits one row per (net, class) pair. A
design with no classes yields zero rows. That is the common case, and the companion marker below
exists for it.
Do not populate ir.Net.net_classes from IPC-2581. Its LogicalNet/@netClass is spelled the same but
is a singular CLOSED enum (CLK/FIXED/GROUND/SIGNAL/POWER/UNUSED)
describing what a net IS. net.ground and ir.Net.roles occupy that derived-role space, and
user-named constraint groups do not. Mixing the two would put GROUND and HighSpeed in one
relation, and a class-scoped query would then silently select the wrong nets.
Absence is not a pass ¶
Only a KiCad project read populates net class. An EDIF netlist, an IPC-2581 board, a bare
.kicad_sch opened without its project, and a KiCad project that simply declares no classes all leave
this relation empty. A rule SCOPED by net class then selects nothing, finds nothing, and reports
clean, and a review cannot tell that from a genuine pass. This case belongs to the false-pass family
(WS3-090 / 096 / 097 / 098 / 099). The other members reach a false pass through an empty datasheet
join or a requirement that compiles to nothing. This one reaches it through a scoping relation,
which is empty because the source carries no such data.
This relation guards against it with the capability gate. A netclass-scoped rule declares
check.CapNetClass, and check.Available reports it not-applicable, with the reason “design carries
no net-class assignments (only a KiCad project file supplies them)”, wherever the design assigns no
classes. The gate is content-derived, not format-derived, because for a scoped rule “this project
declares no classes” and “this format has no classes” are the same answer, with nothing in scope
either way. design.has_netclass is the queryable twin of that capability. An ad-hoc query can
ask it whether a class-scoped question is even answerable on this design before trusting its result.
Datalog ¶
Every classed net and its class:
net.netclass(?net, ?class) => ?net, ?class
Scope an existing question by the project’s own class, the way a vendor rule deck does, over the parts sitting on a high-speed net:
net.netclass(?net, "HighSpeed"), component.net(?ref, ?net) => ?ref, ?net
Guard it with design.has_netclass, so the query states that it only means something on a design that
assigns classes:
design.has_netclass(?_), net.netclass(?net, "HighSpeed"), component.net(?ref, ?net) => ?ref, ?net