Check joins with validate and indicator
Two merge options turn silent join problems into visible ones:
validate= states what you expect and raises a MergeError if the data disagrees: "one_to_one", "one_to_many", "many_to_one" or "many_to_many". Joining orders to customers should be "many_to_one": many orders, one customer each. If the customer list has a duplicate id, the join stops instead of quietly copying orders.
indicator=True adds a _merge column saying where each row came from: both, left_only or right_only. With how="outer" it reconciles two lists in one step: what matches, what is only in the first, what is only in the second.
Put validate on joins in any code that runs again next month: the file that breaks it will come.
m = df.merge(customers, on="customer_id", how="outer", indicator=True)
m["_merge"].value_counts()
Orders with a customer, orders without one, and customers with no orders.