It didn’t work.
Every time I stepped through the code, the list boxes were coming through completely unchanged.
Then I had a Homer-like "Doh!" moment. There’s no way ASP.NET could know I was removing stuff from the lists. The only values submitted to the form from lists are selected items, not the entire contents of the list.
Having chastised myself for not thinking of that sooner, I came up with a workaround. Simply copy the contents of a list to a hidden field, delimited with commas. Then I can use server-side ASP.NET to work out what has and hasn’t been removed.
Not pretty, and indeed the whole way of doing this isn’t the best, but I can’t change that at the moment.