tscircuit / tscircuit/schematic-trace-solver
bug: nearly axis-aligned segments escape all obstacle collision checks, letting traces pass through chips
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13
- Forks
- 314
- Avg merge
- 9h 3m
- Merged PRs (30d)
- 132
Description
Summary
segmentIntersectsRect reports no collision for any segment that is neither exactly vertical nor exactly horizontal. Segments that are only nearly axis aligned therefore escape every obstacle check, and a recovered trace can run straight through a chip body.
Root cause
In lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions.ts:
const EPS = 1e-9
...
const vert = isVertical(a, b, eps)
const horz = isHorizontal(a, b, eps)
if (!vert && !horz) return false
EPS is 1e-9, but real pin coordinates are not always exactly on the routing grid. A pin at x = 5.3999378 connected to one at x = 5.4 produces a segment with dx = 6.22e-5. That is far below the schematic grid, yet five orders of magnitude above 1e-9, so isVertical is false, isHorizontal is false, and the early return declares the segment collision free.
Everything downstream trusts that answer. UnroutedTraceRecoverySolver checks each candidate with pathCollidesWithObstacles and accepts the first that passes, so the skewed candidate is accepted and emitted as the final trace.
Minimized reproducer
{
"chips": [
{
"chipId": "schematic_component_4",
"center": { "x": 5.4, "y": 2.4 },
"width": 0.3041465,
"height": 0.9,
"pins": [
{ "pinId": "SJ2.1", "x": 5.3999378, "y": 1.9499999999999997, "_facingDirection": "y-" }
]
},
{
"chipId": "schematic_component_5",
"center": { "x": 5.555, "y": 1.2 },
"width": 1.21,
"height": 0.6,
"pins": [
{ "pinId": "R3.2", "x": 5.4, "y": 1.5, "_facingDirection": "y+" }
]
},
{
"chipId": "schematic_component_8",
"center": { "x": 5.555, "y": 1.2 },
"width": 0.555,
"height": 0.9,
"pins": []
}
],
"directConnections": [
{ "pinIds": ["SJ2.1", "R3.2"], "netId": ".SJ2 > .pin1 to .R3 > .pin2" }
],
"netConnections": [],
"availableNetLabelOrientations": {}
}
Observed
The solver reports solved, and netLabelToTraceSolver.getOutput().traces contains one trace:
SJ2.1-R3.2: (5.3999378, 1.95) -> (5.4, 1.5000000000000004)
schematic_component_8 spans x [5.2775, 5.8325], y [0.75, 1.65]. The segment enters that rect at y = 1.65 and ends at y = 1.5, so 0.15 units of it are inside a chip the trace does not terminate on.
Calling the helper directly confirms the check itself is what fails:
segmentIntersectsRect({x:5.3999378,y:1.95}, {x:5.4,y:1.5}, chip8) === false
segmentIntersectsRect({x:5.4, y:1.95}, {x:5.4,y:1.5}, chip8) === true
Only the 6e-5 skew separates the two calls.
Expected
A segment that passes through a chip body should be reported as colliding regardless of a sub-grid skew, so UnroutedTraceRecoverySolver rejects the candidate and picks a routed alternative.
Sub-solver
Detection lives in SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions.ts; the visible symptom surfaces through UnroutedTraceRecoverySolver.
Notes
This is not specific to co-located chips. The same trace crosses the blocking chip when that chip is moved off the other chip's center and given a real pin, so it is a general obstacle-detection gap rather than a degenerate-input artifact. Found by differential fuzzing over the fixtures in tests/bug-reports and tests/examples; two independent fuzzed inputs reduce to this same root cause.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions.ts and reproduce the minimized case with segmentIntersectsRect. Check the related pathCollidesWithObstacles flow in UnroutedTraceRecoverySolver, using fixtures in tests/bug-reports and tests/examples. Done means the skewed segment is reported as colliding and recovery rejects it in favor of a routed alternative.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100