diff method
Diffs this (current) registry against previous (P4/P5): pins whose
content key changed while their owner skill persists are SUPERSEDED;
pins whose owners all vanished (deleted, renamed, consent revoked)
— or whose owner still exists but no longer declares the line — are
DROPPED. Never silent — render the notices.
Budget drops are deliberately NOT part of the diff: a pin dropped by the previous window's budget was already reported at drop time (P6) and is not a lifecycle change — the diff baseline covers kept pins only.
Implementation
OperativePinDiff diff(SkillOperativePins previous) {
final currentKeys = pinByKey.keys.toSet();
final currentSkills = {
for (final pin in pins)
for (final p in pin.provenance) p.skillName,
};
final superseded = <({OperativePin previous, OperativePin current})>[];
final droppedPins = <OperativePin>[];
// Round 3: a successor may serve at most ONE supersede — a skill that
// edited two pinned lines between two windows has TWO distinct
// new-key pins, and binding both old lines to the first match named
// the wrong "→" line in one of the notices.
final claimedSuccessors = <String>{};
for (final old in previous.pins) {
if (currentKeys.contains(old.contentKey)) continue;
if (old.provenance.any((p) => currentSkills.contains(p.skillName))) {
// The successor must be a CURRENT pin of the same owner skill
// carrying a NEW content key — never just the skill's first pin
// (a multi-pin skill's unrelated surviving line must not be named
// as the replacement, review gh-1409 round 2) and never a pin
// already claimed by an earlier supersede in this same diff
// (round 3).
OperativePin? replacement;
for (final pin in pins) {
final isNewKey = !previous.pinByKey.containsKey(pin.contentKey) &&
!claimedSuccessors.contains(pin.contentKey);
final sameOwner = pin.provenance.any(
(p) => old.provenance.any((o) => o.skillName == p.skillName),
);
if (isNewKey && sameOwner) {
replacement = pin;
claimedSuccessors.add(pin.contentKey);
break;
}
}
if (replacement != null) {
superseded.add((previous: old, current: replacement));
} else {
droppedPins.add(old);
}
} else {
droppedPins.add(old);
}
}
return OperativePinDiff._(superseded: superseded, dropped: droppedPins);
}