Skip to content

feat(series): Carry patch/ entries onto the buffer as part of porting - #2660

Open
krlmlr wants to merge 4 commits into
mainfrom
claude/gallant-edison-5t2j2g
Open

feat(series): Carry patch/ entries onto the buffer as part of porting#2660
krlmlr wants to merge 4 commits into
mainfrom
claude/gallant-edison-5t2j2g

Conversation

@krlmlr

@krlmlr krlmlr commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

A patch/ entry does nothing on -dev. vendor-one.sh applies the buffer's stack to every tree it regenerates, so <S>-build is where an entry has to live to affect what the series vendors next.

Entries reach -dev two ways and only one of them puts them there. A firing writing one during a repair is told by stage 3 to commit it onto the buffer in the same firing — that half works. But stage 4's port brings whole main commits over, patch/ files included, so an entry born as a pull request against main arrives on every -dev without any firing deciding to put it there, and reaches no buffer at all, -build taking no ports by design.

The drift is quiet while upstream leaves the patched file alone, because the buffer is then internally consistent and its commits carry no delta for that file. It bites the first time upstream touches one: the buffer regenerates that file without the fix, and the commit that reaches -dev from it reverts the fix while reading as an ordinary vendor commit.

What this changes

Carry it where the port already runs, rather than detecting the gap afterwards. series-port.sh --apply now finishes by calling the new series-patch-sync.sh <S> --apply, which is a read-only report on its own.

What carries is decided by test-applying against the buffer's own tree, never by the file list — a buffer runs ahead of main, so an entry main needs may not fit the engine the buffer has vendored, and committing it there regardless breaks the next vendor run outright rather than helping anything:

  • carry — applies cleanly, taken with its effect on the tree
  • satisfied — reverse-applies, so the effect is already there; the entry is taken alone, to keep the two stacks identical
  • stale — neither: upstream moved the code out from under it, so on this engine the entry answers nothing

Two shapes are reported and never carried, because both are judgement and both break the next vendor run if guessed at:

  • a supersession — a candidate whose files an entry the buffer has and -dev lacks also touches. 0003-Fix-clang-warnings-in-re2 displacing 0003-Try-to-ignore-clang-warnings is the standing example: the real fix, hoisting and naming the anonymous struct, replacing the two #pragma clang diagnostic ignored lines that stood in for it.
  • an entry main edited in place, which the port brings to -dev under a name the buffer already has. Candidates are therefore compared by blob; a name-only comparison calls those two stacks level. 0009-Remove-stderr-for-zstd is that one today.

series-check.sh gains a PATCH DRIFT line per series, printed beside the verdict like CUTOVER is, naming what the two stacks differ by in all three directions. It is the backstop, not the mechanism: after a port, what it reports is precisely what the carry declined, which is stage 3 work.

Finally, two entries born on a series buffer are routed to main, which is where the loop says a fix belongs when it is not series-specific: 0034-Guard-explicit-producer-token-in-concurrent-queue and 0035-Silence-deprecated-Catalog-GetEntry-self-delegation. Both apply cleanly to main's vendored tree today, and both keep the names the buffers already use, so the stacks match rather than growing a third spelling of the same diff.

Measured, not assumed

Every entry in the union of the stacks was test-applied, reverse-applied and neither, against every buffer and every -dev. That is what separated the four cases above, and it caught one that a file-list carry would have got wrong: 0036-Mark-two-assert-only-bindings-used and 0038-Initialize-every-member-of-DependencySubject are on main, and on the main series' newer engine they fit nothing. Committing them to that buffer would have failed its next vendor run with vendor.sh's "patches moved" exit.

The three entries born on a buffer that do not appear in the routing commit — 0036-Guard-assert-only-plan-verifiers, 0037-Cast-to-void-in-the-default-aggregate-state-memset and 0039-Return-past-the-exhaustive-DatePart-specifier-switches — do not apply to main's engine at all, so they stay series-specific by engine version and reach main when main's engine reaches the code they answer.

Effect on the branches

Run against all six series, the carry closed the drift on the four that had it (main, main-fwd, v1.5-variegata, v1.5-variegata-fwd; the two v1.4-andium series are frozen, take no ports, and were already level). The 0003 supersession was then resolved by hand as stage 3 work, reversing the entry being replaced and applying the replacement, with src/duckdb/third_party/re2 verified byte-identical to each -dev afterwards.

What remains is stale only, and correctly so. No -dev branch was touched: buffers carry no CI, so closing all of this cost no check runs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D36f3J68XGNUAu4o1DX5xD

claude added 4 commits August 15, 2026 17:02
…the buffer

`vendor-one.sh` applies the *buffer's* `patch/*.patch` to every tree it
regenerates, so an entry that never reached `<S>-build` is one the next vendor
run will not apply. Stage 3 of the series loop already says to commit an entry
onto the buffer in the same firing, but that only binds the entries a firing
writes: stage 4's port carries whole `main` commits onto `-dev`, `patch/` files
included, so an entry born as a pull request against `main` reaches every `-dev`
without any firing deciding to put it there, and reaches no buffer at all.

Today that is five entries on `main`, `main-fwd`, `v1.5-variegata` and
`v1.5-variegata-fwd` -- `0035`, `0036`, `0037`, `0038`, and `0003` under a name
the buffers still carry in its older spelling. The drift is quiet while upstream
leaves the patched files alone, because the buffer is then internally consistent
and its commits carry no delta for them; it bites the first time upstream
touches one, and the fix is reverted on `-dev` by a commit that reads as an
ordinary vendor.

Report it rather than close it: which entry belongs on which buffer, and what
its effect on that buffer's tree is, is the repair stage's judgement. The line
is printed in both directions, because a renamed entry is one of each and
neither half alone says so.
Both were written on a series buffer, and neither is series-specific: they
apply cleanly to `main`'s vendored tree today, which is the test the loop's
stage 3 sets for routing a fix through `main` rather than keeping it on the
series. Kept under the names the buffers already use, so the stacks match
rather than growing a third spelling of the same diff.

- `0034-Guard-explicit-producer-token-in-concurrent-queue`: `inner_enqueue()`
  and `inner_enqueue_bulk()` dereference the producer a token carries without
  checking it.
- `0035-Silence-deprecated-Catalog-GetEntry-self-delegation`: the deprecated
  `Catalog::GetEntry()` overloads delegate to one another, which the check
  reports as a significant warning.

Measured rather than assumed. Against every buffer and `-dev` of every series,
each entry was test-applied, reverse-applied and neither:

  entry                     main   main-*   v1.5-*
  0034-Guard-explicit...    APPLY  in       APPLY
  0035-Silence-deprecat...  APPLY  in       APPLY

`in` means the effect is already in that tree. The three entries born the same
way that do *not* appear here -- `0036-Guard-assert-only-plan-verifiers`,
`0037-Cast-to-void-in-the-default-aggregate-state-memset` and
`0039-Return-past-the-exhaustive-DatePart-specifier-switches` -- do not apply to
`main`'s engine at all, so they stay series-specific by engine version and reach
`main` when `main`'s engine reaches the code they answer.
A `patch/` entry does nothing on `-dev`. `vendor-one.sh` applies the *buffer's*
stack to every tree it regenerates, so `<S>-build` is where an entry has to live
to affect what the series vendors next. Entries reach `-dev` two ways and only
one of them puts them there: a firing writing one during a repair is told by
stage 3 to commit it onto the buffer in the same firing, but stage 4's port
brings whole `main` commits over, `patch/` files included, so an entry born as a
pull request against `main` arrives without any firing deciding to put it there
-- and reaches no buffer at all, `-build` taking no ports by design.

So carry it where the port already runs, rather than detecting the gap
afterwards: `series-port.sh --apply` now finishes by calling the new
`series-patch-sync.sh <S> --apply`, which is a read-only report on its own.
`series-check.sh`'s PATCH DRIFT line stays as the backstop it should have been
from the start -- after a port it names what the carry deliberately declined.

What carries is decided by test-applying against the buffer's own tree, never by
the file list. A buffer runs ahead of `main`, so an entry `main` needs may not
fit the engine the buffer has vendored, and committing it there regardless
breaks the next vendor run outright rather than helping anything:

  carry      applies cleanly -- taken with its effect on the tree
  satisfied  reverse-applies, so the effect is already there -- entry taken
             alone, to keep the two stacks identical
  stale      neither: upstream moved the code out from under it, so on this
             engine the entry answers nothing

Two shapes are reported and never carried, because both are judgement and both
break the next vendor run if guessed at. A candidate whose files an entry the
buffer has and `-dev` lacks also touches is a *supersession*, not an addition --
`0003-Fix-clang-warnings-in-re2` displacing `0003-Try-to-ignore-clang-warnings`,
the real fix replacing the pragma that stood in for it. And an entry `main`
edited in place, which the port brings to `-dev` under a name the buffer already
has: candidates are therefore compared by blob, since a name-only comparison
calls those two stacks level. `0009-Remove-stderr-for-zstd` is that one today.
… the carry

An entry `main` edits in place reaches `-dev` through the port under a name the
buffer already has, so a name-only comparison calls the two stacks level while
they differ -- `0009-Remove-stderr-for-zstd` today. The advice line now names
`series-patch-sync.sh` rather than telling a reader to bring the buffer level by
hand: after a port, what this reports is precisely what the carry declined.
@krlmlr krlmlr changed the title feat(series-check): Report a patch stack that reached -dev and not the buffer feat(series): Carry patch/ entries onto the buffer as part of porting Aug 15, 2026
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.

2 participants