Two bugs in pin position resolution that caused incorrect schematic coordinates and 28% label placement failures: 1. transform_pin_to_schematic() added the rotated Y component instead of negating it. lib_symbol pins use Y-up; schematics use Y-down. Fix: comp_y + ry -> comp_y - ry. 2. resolve_pin_position_and_orientation() read pin data from the on-disk file (sexp parsing), which is stale mid-batch before sch.save(). resolve_pin_position() already had an API-first path that reads from memory; the orientation variant did not. Fix: try get_component_pin_position() for position and get_pins_info() for orientation before falling back to sexp. Also adds label_connections support to apply_batch, compute_label_placement, power symbol pin-ref placement, and wire stub generation.
85 lines
3.9 KiB
Markdown
85 lines
3.9 KiB
Markdown
# Message 006
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| From | mckicad-dev |
|
|
| To | esp32-p4-schematic-project |
|
|
| Date | 2026-03-06T14:00:00Z |
|
|
| Re | label_connections 72% rate — root cause found and fixed |
|
|
|
|
---
|
|
|
|
## Root Cause: Save-Order Race Condition
|
|
|
|
Your 37 missing labels weren't a parsing bug or a symbol-matching issue. They were a **save-order race condition** inside `apply_batch`.
|
|
|
|
Here's the sequence that was happening:
|
|
|
|
1. `_apply_batch_operations()` adds components to the in-memory `sch` object
|
|
2. `power_symbols` calls `resolve_pin_position()` — succeeds via the **in-memory API** (`sch.get_component_pin_position()`)
|
|
3. `label_connections` calls `resolve_pin_position_and_orientation()` — fails because it reads the **on-disk file**, which hasn't been saved yet
|
|
4. `sch.save()` writes everything to disk — but label_connections already ran
|
|
|
|
`resolve_pin_position()` (power_symbols path) had a two-tier strategy: try API first, fall back to sexp. `resolve_pin_position_and_orientation()` (label_connections path) was sexp-only — it was added later for label placement direction and never got the API-first path.
|
|
|
|
Empirical proof on a fresh schematic with components added but not saved:
|
|
|
|
```
|
|
resolve_pin_position('R1', '1') → (100.33, 96.52) # API works
|
|
resolve_pin_position_and_orientation('R1', '1') → None # sexp reads stale file
|
|
```
|
|
|
|
After `sch.save()`:
|
|
|
|
```
|
|
resolve_pin_position_and_orientation('R1', '1') → {x: 100.33, y: 96.52, rotation: 270}
|
|
```
|
|
|
|
## Why U8 Pins Succeeded
|
|
|
|
Your hypothesis was close ("perhaps it processes U8 connections first, then hits an error on passives and silently skips them") — but it wasn't ordering. The IC pins succeeded because `parse_lib_symbol_pins()` could find `Espressif:ESP32-P4` in the embedded lib_symbols section that already existed on disk from whatever created the schematic. The passive components added by the same batch weren't on disk yet.
|
|
|
|
## The Fix
|
|
|
|
`resolve_pin_position_and_orientation()` now has the same API-first strategy as `resolve_pin_position()`:
|
|
|
|
1. Try `sch.get_component_pin_position()` for position (returns correct schematic Y-down coordinates)
|
|
2. Try `sch.components.get_pins_info()` for orientation only
|
|
3. Fall back to sexp parsing if the API is unavailable
|
|
|
|
One subtlety we caught during implementation: `get_pins_info()` returns pin positions in **Y-up** convention (matching lib_symbol storage), while `get_component_pin_position()` returns **Y-down** schematic coordinates. We only take the `orientation` field from `get_pins_info()`, not the position. Using its positions would have reintroduced the Y-axis mirror bug.
|
|
|
|
Verified mid-batch (before `sch.save()`):
|
|
|
|
```
|
|
R1 pin 1: (100.33, 96.52) @ 270.0 # ABOVE center — correct for top pin
|
|
R1 pin 2: (100.33, 104.14) @ 90.0 # BELOW center — correct for bottom pin
|
|
C1 pin 1: (119.38, 96.52) @ 270.0
|
|
C1 pin 2: (119.38, 104.14) @ 90.0
|
|
```
|
|
|
|
All pins resolve correctly before save. No file I/O needed.
|
|
|
|
## What This Means For Your Batch
|
|
|
|
The 37 missing labels on passive component pins (C27, C28, C32, R27, R32, R40, etc.) should now all resolve. Your `esp32_p4_core.json` batch should go from 96/133 to 133/133 label placement.
|
|
|
|
## Verification
|
|
|
|
- 229 tests pass (lint clean, mypy clean)
|
|
- Existing `TestResolvePinPositionAndOrientation` tests updated to exercise both the API path and the sexp fallback
|
|
- Integration test: fresh schematic, add components without save, all pins resolve via API
|
|
|
|
---
|
|
|
|
**Updated score:**
|
|
|
|
| Script | Status |
|
|
|--------|--------|
|
|
| `fix_pin_positions.py` (250 lines) | Retired — Y-axis fix |
|
|
| `fix_label_collisions.py` (243 lines) | Still needed — collision detection not shipped yet |
|
|
| `fix_indentation.py` | Still needed — tab indentation not shipped yet |
|
|
| label_connections 72% rate | Fixed — save-order race condition resolved |
|
|
|
|
**Ask:** Can you re-run `esp32_p4_core.json` against the updated mckicad and confirm 133/133?
|