You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pick the line terminator for spliced lines through one line_endings::terminator #815
Drift, proved by execution. A throwaway unit probe on main, run twice, gave:
for "a\nb\r\nc\r\n": detect_eol and pypi_uv::newline_of → CRLF, gradle::newline_of → LF, majority_terminator → CRLF;
for "a\r\nb\nc\n": the first two → CRLF, gradle::newline_of → CRLF, majority_terminator → LF.
On a uniform file all three agree.
Symptoms
None filed for these sites specifically. The same disagreement produced #467 and #695 in other writers (see #814).
Impact
Low risk, small. The rules differ only on mixed CRLF/LF files, where a new line comes out in a style that depends on which copy the writer was pasted from.
Behavior is unchanged for LF-only and CRLF-only files. On a mixed file, inserted lines take the majority style. Majority is stable under appending lines in its own style, so revert paths that remove {line}{nl} (uv [manifest], go.sum, Gradle append_line) still match what the forward pass wrote.
Size and scope
About 15 files, roughly −60/+40 production lines, plus unit tests. Out of scope: preserve_line_endings and crlf_to_lf (child 2), yarn classic's mixed-file posture (child 3, #467), the pnpm CRLF refusal (review 4.7 G) and the Poetry/PDM rule (PR #703).
Acceptance criteria
rg 'contains\("\\r\\n"\) \{ "\\r\\n"' crates/socket-patch-core/src finds no production hits; detect_eol and both newline_of functions are gone.
New unit tests in utils/line_endings.rs for terminator: LF, CRLF, None, and mixed with a CRLF majority, an LF majority and a tie.
A regression test on one append-and-revert writer (for example go_sum_edit or Gradle append_line) over a mixed file: forward then revert is byte-exact.
These stay green: crlf_go_sum_preserves_line_endings, test_crlf_go_mod_preserves_line_endings, rewrites_hash_pinned_continuation_and_preserves_crlf, transitive_append_crlf_root_without_trailing_newline, crlf_pyproject_and_lock_round_trip_byte_exact, kotlin_settings_crlf_and_missing_newline_are_preserved, crlf_and_tabs_are_preserved (maven_reactor), gem_crlf_lock_checksum_pinned_preserving_crlf, gem_crlf_lock_checksums_header_gains_crlf_entry, gemfile_rerun_on_crlf_checkout_never_nests, and the full cargo test -p socket-patch-core.
Dependencies
Blocked by nothing. It touches gradle.rs and maven_reactor.rs lines that #715's children also edit, so rebase whichever lands second. It unblocks children 2–4 of #814.
[agent] Triaged: priority:p3 (a cross-cutting refactor). This is child 1 of tracking issue #814. Confirmed on main: common::detect_eol, pypi_uv::newline_of and gradle::newline_of (which follows a different rule) all still exist. Not a duplicate, and no open PR covers it.
[agent] Claiming this issue for the architecture refactor routine (highest leverage: the only refactor slice left whose files no open PR changes; it collapses 8 copies of the "any \r\n → CRLF" rule into one line_endings::terminator). Branch: arch-refactor/815-line-terminator. Claim-ID: 2026-10-08T03:56:03Z-4c3126
Slice taken (slice 1): add utils::line_endings::terminator and route the copies in files no open PR touches: formats/gem/hosted.rs, redirect/upstream/{composer,gem,pypi}.rs, redirect/pipenv.rs, utils/python_script.rs and vendor/go_mod_edit.rs (2 sites). Remaining (slice 2, after the open PRs that change those files land): vendor::common::detect_eol and its callers, pypi_uv::newline_of, maven_reactor.rs ×2, redirect/mod.rs, the crlf flags in upstream/cargo.rs/npmrc.rs/pypi_pipenv.rs, and the Gradle newline_of.
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: register comment.
Kind: refactor. Source: review 4.4 and 5.4 (CRLF policies); register E16. Child 1 of tracking #814.
Problem
Writers that insert or append lines pick the terminator with three hand-written rules (main @
045d7ec):\r\n→ CRLF, written 14 times:vendor/common.rs#L157-L163detect_eol, used by go.sum, go.mod, requirements and yarn classic;vendor/pypi_uv.rs#L1011-L1017newline_of, a byte-identical private copy;if x.contains("\r\n") { "\r\n" } else { "\n" }informats/gem/hosted.rs#L65,vendor/jvm/maven_reactor.rs#L1519,[`#L1776`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/vendor/jvm/maven_reactor.rs#L1776),``upstream/composer.rs#L259-L263,[`upstream/gem.rs#L535`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/patch/redirect/upstream/gem.rs#L535),``upstream/pypi.rs#L629,[`redirect/pipenv.rs#L129`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/patch/redirect/pipenv.rs#L129), [`redirect/npmrc.rs#L614`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/patch/redirect/npmrc.rs#L614), [`redirect/mod.rs#L5775`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/patch/redirect/mod.rs#L5775), [`utils/python_script.rs#L44`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/utils/python_script.rs#L44); plus the `crlf` flags in [`upstream/cargo.rs#L304`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/patch/redirect/upstream/cargo.rs#L304``) andvendor/pypi_pipenv.rs#L153.vendor/jvm/gradle.rs#L855-L861, a second privatenewline_ofwith a different rule under the same name.utils/line_endings.rs#L74-L82majority_terminator(JsonLayout, composerlock_text).Drift, proved by execution. A throwaway unit probe on main, run twice, gave:
"a\nb\r\nc\r\n":detect_eolandpypi_uv::newline_of→ CRLF,gradle::newline_of→ LF,majority_terminator→ CRLF;"a\r\nb\nc\n": the first two → CRLF,gradle::newline_of→ CRLF,majority_terminator→ LF.On a uniform file all three agree.
Symptoms
None filed for these sites specifically. The same disagreement produced #467 and #695 in other writers (see #814).
Impact
Low risk, small. The rules differ only on mixed CRLF/LF files, where a new line comes out in a style that depends on which copy the writer was pasted from.
Proposed change
pub(crate) fn terminator(text: &str) -> &'static strtoutils/line_endings.rs:LineEndings::Crlf→"\r\n",Mixed→majority_terminator(text),Lf | None→"\n".vendor::common::detect_eol,vendor::pypi_uv::newline_of,vendor::jvm::gradle::newline_of, and the 12 inline copies.yarn_classic_lock::block_eolkeeps its block-local rule but falls back toterminator(its Yarn classic hosted and vendored rewrites convert LF lines of a mixed CRLF/LF yarn.lock to CRLF, so rollback is not byte-exact #467 behavior is child 3 of Tracking: classify line endings in one place instead of five drifting rules #814).{line}{nl}(uv[manifest], go.sum, Gradleappend_line) still match what the forward pass wrote.Size and scope
About 15 files, roughly −60/+40 production lines, plus unit tests. Out of scope:
preserve_line_endingsandcrlf_to_lf(child 2), yarn classic's mixed-file posture (child 3, #467), the pnpm CRLF refusal (review 4.7 G) and the Poetry/PDM rule (PR #703).Acceptance criteria
rg 'contains\("\\r\\n"\) \{ "\\r\\n"' crates/socket-patch-core/srcfinds no production hits;detect_eoland bothnewline_offunctions are gone.utils/line_endings.rsforterminator: LF, CRLF, None, and mixed with a CRLF majority, an LF majority and a tie.go_sum_editor Gradleappend_line) over a mixed file: forward then revert is byte-exact.crlf_go_sum_preserves_line_endings,test_crlf_go_mod_preserves_line_endings,rewrites_hash_pinned_continuation_and_preserves_crlf,transitive_append_crlf_root_without_trailing_newline,crlf_pyproject_and_lock_round_trip_byte_exact,kotlin_settings_crlf_and_missing_newline_are_preserved,crlf_and_tabs_are_preserved(maven_reactor),gem_crlf_lock_checksum_pinned_preserving_crlf,gem_crlf_lock_checksums_header_gains_crlf_entry,gemfile_rerun_on_crlf_checkout_never_nests, and the fullcargo test -p socket-patch-core.Dependencies
Blocked by nothing. It touches
gradle.rsandmaven_reactor.rslines that #715's children also edit, so rebase whichever lands second. It unblocks children 2–4 of #814.