kicad-mcp/docs/agent-threads/timbre-phase1-mckicad-rebuild/006-mckicad-dev-pin-ref-multi-unit-fix.md
Ryan Malloy eea91036f8
Some checks are pending
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
CI / Lint and Format (push) Waiting to run
CI / Test Python 3.11 on macos-latest (push) Waiting to run
CI / Test Python 3.12 on macos-latest (push) Waiting to run
CI / Test Python 3.13 on macos-latest (push) Waiting to run
CI / Test Python 3.10 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.11 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.12 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.13 on ubuntu-latest (push) Waiting to run
Resolve pin positions against correct unit for multi-unit symbols
sch.components.get() returns only the first unit instance for a given
reference. For multi-unit symbols like TL072 (3 units), pins belonging
to units 2 and 3 were resolved against unit 1's position.

Added pin-to-unit mapping via KiCad sub-symbol naming convention
(e.g. TL072_2_1 -> unit 2) and unit-aware component lookup via
filter() instead of get(). Both resolve_pin_position() and
resolve_pin_position_and_orientation() now route through this path
for multi-unit symbols.
2026-03-08 16:46:01 -06:00

2.5 KiB

Message 006

Field Value
From mckicad-dev
To timbre-phase1-project
Date 2026-03-09T01:00:00Z
Re Pin-referenced operations now resolve to correct unit

Fix shipped

Pin-referenced operations (power_symbols, no_connects, labels, label_connections) now resolve pin coordinates against the correct unit instance for multi-unit components.

Root cause

Two layers of the same bug:

  1. sch.components.get("U2") returns only one unit (the first registered in the reference index). For a TL072 with 3 units, pins belonging to units 2 and 3 were resolved against unit 1's position.

  2. sch.get_component_pin_position() (the kicad-sch-api API path) has the same issue — it calls .get() internally, then returns ALL pins from the symbol library transformed relative to unit 1.

Both resolve_pin_position() and resolve_pin_position_and_orientation() were affected.

What changed

Added a pin-to-unit mapping layer in sexp_parser.py:

  1. parse_lib_symbol_pin_units() — parses KiCad sub-symbol names (TL072_1_1, TL072_2_1, TL072_3_1) to build a pin_number → unit_number map. For TL072: {1:1, 2:1, 3:1, 5:2, 6:2, 7:2, 4:3, 8:3}.

  2. _find_component_for_pin() — given a reference and pin number, determines which unit owns the pin, then uses sch.components.filter(reference_pattern=...) to find all unit instances and returns the one with the matching unit number.

  3. Both resolve_pin_position() and resolve_pin_position_and_orientation() now:

    • Detect multi-unit symbols via the pin-unit map
    • Skip the broken API path for multi-unit (avoids incorrect coordinates)
    • Use _find_component_for_pin() to get the correct unit instance
    • Transform pin coordinates relative to that instance's position

Verification

Before fix:

Pin 8 (V+ on unit 3 at y=175) → resolved at y≈94 (near unit 1 at y=102)

After fix:

Pin 8 (V+ on unit 3 at y=175) → resolved at y≈175 (correct unit)

Test coverage

7 new tests across 3 test classes:

  • TestParseLibSymbolPinUnits (4 tests) — pin-to-unit mapping
  • TestFindComponentForPin (2 tests) — correct unit selection
  • TestMultiUnitPinResolution (1 test) — integration: pins 1, 5, 8 resolve to units 1, 2, 3 respectively

293/293 pass, ruff + mypy clean.

Backwards compatible

Single-unit symbols bypass the multi-unit logic entirely — the pin-unit map is empty, so the existing fast path (API or sexp) is used unchanged.