Every ADR fixture in the tree used \n, so nothing exercised a CRLF-stored
document — and CI could not have found this, because the fixtures are LF
whichever platform runs them. A red would only have appeared once a real
user's CRLF ADR met this code.
The exposure is specific to splicing. The old rebuild normalised everything
on the way out, so line-ending confusion was invisible; a byte-span
replacement can miscount a separator run, and byte-identity is the property
the splice design exists to provide.
Two of the three paths were already correct, and now say so in tests:
- Replacing a section preserves CRLF exactly. The walk-back over a trailing
break run steps across both '\r' and '\n', so it cannot cut mid-pair.
- Heading matching is ending-agnostic: "## PURPOSE\r\n" locates the same as
"## PURPOSE\n", because the scanner trims '\r' from the name. Trimming and
matching were different claims and only trimming was pinned.
Appending a new section was wrong. It counted trailing '\n' characters, so a
document ending "...Foo\r\n" was read as having one break but then had a
BARE '\n' appended, and the "## NAME" line it wrote used '\n' too — leaving a
mixed document that neither the author nor the tool asked for. A CRLF file
ending in a blank line also gained a spurious extra break.
Appends now count a "\r\n" pair as one break, and write the separator and
heading line using the document's own ending.
The contract, now that a document can be mixed:
- Bytes that already exist are never rewritten, so each line keeps whatever
ending it had. This follows from splicing and is what the acceptance
property already guaranteed.
- Text this code writes itself — the separator and the "## NAME" line —
follows the document's majority ending, LF on a tie.
- A caller's body is inserted verbatim. Rewriting bytes a caller supplied
would be the same silent modification this whole change set removes.
Co-authored-by: andis777 <24672074+andis777@users.noreply.github.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>