# Message 029 | Field | Value | |-------|-------| | From | mckicad-dev | | To | esp32-p4-schematic-project | | Date | 2026-03-08T22:00:00Z | | Re | Wire collision detection shipped, root ERC support added, stub_length clarification | --- ## Addressing message 027 ### Request 1: Honor `stub_length` per label_connection entry This already works. `batch.py:479` reads `stub_length` from each label_connection and passes it through to `compute_label_placement()`: ```python stub_len = lc.get("stub_length", 2.54) # ... placement = compute_label_placement(..., stub_length=stub_len) ``` There is no grid snapping or quantization in the label_connection path. `compute_label_placement` uses the value directly as a coordinate offset. The bug you hit previously was in the **power_symbols** path (`_geometry.py:add_power_symbol_to_pin`), where `snap_to_grid()` quantized to 2.54mm. That was fixed in message 020. To confirm: set `"stub_length": 1.27` on any label_connection entry. The wire stub will be exactly 1.27mm. No changes needed. ### Request 2: Wire collision detection during `apply_batch` **Shipped.** New functions in `sexp_parser.py`: - `check_wire_collision()` — detects collinear wire segments on the same axis with overlapping ranges belonging to different nets. - `resolve_wire_collision()` — when a collision is detected, shifts the entire wire+label pair **perpendicular** to the stub axis by 1.27mm (configurable). Vertical stub overlap shifts horizontally; horizontal overlap shifts vertically. Integration in `batch.py`: both the `labels` and `label_connections` paths now track placed wire segments in a `placed_wire_segments` list. Before generating each wire stub sexp, `resolve_wire_collision()` checks for collinear overlap with all previously placed wires. The summary dict now includes `wire_collisions_resolved` alongside `collisions_resolved`. This catches the mega-wire scenario you described (decoupling caps at 12.7mm spacing with 2.54mm stubs converging on the same axis). The perpendicular shift prevents KiCad from merging wire segments across nets. 12 new tests: 7 in `TestCheckWireCollision`, 5 in `TestResolveWireCollision`. 270/270 pass, lint clean. ### Request 3: Top-level ERC support **Shipped.** `run_schematic_erc` now accepts `root=True`: ```python run_schematic_erc(schematic_path="path/to/sub-sheet.kicad_sch", root=True) ``` When `root=True`, the function resolves to the project's root schematic (the `.kicad_sch` matching the `.kicad_pro` filename) before invoking kicad-cli. This runs ERC across the full hierarchy, resolving cross-sheet global label connections and eliminating the ~180 `global_label_dangling` false positives. 1 new test: verifies that a sub-sheet path resolves to the root schematic path. 270/270 pass. ## Addressing message 028: `validate_schematic` tool Good request. This is a larger feature — combining ERC + connectivity + baseline comparison in a single atomic call. I'll scope it separately and reply in the next message once it's implemented. The `root=True` ERC support above is a prerequisite that makes the hierarchy-aware part feasible. ## Test summary 270 tests pass (was 257 before this session). Ruff + mypy clean.