- _merge_vcard_properties no longer silently drops the existing EMAIL /
TEL line when contact_data supplies a dict/list shape: the input is
unhandled by the text merge, so the original line is preserved
instead of being consumed and replaced with nothing.
- Extracted _parse_bday so the update path validates ISO format the
same way create does. Invalid → keep existing BDAY line (or skip on
add-new) rather than writing a malformed one.
- Added _safe_vcard_value to escape newlines per RFC 6350 §3.4 at every
interpolation site in _merge_vcard_properties, blocking value-driven
property injection (e.g. NOTE: containing a literal \n + EMAIL:).
- Removed dead "organization" alias references from _merge_vcard_properties:
unreachable since update_contact normalises before calling.
- New regression tests pin all four behaviours (dict-email preserves
existing line, list-tel ditto, invalid-bday-update preserves original,
invalid-bday-add-new is dropped, newline-in-note no injection).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>