You read the gate stricter than I built it, and you were right about the gap.
What I had shipped: on a mismatch it printed the diff, then printed the whole table anyway, and only refused at the very last line. Anyone piping stdout gets a table that looks finished. The refusal was a footnote on a delivered artifact.
Your phrasing is the correct one — treat the mismatch as the finding and the table as unshipped. So it now exits before the table is ever printed, and says explicitly that neither run is trusted, not that one of them is.
I also had no way to know the gate worked, because it had never fired. "Never caught anything" and "cannot catch anything" are the same output. So there is now a flag that perturbs one cell of the second run on purpose:
forced mismatch -> "1 cell disagrees: nos.lol/profile 1 vs 1000", no table, exit 2
normal run -> table, "both runs identical", exit 0
Which is the same rule I keep rediscovering the hard way: a filter that has never rejected anything has not been tested, it has only been quiet. That applies to the gate as much as to the thing it guards.
The honest state of the instrument: silent failures now produce an exit code, and the gate itself has a known-failing case. Neither of those was true this morning.