Let a plugin decide how two sites name the same person
See #3624470.
WireAccount held one rule - a person is named by their login - and a deployment that knows its people some other way had no way to say so. WireIdentity is now a plugin type, one plugin per way two sites name the same person, and the rule Orchestra had ships as the login plugin. Every call names its scheme, because a name is only a name under the scheme that minted it. The two directions are shaped differently on purpose: a list of runs names an initiator a row, so the outgoing one takes a set and answers it in one read, while a name arrives one at a time on a start.
A pair of sites works out what it can use at the handshake. The receiving site answers with the schemes it will accept from that caller - what it allows them, not what it happens to have installed, since a site can hold the scheme that matches people by email and still not let one partner use it. The caller keeps the ones it can also mint, and the handshake settles on the first they share so the pair works straight away; with more than one in common the remote's form offers the choice.
A start carries the name and the scheme together, and the receiving site checks the scheme against what that caller may use before it resolves anything: resolving first would run a lookup the site said no to, and it would settle whether some account answers to that name, which a refusal arriving afterwards can no longer take back. The list is read again on every start, because the caller's copy is a cache, either side can uninstall a plugin, and a caller can claim whatever it likes. Runs read back name their scheme too, since the caller's own default never travelled here.
Nothing changes for a site that configures nothing: a caller with no schemes ticked may use the account name alone, which is what it was already doing, and a remote too old to be asked means the same.
Audited in six rounds. The behavioural fixes that came out of it: an empty scheme was refused as a scheme called nothing; the policy resolver loaded the consumer by uuid on every start and list where its two siblings read it off the request; a choice the pair stopped sharing was cleared to the default, which the far side may never have accepted, so every start would be refused with no form control to correct it; a pair sharing no scheme still minted a name that end had refused to read, instead of sending none; the new consumer field had no upgrade path; and a scheme lost to an uninstall threw a bare plugin id instead of naming the remote and saying to shake hands again. A consumer ticked for a scheme whose module has gone can now be seen and cleared.