Struggling with the strange behaviour I was seeing, where a function would execute correctly if called directly, but not if called from a for loop, I discovered two things: the same problem still exists in eXist 1.4.1, but there I see an actual error to the effect that the context is missing for a node; and I can eliminate the problem by rewriting some XPath inside the query. This is the XPath that was causing the problem:
for $n in (distinct-values($doc//@key[parent::tei:name[not(@type)]]))
Admittedly it's a bit perverse. If it's rewritten like this:
for $n in (distinct-values($doc//tei:name[not(@type)]/@key))
then the query works even when executed inside a loop. This means I can now generate all the complete OAI records that JD would like to see.