Emissions are all good, except for lambda (air/fuel ratio) which was 1.2, i.e. pretty far off (20% too much oxygen present, though I suspect 1.2 was the limit of the analyser they were using and in fact it was even worse than this). In a perfect world the oxygen and fuel would balance in exactly the right ratio and all the oxygen would be used up burning the fuel to produce CO2.
In my world, however, the prime suspect is an exhaust leak upstream of the lambda sensors, which would explain (a) the excess oxygen as the exhaust flow draws in more air and (b) the rubbish fuel economy as the lambdas detect the oxygen and compensate with extra fuel. Presumably the cat is then using the excess oxygen to burn the excess fuel and hence I'm seeing normal HC (unburned fuel) levels at the tailpipe, which will be rapidly destroying the cat.
After looking for an exhaust leak and not finding one, I took the exhaust apart in search of more evidence, and eventually found this where the primaries join the block:
Exhaust gaskets. Note scorch marks at top left.
Which looks like pretty solid evidence of a leak. I've ordered new gaskets (these are off the old 328 engine and are slightly different to the M3 gaskets, which can't help), and booked a retest. They said they'd "make sure it passes" next time, which is nice of them, but I'd quite like to actually fix the problem.