I hope I understand the issue properly and that content below will unblock you.
First of all I’ll try to reduce your case to the image(s) below
a is contactPoint.Position (It’s a world position of contact point on body A)
b is contact point on triangle 2 of body B
c is position of body A
So first version of your ray that didn’t have a hit was from c to a and when you expanded it you managed to hit body b. Luckily for sphere a, b and c are colinear so extended ray was hitting the mesh in b (or around b due to numerical inaccuracies.
Next thing with the ray is that it does a cast on a world level so the hit can happen on either triangle 1 or triangle 2. It can be considered that as if triangle being hit is random from those two triangles. So the resulting normal may be the blue one which means that penetration can happen and then penetration recovery can bounce the sphere off. If b is a vertex shared between the triangles the result can just be worse.
It’s easy to create a situation where wrong triangle being hit can result in a ghost collision.
So if ray hits triangle 1 we get the ghost collision on the blue normal. Problem is that if ray hits triangle 2 and we get the green normal, the sphere is actually already in a penetration of that normal and penetration recovery kicks in right away.
I hope that this discourages everyone from using a raycast toward the contact point b on B
Now something about the potential solution.
As @petarmHavok proposed the collider should be casted and let’s consider how that helps. If we think about case of avoiding ghost collision and having a hit we will end up with following thing:
so we will cast body A from c to c’. The movement is just the velocity * dt. At the point of the callback the velocity of the body has already been adjusted by gravity effect in Unity.Physics. So cast hit will return the green normal and everything is fine.
Lets check the second case with the same approach:
We are doing the same thing just this time there is no hit. Since there is no hit we need to create some normal on our own. If we just disable the contact the triangle 2 may stay “unguarded” which may not be much of a problem on this diagram but in general it can be. So in this case we should form the green separation plane which is parallel to the movement vector. We shouldn’t rotate the plane more than that because overshooting may result in body A ending up in the immediate penetration like on the second diagram.
Important: Instead of doing the cast on the world level and ending up with the same normal for all contact points the collider cast has to be done on ((bodyA, colliderKeyA), (bodyB, colliderKeyB)) pair level. That is the only way to make sure that all original contacts are represented with proper ones after the cast.
How to do this? For this we need to do something similar to what @mpforce1 did. Luckily there is no need to change the physics code. This time we get the leaf collider through collider.getLeaf(key, out targetLeaf) and then we use the result as a target for the cast and call targetLeaf.Collider->castCollider(). Unfortunately this is unsafe. I hope that you are find with it.
Also, the input for castCollider has to be in the targetLeaf.Collider’s space.
I hope that this helps. I haven’t written the code myself although we should definitely provide some referenced implementation. Welding is a very hard problem and there is no solution for it that fits all the cases. Havok has been building solution for welding for a decade and it’s still not perfect, but still, using Havok has high probability of solving the welding problem for most of the games. I hope for those who cannot afford Havok this post gives enough information and reasoning around welding to try to implement solution that covers all their cases.