Right now a number of extensions treat the ParserOutput as a read-write store, reading a previous value from the ParserOutput, updating it, and then storing the updated value back. This is incompatible with the separate/asynchronous/incremental parsing model on the Parsoid roadmap, the "write-only" model of the Parsoid ContentMetadataCollector interface, and the proposed asynchronous-parsing aspect of the WikiFunctions feature.
Methods which assume a destructive update should be replaced with append and set variants which are guaranteed to be write-only. (The "set" will throw an exception if a different value is stored for a key, although use as a flag where multiple places set the same value is permitted; "append" collects all values in a set.)
Any post-processing (to select the minimum value set, the last value set in wikitext order, etc) should be done when the collected results are transferred to the OutputPage, not done in the ParserOutput itself (ie, in the OutputPageParserOutput hook).
Generally speaking the requirement is that the operations to combine metadata should be order-independent. Increment operations are fine, as long as they are recorded as such and not as "read, opaquely modify, then write". Similarly set-union operations are okay, even with repeated elements. I can take the metadata output *without a fragment* and union it with the metadata *of the fragment* and get a consistent result, without having to determine exactly where in the document the fragment falls. By the same logic, overwriting an existing key in the metadata with the same value is fine: the output will set the key to the desired value regardless of the order in which we evaluated the two fragments which wrote that key/value pair.
Overwriting a key with a new value is *not* okay, because we can't later update either of the pieces which wrote that key without knowing the order in which the fragments appeared, since the final value is typically "the last write". Cases where the final value is a function of *all* writes, for example cache expiry where the final value is min(<all writes>) are acceptable, because the final value doesn't depend on the order in which fragments are evaluated.