If you scan to the bytes 5820 in the compilations of A, you'll see the two versions differ just after.

I'd expected solc compilations to be repeatable (that seems important for verifying that code on the blockchain is consistent with public source), and don't understand why these two versions of A should differ. What am I missing?

Many thanks for any insight!

Update: I'm using the empty contract as an example here, but I first encountered inconsistent compilations with a less trivial contract. It's not just a quirk of the empty contract.

Then I took the content of "Runtime Bytecode" and pasted it in the disassembler.

The lines:

[17] PUSH6 0x627a7a723058
[18] SHA3 // Its opcode is 0x20

Correspond to the xxxxx5820 that you identified. And guess what:

> web3.toUtf8("0x627a7a723058")
"bzzr0X"

Then what comes right after that, in my case 81ef35e9ce2010474897d82da20c73d954e24c1e93fceaca1da5d1ed75650a26 so 32 bytes which, if you go back to Solidity, are the same ones as under "Metadata location".

So my understanding is that the code of the contract has not changed; only its Swarm address has. And contract verifiers need to abstract that part away.

Thanks for all the investigating! This looks consistent with the reddit thread @BokkyPooBah points to in a comment to the original post. I'll let this sit for a while in case others want to weigh in, but I think you and BokkyPooBah have basically figured this out.
– Steve WaldmanJan 24 '17 at 10:53