You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reach the last testable corners of the collision code
Five branches of _ibc.py had no coverage, and each turned out to be the mirror
image of a covered one, told apart only by a choice the caller never makes
deliberately. So each is pinned as an invariance rather than a value.
The 3D slider names the edge an agent leaves by its position in the triangle --
Q0Q1, Q1Q2 or Q2Q0 -- and branches on which. Every 3D case in the suite writes
the shared edge first, so the middle branch was unreachable by construction.
Cyclically rolling one triangle's vertices walks all three in turn, and the
resolved position is bit-identical across them, which is the actual contract:
where a vertex list starts is an accident of the mesh file. Rotation rather than
an arbitrary permutation, so the winding and hence the normal are preserved.
The moving slider has the same shape twice over. Which of an adjacent element's
two vertices is the shared one decides a branch, so the wedged-agent case now
runs both orderings and compares them directly -- the only way to see the two
disagree. That case also leaves its element by the second vertex rather than the
first, which nothing else in the moving suite did.
The travel-reversal critical time only binds when the element turns through the
perpendicular to the agent's travel, which no translating or tilting wall does;
a pivot from 60 to 120 degrees flips the projection from +2 to -2. The test
asserts that sign change, so it cannot quietly stop exercising the branch.
Contact arriving at the very end of the step is covered too, where the slider
skips the projection entirely and only backs the agent off.
The moving stack-exhaustion re-raise gets its own case: it is a different
routine from the static one, so covering that said nothing about this. It does
not exhaust the real stack -- every element the moving slider crosses costs an
ODE solve, so doing that naturally took about three seconds. The limit is
lowered relative to the depth already in use instead, which runs in 0.27s and
does not depend on the platform's stack size. RecursionError subclasses
RuntimeError, so the explained failure is told from a bare one by inspecting it
rather than by the except clause.
Also fixes a typo in a raise the tests cannot reach: Brenq -> Brentq.
Coverage of _ibc.py goes from 96% to 99%. The seven lines left are three
placeholders behind the 3D-moving NotImplementedError, two numerical corners
documented in place as unreachable, and two solver non-convergence raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
0 commit comments