fix(vcard): stop fold loop on invalid UTF-8 - #14
Conversation
folded walked cut down to 0 when every nonempty prefix was invalid UTF-8, wrote a blank continuation, and never advanced the line. Advance one invalid byte so export can finish. People() already salvages broken person.md names; aborting the whole address book would drop every later contact. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 5, 2026, 4:10 PM ET / 20:10 UTC. ClawSweeper reviewWhat this changesMakes vCard export advance past invalid UTF-8 bytes in damaged contact names, with regression tests and a changelog entry. Merge readiness✅ Ready for maintainer review This remains a useful, focused fix: current main still permits the export loop to stop advancing. The supplied real CLI proof supports completion after the patch, and no blocking defect was found. Priority: P2 Review scores
Verification
How this fits togetherClawdex reads contacts from local Markdown files, salvaging fields when their metadata is damaged. Its vCard exporter formats those contacts into folded text lines and writes them to a file or stdout. flowchart LR
A[Contact Markdown files] --> B[Read and salvage fields]
B --> C[Export selected contacts]
C --> D[Format vCard fields]
D --> E[Fold lines with forward progress]
E --> F[File or stdout]
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Keep folding byte-preserving and guarantee forward progress on malformed input while retaining valid Unicode boundaries. Do we have a high-confidence way to reproduce the issue? Yes: current-main source establishes the zero-progress loop, and the contributor supplies a concrete malformed-contact CLI reproduction. This read-only review did not execute it. Is this the best way to solve the issue? Yes: the fallback narrowly repairs termination without introducing configuration, discarding contact bytes, or changing valid-input folding. AGENTS.md: not found in the target repository. Codex review notes: model internal, reasoning medium; reviewed against baa945d86da0. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
History |
|
Maintainer proof for head 9e586b4:
The Unreleased entry credits @SebTardif. Prepared for a maintainer squash merge; no merge performed. |
What Problem This Solves
clawdex export vcard --allcan hang forever whenPeople()salvages aperson.mdwhose display name is longer than 75 bytes and starts with aninvalid UTF-8 byte.
foldedininternal/vcard/vcard.gowraps RFC 6350 lines at 75 octets andwalks
cutbackward untilutf8.ValidString(line[:cut])so it does notsplit a rune. A leading invalid byte makes every nonempty prefix invalid.
cutbecomes 0,ValidString("")is true, the function writes a blankcontinuation (
\r\n) and does not advanceline, then repeats.The loop has been in place since the CLI bootstrap
(
fc837601e1,2026-05-08). Open PRs #11
and #12 cover avatar reads
and Google HTTP timeouts. They do not touch vCard fold.
Evidence
Built
clawdexfrom this branch and from unpatchedorigin/main. Initializeda contacts repo, wrote
people/bad-name/person.mdwith broken YAML soPeople()salvages, and setnameto byte0xffplus 80 ASCIIabytes(81 bytes, over the 75-octet fold limit). Then ran the public export.
Unpatched binary (same fixture, 1 second deadline):
Patched binary, same fixture and command:
Elapsed 29ms. Output is 288 bytes and starts
BEGIN:VCARD/FN:with thename folded across continuation lines. Export returns instead of spinning.
A standalone
goprogram that callsvcard.WritewithName: "\xff" + 80*'a'matches that: unfixed fold hits the 400ms deadline;patched
Writereturns in 0s with 267 bytes andcontains_FN=true.Real behavior proof
Behavior or issue addressed: vCard export no longer hangs when a salvaged person name is longer than 75 bytes and starts with an invalid UTF-8 byte. Fold advances one invalid byte and finishes the address book.
Real environment tested: Windows amd64, Go 1.26.6, clawdex built from this branch to
bin/clawdex.exe, isolated config under%TEMP%\clawdex-f006-exportwithauto_repair = falsesoPeople()salvages the brokenperson.md.Exact steps or command run after this patch:
Evidence after fix: terminal output from the patched binary:
Same fixture against the unpatched binary never printed a result (killed after 1s). After the patch the command returns in 29ms and writes a 288-byte
.vcf.Observed result after fix: Export completes and writes one vCard. The long FN is folded on 75-octet lines. The rest of the book is not aborted.
What was not tested: Google or Apple import of a long invalid-UTF-8 FN (those adapters emit UTF-8). Live Contacts import of the folded
.vcfon a phone.