Temporal Conflict Detector
ConflictDetector that distinguishes world progression from genuine contradiction using the proposition predicate and temporal recency.
A clash is classified as ConflictType.WorldProgression when both hold:
the predicate is in evolvingPredicates — i.e. a fact that legitimately changes over time, such as an employer or residence; and
the incoming proposition is not older than the existing one.
The predicate is read from metadata[Proposition.PREDICATE] on the incoming proposition, falling back to the existing proposition's predicate when the incoming one carries none. In a revision flow the stored/existing proposition is the likelier carrier of enriched predicate metadata, while a freshly extracted incoming one may not yet have a cached predicate — so considering both avoids mis-classifying the very world-progression case this detector exists to catch.
Recency uses the temporal anchor when present (temporal.observedAt, falling back to temporal.validFrom), otherwise the proposition's contentRevised.
Tie rule: recency is compared with strict supersession. When the two anchors are the same Instant, neither proposition strictly supersedes the other, so an equal-recency clash on an evolving predicate is treated as ConflictType.WorldProgression rather than a ConflictType.Contradiction — equal timestamps are deliberately not a temporal contradiction. Only an incoming proposition that is strictly older falls back to ConflictType.Contradiction.
Every other case — a stable predicate, an absent predicate on both propositions, or a strictly older incoming — is classified conservatively as ConflictType.Contradiction.
No LLM or IO is involved; classification is deterministic and O(1).