Skip to content

vendor/mailparse is a permanent carry: upstream declined the change - #217

Merged
kurok merged 1 commit into
masterfrom
vendored-mailparse-permanent
Aug 28, 2026
Merged

kurok merged 1 commit into
masterfrom
vendored-mailparse-permanent

Conversation

@kurok

@kurok kurok commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Docs only. vendor/mailparse/PATCH.md, the changelog and CONTRIBUTING all described the patched mailparse as a temporary carry with removal steps "once a release includes it". Upstream declined the change (staktrace/mailparse#142, closed 2026-08-28: the project does not accept new external dependencies, particularly ones relying on unsafe code), so those statements are now false.

What changes:

  • PATCH.md — "When this goes away" becomes "Keeping this in sync": the copy is permanent, every upstream mailparse release is a hand-merge into it, and the procedure (diff the new release against the previous one, apply to the copy, keep the two functions and the test, run its suite via the lint job) is written down. It also records why upstream declined and what an upstreamable version would have to look like (dependency-free), without proposing one.
  • CHANGELOG / CONTRIBUTING — the three references to "upstream as build(deps-dev): bump mail-parser from 3.15.0 to 4.6.4 #142 / removal steps" now say what happened.

Nothing in code, config or CI changes; the patch itself and the [patch.crates-io] mechanism are unaffected. tests/test_readme_snippets.py unaffected (README not touched).

PATCH.md, the changelog and CONTRIBUTING described the patched mailparse as a
temporary measure with removal steps for when a release included it. Upstream
declined the change on 2026-08-28 -- the project does not accept pull requests
that add external dependencies, particularly ones relying on unsafe code, and
memchr's SIMD paths are exactly that. So no release will include it, and the
removal steps were instructions for an event that will not happen.

PATCH.md now describes the opposite operation: how to merge each future
mailparse release into this copy without losing the two functions, and why the
version has to move in three manifests at once. It records the reason upstream
gave, and the one shape an upstreamable version could take -- dependency-free,
word-at-a-time -- without proposing to build it.

Signed-off-by: kurok <22548029+kurok@users.noreply.github.com>
@kurok
kurok merged commit 6302493 into master Aug 28, 2026
15 checks passed
@kurok
kurok deleted the vendored-mailparse-permanent branch August 28, 2026 07:00
kurok added a commit that referenced this pull request Sep 17, 2026
vendor/mailparse is upstream 0.16.1 with three functions changed, and every
speed number this library advertises comes from it. Upstream declined the
change (#217), so the copy is a permanent carry and each mailparse release is
a hand-merge -- the moment either half of the delta is most likely to be lost
or half-applied.

Ownership of that copy rested entirely on prose, and the prose had already
drifted: the lint-job comment said only the boundary search changed, and the
README said both loops moved to memchr when one of them is bytescan.rs.
PATCH.md asserted exactly which files differ from the registry crate, but
nothing re-checked it and there was no machine-readable patch to re-apply.

I hit this class of mistake myself while rebasing #238: #244 had merged with
its PATCH.md entry describing only half of what it changed, and I noticed
only because a rebase conflict made me read the file. Nothing in CI did.

upstream.patch is the delta in machine-readable form.
check_vendored_mailparse.sh re-applies it on every run: download the
published crate, verify its sha256, apply the patch, diff -r against this
directory, fail on any output.

Nothing else can see this. The vendored test suite passes on *unpatched*
upstream -- it tests behaviour, and the patch does not change behaviour -- so
a half-applied hand-merge would surface only as an unexplained 4-10x
regression in the benchmark gate, on whichever unrelated PR ran next. Given
what the gate has been doing this week, it might well have been read as
layout noise and waved through.

The script also asserts the two things PATCH.md's sync recipe is easiest to
get wrong: that both root manifests require exactly the vendored version --
a Dependabot bump of one alone would silently switch the build back to the
registry crate -- and that Cargo.lock still records mailparse with no
`source =` line, which is the signature of [patch.crates-io] being in effect.

Verified the guard actually fails, rather than assuming it: an edit to a
vendored source without regenerating the patch, a drifted root requirement,
and a corrupted patch each exit 1, and the clean tree passes. It runs locally
too (MAILPARSE_CRATE_FILE to skip the download, and it reads the version with
awk and falls back to shasum, so it does not need python 3.11 or GNU
coreutils).

The sdist check gains the same treatment: bytescan.rs, qp.rs and the patch
must be present, and a stray target/ or Cargo.lock from running cargo in the
vendored crate must not be -- both hazards .gitignore documents and nothing
enforced.

No Rust source change, so the wheel is byte-identical -- which also means the
benchmark gate compares identical binaries here and cannot flip on placement.

Signed-off-by: kurok <22548029+kurok@users.noreply.github.com>
kurok added a commit that referenced this pull request Sep 17, 2026
vendor/mailparse is upstream 0.16.1 with three functions changed, and every
speed number this library advertises comes from it. Upstream declined the
change (#217), so the copy is a permanent carry and each mailparse release is
a hand-merge -- the moment either half of the delta is most likely to be lost
or half-applied.

Ownership of that copy rested entirely on prose, and the prose had already
drifted: the lint-job comment said only the boundary search changed, and the
README said both loops moved to memchr when one of them is bytescan.rs.
PATCH.md asserted exactly which files differ from the registry crate, but
nothing re-checked it and there was no machine-readable patch to re-apply.

I hit this class of mistake myself while rebasing #238: #244 had merged with
its PATCH.md entry describing only half of what it changed, and I noticed
only because a rebase conflict made me read the file. Nothing in CI did.

upstream.patch is the delta in machine-readable form.
check_vendored_mailparse.sh re-applies it on every run: download the
published crate, verify its sha256, apply the patch, diff -r against this
directory, fail on any output.

Nothing else can see this. The vendored test suite passes on *unpatched*
upstream -- it tests behaviour, and the patch does not change behaviour -- so
a half-applied hand-merge would surface only as an unexplained 4-10x
regression in the benchmark gate, on whichever unrelated PR ran next. Given
what the gate has been doing this week, it might well have been read as
layout noise and waved through.

The script also asserts the two things PATCH.md's sync recipe is easiest to
get wrong: that both root manifests require exactly the vendored version --
a Dependabot bump of one alone would silently switch the build back to the
registry crate -- and that Cargo.lock still records mailparse with no
`source =` line, which is the signature of [patch.crates-io] being in effect.

Verified the guard actually fails, rather than assuming it: an edit to a
vendored source without regenerating the patch, a drifted root requirement,
and a corrupted patch each exit 1, and the clean tree passes. It runs locally
too (MAILPARSE_CRATE_FILE to skip the download, and it reads the version with
awk and falls back to shasum, so it does not need python 3.11 or GNU
coreutils).

The sdist check gains the same treatment: bytescan.rs, qp.rs and the patch
must be present, and a stray target/ or Cargo.lock from running cargo in the
vendored crate must not be -- both hazards .gitignore documents and nothing
enforced.

No Rust source change, so the wheel is byte-identical -- which also means the
benchmark gate compares identical binaries here and cannot flip on placement.

Signed-off-by: kurok <22548029+kurok@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant