fix(wire_connectivity): pwr-flags must not bridge unrelated power rails (#177)

Every power:PWR_FLAG symbol carries Value="PWR_FLAG" — the ERC marker
inherits its rail's name from the wire/label it sits on. Commit 7f3a379
added #FLG symbols to the same handling loop as #PWR power ports inside
_parse_virtual_connections, so every pwr-flag was getting appended to
label_to_points["PWR_FLAG"]. The BFS in _find_connected_wires uses
label_to_points for virtual jumps; reaching any pwr-flag pin caused it
to teleport to every other pwr-flag pin, walking across each one's stub
wire into a different power rail. The result: get_net_connections(rail)
returned the union of pins on every rail that had a pwr-flag, for any
rail.

Fix: pwr-flag pin positions still register as anchors in point_to_label
(preserving the original intent of 7f3a379 so find_orphaned_wires keeps
accepting them), but they no longer enter label_to_points. The pwr-flag
remains electrically connected to its rail via the wire-graph BFS through
the wire it sits on; the label-jump mechanism is unnecessary for that
path and actively harmful when the "label" is the same for unrelated
rails.

Tests: three unit tests on _parse_virtual_connections cover the bug
(over-merge gone), regression check (power ports still work in both maps),
and edge case (pwr-flag and port at same point — port name wins). All
three fail on main, pass on this branch.

Full suite: 667 passed, 11 skipped, 0 regressions (modulo the pre-existing
tests/test_get_pin_angle.py collection error which is unrelated to
wire_connectivity).

End-to-end verification on a single-sheet schematic with 7 distinct
power rails each carrying a pwr-flag: every queried net now matches
the official kicad-cli netlist output (modulo a separate library-symbol
bug on PCM_Diode_Schottky_AKL:MBRS130 with duplicate pin definitions,
out of scope here).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
blinksoft
2026-05-18 13:53:34 -04:00
committed by GitHub
parent 1f095cff59
commit 68b8bbf2fb
2 changed files with 235 additions and 3 deletions

View File

@@ -236,7 +236,9 @@ def _parse_virtual_connections(
if not hasattr(symbol, "property") or not hasattr(symbol.property, "Reference"):
continue
ref = symbol.property.Reference.value
if not (ref.startswith("#PWR") or ref.startswith("#FLG")):
is_pwr_port = ref.startswith("#PWR")
is_pwr_flag = ref.startswith("#FLG")
if not (is_pwr_port or is_pwr_flag):
continue
if ref.startswith("_TEMPLATE"):
continue
@@ -248,8 +250,28 @@ def _parse_virtual_connections(
continue
pin_data = all_pins["1"]
pt = _to_iu(float(pin_data[0]), float(pin_data[1]))
point_to_label[pt] = name
label_to_points.setdefault(name, []).append(pt)
if is_pwr_port:
# Power-port symbol: Value is the net name (+BATT, GND, ...).
# Register in both maps so BFS-via-label-jump can bridge to
# other instances of the same named power net.
point_to_label[pt] = name
label_to_points.setdefault(name, []).append(pt)
else:
# Power-flag symbol (#FLG*): Value is always "PWR_FLAG" — an
# ERC marker, not a net name. The pin position is registered
# in point_to_label so find_orphaned_wires accepts wire ends
# terminating on a PWR_FLAG as valid anchors. It is NOT added
# to label_to_points: doing so would let BFS-via-label-jump
# virtually bridge every distinct power rail that has a
# pwr-flag into one mega-net (since every #FLG shares
# Value="PWR_FLAG"). The pwr-flag remains electrically
# connected to its rail via the wire-graph BFS through the
# wire it sits on; the label-bridge mechanism is unneeded
# and actively harmful here.
# setdefault avoids clobbering an upstream power-port label
# in the unlikely case that one sits at the same point.
point_to_label.setdefault(pt, name)
except Exception as e:
logger.warning(f"Error parsing power symbol: {e}")