Summary
On tscircuit/spi-display-webcam-interceptor, tsci check reports a via from the U_BUF.pin7 -> U_MCU.pin6 route overlapping the adjacent U_MCU.pin5 pad/trace, even though the custom capacity-router input sets allowViaInPad: false.
The evidence indicates this is not the raw capacity solver choosing a via-in-pad location. The invalid location is introduced by the caller's post-routing transform after solver.getOutputSimpleRouteJson() returns. This issue is filed here because the failure occurs at the custom autorouter output boundary and the board already has an autorouter fixture/report; it may ultimately belong in core/output validation.
Reproduction
Board: https://github.com/tscircuit/spi-display-webcam-interceptor/tree/7c17e38d7e2fcdfc178b16614b13ce2b0da4c813
git clone https://github.com/tscircuit/spi-display-webcam-interceptor.git
cd spi-display-webcam-interceptor
git checkout 7c17e38d7e2fcdfc178b16614b13ce2b0da4c813
bun install
npx tsci check
Versions in the project:
tscircuit: ^0.0.2285
@tscircuit/capacity-autorouter: 0.0.785
Relevant existing autorouting input/report for this 87-connection ESP32-P4 phase:
Actual DRC errors
PCB trace trace[.U_BUF > port.pin9, .U_MCU > port.pin5] overlaps with pcb_via "pcb_via[#pcb_via_119]" (accidental contact)
Pad pcb_port[.U_MCU > .GPIO5] and trace trace[.U_BUF > port.pin7, .U_MCU > port.pin6] are too close (clearance: 0.05mm, minimum: 0.1mm)
pcb_via_119 belongs to source_trace_34 (U_BUF.pin7 -> U_MCU.pin6), while the overlapping neighboring route is source_trace_33 (U_BUF.pin9 -> U_MCU.pin5).
Final Circuit JSON geometry:
| Object |
Center |
Copper geometry |
U_MCU.pin5 / GPIO5 |
(-2.99999, 5.975102) |
top rectangular pad 0.6500114 x 0.1500124 mm |
U_MCU.pin6 / GPIO6 |
(-2.99999, 5.62509) |
top rectangular pad 0.6500114 x 0.1500124 mm |
pcb_via_119 on source_trace_34 |
(-2.8, 5.8) |
0.6 mm outer diameter, 0.3 mm drill |
Why it happens
Both the custom autorouter group and the AutoroutingPipelineSolver input explicitly set allowViaInPad: false.
After routing completes, however, the board calls normalizeToPlatedThroughVias(solver.getOutputSimpleRouteJson().traces). For source_trace_34, this transform finds the first MCU-side via and shifts the via plus coincident route points by -0.6 mm on X:
https://github.com/tscircuit/spi-display-webcam-interceptor/blob/7c17e38d7e2fcdfc178b16614b13ce2b0da4c813/index.circuit.tsx#L412-L442
The final via is at X -2.8, so its solver-returned X coordinate was approximately -2.2 before this transform. Moving it left by 0.6 mm places its copper inside the neighboring pin 5 pad and also creates the second pad-to-trace clearance error. The solver cannot account for an obstacle violation introduced after its output is returned.
Expected behavior / design question
At minimum this should be much easier to diagnose at the custom autorouter boundary. Possible directions:
- Validate custom
algorithmFn output against pads, traces, obstacles, and allowViaInPad before accepting it.
- Expose/reuse an autorouter output validation helper that callers can run after route post-processing.
- Have core emit a targeted error that identifies the returned connection and invalid via before conversion to Circuit JSON.
The immediate board fix is to remove this coordinate mutation and let the solver route the connection. The framework-level question is whether invalid geometry returned by custom output post-processing should be rejected or diagnosed by tscircuit-autorouter, or by tscircuit core when it consumes the custom router result.
Summary
On
tscircuit/spi-display-webcam-interceptor,tsci checkreports a via from theU_BUF.pin7 -> U_MCU.pin6route overlapping the adjacentU_MCU.pin5pad/trace, even though the custom capacity-router input setsallowViaInPad: false.The evidence indicates this is not the raw capacity solver choosing a via-in-pad location. The invalid location is introduced by the caller's post-routing transform after
solver.getOutputSimpleRouteJson()returns. This issue is filed here because the failure occurs at the custom autorouter output boundary and the board already has an autorouter fixture/report; it may ultimately belong in core/output validation.Reproduction
Board: https://github.com/tscircuit/spi-display-webcam-interceptor/tree/7c17e38d7e2fcdfc178b16614b13ce2b0da4c813
git clone https://github.com/tscircuit/spi-display-webcam-interceptor.git cd spi-display-webcam-interceptor git checkout 7c17e38d7e2fcdfc178b16614b13ce2b0da4c813 bun install npx tsci checkVersions in the project:
tscircuit:^0.0.2285@tscircuit/capacity-autorouter:0.0.785Relevant existing autorouting input/report for this 87-connection ESP32-P4 phase:
Actual DRC errors
pcb_via_119belongs tosource_trace_34(U_BUF.pin7 -> U_MCU.pin6), while the overlapping neighboring route issource_trace_33(U_BUF.pin9 -> U_MCU.pin5).Final Circuit JSON geometry:
U_MCU.pin5/ GPIO5(-2.99999, 5.975102)0.6500114 x 0.1500124 mmU_MCU.pin6/ GPIO6(-2.99999, 5.62509)0.6500114 x 0.1500124 mmpcb_via_119onsource_trace_34(-2.8, 5.8)0.6 mmouter diameter,0.3 mmdrillWhy it happens
Both the custom autorouter group and the
AutoroutingPipelineSolverinput explicitly setallowViaInPad: false.After routing completes, however, the board calls
normalizeToPlatedThroughVias(solver.getOutputSimpleRouteJson().traces). Forsource_trace_34, this transform finds the first MCU-side via and shifts the via plus coincident route points by-0.6 mmon X:https://github.com/tscircuit/spi-display-webcam-interceptor/blob/7c17e38d7e2fcdfc178b16614b13ce2b0da4c813/index.circuit.tsx#L412-L442
The final via is at X
-2.8, so its solver-returned X coordinate was approximately-2.2before this transform. Moving it left by0.6 mmplaces its copper inside the neighboring pin 5 pad and also creates the second pad-to-trace clearance error. The solver cannot account for an obstacle violation introduced after its output is returned.Expected behavior / design question
At minimum this should be much easier to diagnose at the custom autorouter boundary. Possible directions:
algorithmFnoutput against pads, traces, obstacles, andallowViaInPadbefore accepting it.The immediate board fix is to remove this coordinate mutation and let the solver route the connection. The framework-level question is whether invalid geometry returned by custom output post-processing should be rejected or diagnosed by
tscircuit-autorouter, or by tscircuit core when it consumes the custom router result.