Do you know the max number of cross joins ahead of time?
What I'd probably do in this case is to build a static table like the one I posted covering a "safe" level. When processing new data I would check if the nesting level would be sufficient and, if not, call as separate proc that would rebuild that table with expanded levels (most probably max_level + 1).
To query the data I would use an iTVF with the number of shippings as an input parameter to return the reduced matrix.
Basically, the "matrix" table would either be created based on a dynamic SQL statement to cover the unknown levels (including re-creation of the iTVF) or I would throw an exception and redo it script based (depending on the business requirement).
I might even add a pre-warning alert to send me an email if I'd have a level of 20 covered and there will be data 18 levels deep... It depends. 😉
But I agree trying to avoid looping for each shipment.