feat(check): add tsci check opens to detect unrouted nets - #4326
Draft
Reiss-Cashmore wants to merge 3 commits into
Draft
feat(check): add tsci check opens to detect unrouted nets#4326Reiss-Cashmore wants to merge 3 commits into
tsci check opens to detect unrouted nets#4326Reiss-Cashmore wants to merge 3 commits into
Conversation
`tsci check shorts` catches copper that is joined when it should not be. Nothing caught the inverse: a net the autorouter silently failed to route. The build succeeds, no short exists, and the board is dead — a real board shipped this way with two unrouted button ground legs. `tsci check opens` reports any net whose copper is split across more than one island, using findBitmapOpens from @tscircuit/check-shorts. Mirrors check shorts: same --mode/--layer/--pixels-per-mm options, same CDN-or-package loading, and exits 1 when opens are found so CI and pre-fab scripts can gate on it.
Opens are a whole-board question in a way shorts are not. A net routed top -> via -> bottom is fully connected, but examined one layer at a time it looks split on both, so running the detector per layer reported an open for essentially every routed net (41 false positives on a real two-layer board; 0 after this change). `--layer all` now means one analysis spanning every copper layer, which is the detector's default. An explicit `--layer top|bottom` still scopes to that single layer.
Reiss-Cashmore
marked this pull request as draft
August 17, 2026 00:46
Some nets are joined off the board by design — mounting holes bonded through a metal enclosure, signals joined by a cable or mating connector. Circuit JSON cannot express "joined outside the board", so the copper for such a net is legitimately split and the check would report a false open. --ignore-net <name> (repeatable) maps to the detector's ignoreNets option and suppresses exactly those nets by name; any other net still reports, so ignoring an unrelated net cannot mask a real fault (covered by a test). The suppression test feature-detects ignoreNets in the resolved check-shorts typings and activates once the pinned dependency is bumped past 0.0.19.
Contributor
|
This PR has been automatically marked as stale because it has had no recent activity. It will be closed if no further activity occurs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
tsci check shortscatches copper joined when it should not be. Nothing catchesthe inverse — a connection that was declared but never routed. The build
succeeds, no short exists, and the board is dead.
That happened to me: a board shipped with two push-button ground legs unrouted,
and no part of the toolchain could have told me before I paid for it.
Change
Adds
tsci check opens, mirroringcheck shorts:--mode pcb|gerber,--layer top|bottom|all,--pixels-per-mm--ignore-net <name>(repeatable) for nets joined off the board by design —mounting holes bonded through a metal enclosure, signals joined by a cable or
mating connector. Circuit JSON cannot express "joined outside the board", so
suppression is explicit and per net name; ignoring an unrelated net cannot
mask a real open (covered by a test)
loadCheckShorts)One behavioural difference from
check shortsworth flagging: opens are awhole-board question. A net routed top -> via -> bottom is fully connected, but
examined one layer at a time it looks split on both. Running per layer reported
an open for essentially every routed net (41 false positives on a real two-layer
board; 0 after). So
--layer allruns a single analysis spanning every copperlayer, while an explicit
--layer top|bottomstill scopes to that layer.False positives and scope — why this is a command, not a default gate
Before wiring this into the pipeline I probed the detector against hardware
that legitimately expects disjoint copper on one net; the full analysis and the
fixes it produced live in tscircuit/check-shorts#49. Summary:
(
internallyConnectedPins— switch poles, relay contacts) and bridged solderjumpers were real false positives; declared internal connections now bridge
islands the way vias bridge layers. This also keeps the check compatible with
pushbutton: documented default internal pin connections are absent core#3115 (emitting pushbutton internal connections), which would
otherwise have made it flag every 4-leg tactile switch.
--ignore-net.GND pin have the identical circuit-JSON signature — one is a design, the
other is my dead board. Silencing one masks the other, so same-net
two-terminal links remain a documented false positive (model as two nets, or
--ignore-net). Prebuilt circuit JSON captured before external routing(FreeRouting-style workflows) also flags everything, truthfully but noisily.
Because of that residual set,
check opensis an explicitly-invokedsubcommand — it is not added to any aggregate check, and it only exits
non-zero when the user runs it. Whether it should ever run by default, and at
what severity, is left as a maintainer decision with the analysis above as
input.
Tests
tests/cli/check/check-opens.test.ts— an unrouted connection is reported; afully routed board reports nothing; an enclosure-joined net flags by default;
--ignore-netsilences exactly that net (feature-detected against the resolvedcheck-shorts typings, activates when the pin is bumped past 0.0.19); ignoring
an unrelated net does not mask a real open.