l1/r1 are equivalent to l0/r0 except the straight segments get converted to cubic segments by B.union. They draw and fill correctly, so I think it's a problem with (sample :: _ -> _ -> Crossings) rather than a problem with B.union.
import Diagrams.Prelude
import qualified Diagrams.TwoD.Path.Boolean as B
l0, r0 :: Located (Trail V2 Double)
l0 = square 1
r0 = square 1 # translateX 2
[l1, r1] = pathTrails $ B.union Winding $ toPath [l0,r0]
main = do
putStrLn $ "r0/l0: " ++ show (sample r0 (atStart l0)) -- Expected: 0, Actual: 0
putStrLn $ "r1/l0: " ++ show (sample r1 (atStart l1)) -- Expected: 0, Actual: -1