Skip to content

fix: reject net-label candidates whose connector runs along another net - #723

Open
DPS0340 wants to merge 5 commits into
tscircuit:mainfrom
DPS0340:fix/connector-collinear-overlap
Open

fix: reject net-label candidates whose connector runs along another net#723
DPS0340 wants to merge 5 commits into
tscircuit:mainfrom
DPS0340:fix/connector-collinear-overlap

Conversation

@DPS0340

@DPS0340 DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown

Stacked on #719 — that should merge first. This adds a second predicate to the same check.

Problem

#719 rejects net-label candidates whose connector crosses another net. But crossing isn't the only way a connector misleads: one laid along another net's trace renders as a single wire carrying two nets. The crossing predicate can't catch it, because collinear segments never intersect at a point.

Exactly one instance in the corpus, on bug-report-20260707T092615Z:

V overlap, length 0.141
  A  C_SENSE.2-C1.2                        net=connectivity_net1   (-9.809,-1.705)→(-9.809,-1.905)
  B  available-net-orientation-13-BAT_POS  net=connectivity_net13  (-9.809,-2.915)→(-9.809,-1.764)

Same x, overlapping y ranges, different nets — drawn as one wire.

Fix

segmentsOverlapCollinearly in geometry.ts, and a rejection in getCandidateStatus sitting directly beside the crossing rejection #719 adds. Reuses the existing trace-collision status, so no new candidate state.

The predicate requires a shared length, not a shared point: touching at one point is a crossing or a junction, both of which are legitimate and handled elsewhere.

Result

different-net collinear overlaps:  1 -> 0

Everything else holds steady:

trace crossings:      19 -> 19   (as left by #719)
labels inside chips:   8 ->  8
label-label overlaps:  7 ->  7
diagonal segments:     2 ->  2

Verification

  • Full suite 168 pass / 0 fail / 4 skip, tsc --noEmit clean, biome clean.
  • 2 snapshots regenerated.
  • repro-atmega328p-missing-gnd-netlabel is one of them, and the name is alarming, so I checked it rather than accepting the regeneration. That test only asserts a snapshot, no behaviour. Comparing label output against main:
    main:     18 labels — GND, VCC_3V3, X_IN1, X_IN2, Y_IN1, Y_IN2, …
    this PR:  18 labels — GND, VCC_3V3, X_IN1, X_IN2, Y_IN1, Y_IN2, …
    
    Identical count and identical net list, GND included. The labels moved, none were lost — the property that repro exists to protect is intact.

Diff: 2 source files plus the 2 snapshots.

@vercel

vercel Bot commented Jul 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
schematic-trace-solver Ready Ready Preview, Comment Jul 26, 2026 3:58am

Request Review

DPS0340 added 4 commits July 26, 2026 12:47
Adds a helper that counts places where traces on different nets properly
cross, and a test that pins the current count for every imported bug
report.

These are current values, not targets — several of these boards are open
bugs. The point is that a routing or cleanup change which makes a board
worse now fails a named assertion instead of disappearing into a
regenerated SVG snapshot.

Verified the guard bites: changing the expected count for
bug-report-20260706T213649Z from 11 to 10 fails with 'Expected: 10,
Received: 11'.
tscircuit#727 (TraceOverlapShiftSolver) fixed the RP2040 USB-C overlap and moved
bug-report-20260707T092615Z from 2 different-net crossings to 3. Measured
either side of that merge:

  ca7e80c (before)  TOTAL 40, this board 2
  be20aa7 (tscircuit#727)    TOTAL 41, this board 3

Pinned at the current value with a comment recording the change, and
reported it on tscircuit#727 so the trade is visible rather than absorbed.
getCandidateStatus already checks the candidate's connector against chips
and other net labels, but never against existing traces. A candidate could
therefore be accepted while its connector cut straight across a different
net, which reads as a short in the rendered schematic.

Reuse the existing tracePathCrossesAnyTrace helper, filtered to traces on
other nets, and reject those candidates so the search moves to the next one.

Measured across every imported bug report: 40 -> 19 different-net
crossings, 7 boards improved, none regressed. Worst board goes 11 -> 4,
and two boards reach zero.
Follow-up to the crossing check: a connector laid collinearly on top of
another net's trace renders as a single wire carrying two nets, which is at
least as misleading as a crossing. The crossing predicate does not catch it
because the segments never intersect at a point.

Adds segmentsOverlapCollinearly and rejects such candidates in
getCandidateStatus, beside the existing crossing rejection.

Different-net collinear overlaps across the imported bug reports: 1 -> 0.
Crossings, label placement and diagonal counts unchanged.
@DPS0340
DPS0340 marked this pull request as draft July 26, 2026 03:50
@DPS0340
DPS0340 force-pushed the fix/connector-collinear-overlap branch from 40d8a36 to 4e4db9b Compare July 26, 2026 03:50
@DPS0340

DPS0340 commented Jul 26, 2026

Copy link
Copy Markdown
Author

Moved to draft — this PR regresses #727, which merged a few hours ago. Reporting it against myself rather than letting it sit as ready.

After rebasing onto current main, repro-rp2040-usb-cc2-ground-overlap fails:

expect(cc2LabelConnector).toBeDefined()
Received: undefined

The collinear-overlap predicate this PR adds rejects every candidate orientation for the CC2 label, so no connector is generated at all. #727 fixed that board by shifting the overlapping trace; my check instead removes the label connector, which is worse than the original bug.

Crossing counts, for completeness:

main            TOTAL 41   (092615Z: 3)
+ #718 #719     TOTAL 20   (092615Z: 3)
+ #723 (this)   TOTAL 19   (092615Z: 2)

So it does buy one more crossing and improves 092615Z back to its pre-#727 value — but not at the cost of dropping a connector.

#719 is unaffected and stays ready. It is rebased onto current main, 167 tests pass, and it does not touch the collinear predicate.

I'll rework this one to fall back to the best available orientation instead of rejecting outright when no overlap-free candidate exists, then re-measure against #727's test. Not asking for review until that passes.

The collinear-overlap check rejected every candidate orientation for the
RP2040 CC2 label, so no connector was generated at all — regressing tscircuit#727,
which had just fixed that board by shifting the overlapping trace.

Leaving a label unattached is worse than an overlap the cleanup passes can
still shift, so the rejection is now a preference: try for an overlap-free
orientation, and if none exists take the best available one.

The fallback fires 28 times across the imported bug reports, so it is load
bearing rather than defensive.

  repro-rp2040-usb-cc2-ground-overlap   pass (was: cc2LabelConnector undefined)
  full suite                            167 pass, 0 fail
  different-net crossings               TOTAL 20
@DPS0340

DPS0340 commented Jul 26, 2026

Copy link
Copy Markdown
Author

Reworked as described — the #727 regression is fixed and this is ready again.

The problem was that the collinear-overlap check rejected every candidate orientation for the RP2040 CC2 label, so no connector was emitted at all. Leaving a label unattached is worse than an overlap the cleanup passes can still shift, so the rejection is now a preference rather than a veto:

try for an overlap-free orientation
  ↓ none found
take the best available one anyway

Same shape as the existing crossing check.

Verification:

before after
repro-rp2040-usb-cc2-ground-overlap cc2LabelConnector undefined ✅ pass
full suite 165 pass / 2 fail 167 pass / 0 fail
different-net crossings TOTAL 19 TOTAL 20

The total goes from 19 back to 20 — that one crossing was bought by dropping a connector, so it was never a real gain. Still an improvement on the 41 that current main measures.

I also checked the fallback isn't dead code: instrumented it across all imported bug reports and it fires 28 times, so it is load-bearing, not defensive.

Stacked on #719, which is unaffected and already ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant