The best [free] solution we have is to set up an External Dependency schedule (EDS). My program has 10 individual teams, each with their own schedule. For external dependencies, they connect to the EDS. The predecessor task is duplicated in the EDS with the actual task a predecessor (typically set as FF). The successor task is then linked to that EDS task. This way, if anyone makes changes to predecessor tasks, I see it first in the EDS and must approve/accept it before the impact will show in the successor task file. This helps prevent rogue, unapproved changes. It’s not the perfect solution, but it works for us.