Comparing matrix blocks by type and field value
My guess would be that this is happening due to lingering parameter values, as it looks like you’re not using clone() at all.
For every place that you are calling entry.programme, change to clone(entry.programme). For example:
{% set talks   = clone(entry.programme).type('item').all() %}
{% set odTalks = clone(entry.programme).type('item').od(':notempty:').all() %}

If you don’t clone the entry query before setting parameters on it and executing it, then whatever parms you set will stay set on it the next time you access the same entry query further on in your template.
(That is mentioned throughout the docs wherever we demonstrate setting parameters on element query field values, e.g. under Working with Matrix Field Data. But I realize it’s awkward &amp; annoying – see craftcms/cms#5640 for my idea of how to improve this in Craft 4.)
If adding clone() functions everywhere doesn’t solve this on its own, the next thing I’d do is run the query through getRawSql() and see what that produces:
&lt;pre&gt;{{ clone(entry.programme).type('item').od(':notempty:').getRawSql() }}&lt;/pre&gt;

You can paste the query that’s output into a MySQL client, and see if there’s anything obviously wrong with it. Or paste it into your question above.