edited contact: raise on a lent note that will not read
EditedContact kept its own lent_text, which read an unreadable stored
lent NOTE as nil. A nil compares unequal to every section a client
sends, so the section read as deleted. Contact.lent_text already
raises on that line; the split now calls it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kqo9sKAi4DnKCQkrtYoAwM
diff --git a/lib/pro_tacts/edited_contact.rb b/lib/pro_tacts/edited_contact.rb
index 633803f..b14d14d 100644
--- a/lib/pro_tacts/edited_contact.rb
+++ b/lib/pro_tacts/edited_contact.rb
@@ -288,7 +288,7 @@ module ProTacts
split = NoteSections.split(value, labels)
if split.sections.empty?
# The two-line shape's truncation (see the method comment).
- kept = rows.find { |row| lent_text(row) == value }
+ kept = rows.find { |row| Contact.lent_text(row) == value }
unless kept.nil?
return [
vcard.replace("NOTE", []),
@@ -315,7 +315,7 @@ module ProTacts
case text
when nil
GroupEdit.new(group_id: row.group.id, position: row.position, line: nil)
- when lent_text(row)
+ when Contact.lent_text(row)
nil
else
GroupEdit.new(
@@ -368,14 +368,6 @@ module ProTacts
joined_notes(vcard, notes)
end
- # What a lent NOTE row says, as text: the unescaped value of its
- # line, or nil for one that will not read and so cannot be compared
- # with anything a client sent.
- #: (Contact::Inherited row) -> String?
- def lent_text(row)
- parsed_line(row.line).property&.text
- end
-
# The submission's NOTE lines joined into the one the invariant
# keeps, at the first one's position: a client's two-NOTE card is
# foreign input, joined rather than refused. A line that will not
diff --git a/test/pro_tacts/test_edited_contact.rb b/test/pro_tacts/test_edited_contact.rb
index 847a309..e1e3409 100644
--- a/test/pro_tacts/test_edited_contact.rb
+++ b/test/pro_tacts/test_edited_contact.rb
@@ -203,6 +203,19 @@ class EditedContactTest < Minitest::Test
)
end
+ # A stored lent NOTE was read on its way in, so one that will not
+ # read now is a broken assumption to raise on (Contact.lent_text)
+ # rather than a section compared unequal to everything a client sent.
+ def test_a_lent_note_that_will_not_read_raises
+ stored = note_card("Own note.")
+ served = note_card("Own note.\n\nShared · Neighbours:\n#{NOTE_TEXT}")
+ lent = [ProTacts::Contact::Inherited.new(group: NEIGHBOURS, position: 1, line: "NOTE;=;:")]
+
+ error = assert_raises(RuntimeError) { decompose(served, before: before(stored, inherited: lent)) }
+
+ assert_equal "group nnnn lends a line that will not read", error.message
+ end
+
# One of two sections deleted, the other and the member's own kept:
# the present section is attributed and the absent one is the
# removal of its row.