Derive identity-map entries from the content matches of a
ModelDiff — the durable form of "we decided these are the same
element".
Pure, order-preserving, and deliberately conservative. An entry is emitted
only for a match that is BOTH claimable (CLAIMABLE_KINDS) AND
one-to-one. Two exclusions carry the design:
Non-destructive kinds emit nothing.ambiguous, duplicated, and
deduplicated are the engine's way of saying it could not tell. A claim
derived from an abstention is a fabrication, and — because the map is
consumed as a key alias on the next run — it would convert an honest
"here are the candidates, you decide" into a silent, unreviewable pairing.
N:N renamed groups emit nothing. A group of N per side agreed on the
data hash and the world geometry hash N times over, which is exactly why
the engine reports it as a set rather than a pairing: every bijection between
the two sides is identical in every field the engine can see. Picking one
(even a deterministic one, sorted by key) would be arbitrary. It is tempting
to argue the choice is harmless because the members are indistinguishable,
but that is only true in this revision — an identity map is written down and
replayed, and the pairing starts to matter in the first later revision where
two of those members diverge, or where one of them carries downstream
annotation (a BCF topic, a review comment, a cost line). At that point a
coin-flip pairing silently swaps two elements' histories, and nothing in the
artifact records that it was a coin flip. 04-identity.md: human-in-the-loop
identity beats wrong automatic identity. The group is still visible in
ModelDiff.contentMatches, so a UI can offer the human the pairing to
confirm; the engine simply will not mint it unattended.
ModelDiff.contentMatches (accepts undefined so
identityMapFromContentMatches(diff.contentMatches) is a valid call on a
diff that never ran the content pass).
Derive identity-map entries from the content matches of a ModelDiff — the durable form of "we decided these are the same element".
Pure, order-preserving, and deliberately conservative. An entry is emitted only for a match that is BOTH claimable (CLAIMABLE_KINDS) AND one-to-one. Two exclusions carry the design:
Non-destructive kinds emit nothing.
ambiguous,duplicated, anddeduplicatedare the engine's way of saying it could not tell. A claim derived from an abstention is a fabrication, and — because the map is consumed as a key alias on the next run — it would convert an honest "here are the candidates, you decide" into a silent, unreviewable pairing.N:N
renamedgroups emit nothing. A group ofNper side agreed on the data hash and the world geometry hashNtimes over, which is exactly why the engine reports it as a set rather than a pairing: every bijection between the two sides is identical in every field the engine can see. Picking one (even a deterministic one, sorted by key) would be arbitrary. It is tempting to argue the choice is harmless because the members are indistinguishable, but that is only true in this revision — an identity map is written down and replayed, and the pairing starts to matter in the first later revision where two of those members diverge, or where one of them carries downstream annotation (a BCF topic, a review comment, a cost line). At that point a coin-flip pairing silently swaps two elements' histories, and nothing in the artifact records that it was a coin flip.04-identity.md: human-in-the-loop identity beats wrong automatic identity. The group is still visible inModelDiff.contentMatches, so a UI can offer the human the pairing to confirm; the engine simply will not mint it unattended.