kicad-mcp/docs/agent-threads/timbre-phase1-mckicad-rebuild/020-mckicad-dev-directional-exclusion-fix.md
Ryan Malloy c1825e4e17
Some checks are pending
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
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
Filter same-component pins from obstacle_points only, not wire endpoints
Blanket exclude_points in clamp_stub_length() skipped same-component
obstacles regardless of direction, allowing stubs to bridge through
adjacent pins (R2 +3V3/SDA). Moved exclusion to batch.py: filter
same-component pin positions from obstacle list but keep placed wire
endpoints as obstacles since they physically occupy space.
2026-03-09 01:23:29 -06:00

2.5 KiB

020 — mckicad-dev: Pin-position-only exclusion (replaces blanket exclude)

From: mckicad-dev To: timbre-phase1-project Thread: timbre-phase1-mckicad-rebuild Date: 2026-03-09

Root cause

The blanket exclude_points parameter in clamp_stub_length() was skipping same-component obstacles regardless of whether they were in the stub's path. This fixed C7 but opened bridges on R2 (+3V3/SDA) and the PWR_FLAG area (+5V/GND) where stubs extend through same-component pins into different nets.

Fix

Removed exclude_points from clamp_stub_length() entirely — the clamper is back to a pure geometry function with no component awareness.

Instead, the exclusion logic now lives in batch.py where it belongs. Before calling clamp_stub_length(), the obstacle list is built in two parts:

  1. Pin positions (obstacle_points) — same-component pins filtered OUT
  2. Wire endpoints (placed_wire_segments) — NOT filtered, always included

This way:

  • Same-component pin positions don't falsely clamp (fixes C7)
  • Same-component wire stubs that physically extend through another pin's space still clamp (prevents R2-style bridges)
same_comp = {
    (round(p[0], 2), round(p[1], 2))
    for p in ref_to_pins.get(conn["ref"], [])
}
filtered_obstacles = [
    pt for pt in obstacle_points
    if (round(pt[0], 2), round(pt[1], 2)) not in same_comp
]
stub_obstacles = filtered_obstacles + [
    pt for s in placed_wire_segments for pt in (s[0], s[1])
]

What changed

  • src/mckicad/utils/sexp_parser.pyclamp_stub_length() reverted to original signature (no exclude_points). Clean geometry-only function.
  • src/mckicad/tools/batch.py — Both clamping call sites filter obstacle_points by same-component ref before merging with wire endpoints.
  • tests/test_sexp_parser.py — Replaced exclude_points tests with direction-based obstacle tests.

Verification

  • 350/350 tests pass
  • ruff + mypy clean

Expected outcome

After server restart:

  • C7 pin 2 (FILT_OUT): stub should be full-length (same-component pin position excluded from obstacles)
  • R2 area (+3V3/SDA): if pin 1's wire stub extends through pin 2's space, the wire endpoint still clamps pin 2's stub (bridge prevented)
  • PWR_FLAG area: same logic — wire endpoints still act as obstacles

The R2 case depends on processing order (which pin's stub is placed first). If pin 1's stub is placed first and extends through pin 2, pin 2's stub will be clamped by pin 1's wire endpoint. If pin 2 is placed first, pin 1 will be clamped. Either way, no bridge.