Hi Jim - Join fails because the edges are not within tolerance, BU succeeds because the bottom face of the upper object is trimmed by the upper edges of the lower object and at least some of the resulting edges are within tolerance.
Join depends upon edges being within tolerance, Booleans depend on being able to trim the objects with curves of intersection.
I would extract the top face of the bottom obiect, and the bottom face of the top object (delete) and use Trim then Join here.
-Pascal
I am trying to write down a build sequence that is reliable. The ultimate problem is that the whole assembly has parts on top and bottom of a partially matching edge curve. I’ll try the trim and see how it goes.