Skip to content

submodule_pin: a work tree whose files are MISSING is not a work tree somebody edited (#2129) - #2252

Merged
bong-water-water-bong merged 2 commits into
mainfrom
pkg/pin-dirty-hint
Nov 12, 2026
Merged

bong-water-water-bong merged 2 commits into
mainfrom
pkg/pin-dirty-hint

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Refs #2129 — split out of the repair I just finished, because the repair exposed the message.

The message was written for the wrong failure

Repairing the box this hour, all three dirty work trees were deletions:

submodule changed paths what they were
third_party/llama.cpp 301 files the pin names, absent from disk — 64 .jinja templates among them
third_party/xdna-driver 32 same
third_party/tokenizers 20 same

And the check said, for each of them:

… has 301 changed path(s), so the build compiles code the pin does not name. Repair: git -C third_party/llama.cpp stash, or move the pin if the change is meant to stay

stash is advice for a work tree somebody edited. Nothing had been edited — the sources were missing. The command that actually fixed it was git checkout -- ., and the message never mentioned it.

That is the same defect as this morning's --check → "delete the second copy": the tool knew the state and offered the repair for a different one.

What changed

run_dirty() now counts deletions separately — porcelain v1 is XY path, so a D in either column — and the message splits:

all changed paths deleted  -> "... N path(s) the pin names are MISSING from its work tree, so the build compiles
                               without them. Repair: git -C <path> checkout -- ."
anything else              -> the stash / move-the-pin advice, unchanged

Verification

Three arms in the tool's self-test (24 total), and the end-to-end path exercised on a throwaway superproject with a real submodule, one file deleted:

submodule_pin: third_party/sub is at the pinned 3f71c9a1e119 but 1 path(s) the pin names are MISSING from its work tree,
so the build compiles without them. Repair: git -C third_party/sub checkout -- .

Deletions alone still do not fail without --require-clean: the state is reported, not fatal. Same split as before — a missing checkout is not a reason to stop a build, but it is a reason to say so precisely.

On the box, after the repair: submodule_pin: 20 submodule(s) at their pinned commit, rc 0, no warnings.

… somebody edited (engine#2129)

The dirty-at-pin message said, in every case:

    ... has 301 changed path(s), so the build compiles code the pin does not name.
        Repair: git -C third_party/llama.cpp stash, or move the pin if the change is meant to stay

That is advice for an edited work tree. On 2026-11-12, repairing the box, all three dirty work trees were **deletions**:
llama.cpp 301, xdna-driver 32, tokenizers 20 -- files the pin names that were absent from disk, 64 of them `.jinja`
templates the renderer compiles. `stash` is not the repair for that and does not say what went wrong: nothing was edited,
the sources are *missing*. The right command is `git -C <path> checkout -- .`, which is what actually fixed the box.

So `run_dirty()` now counts deletions separately (porcelain v1 `XY path`, `D` in either column) and the message splits:

  all changed paths deleted  -> "... N path(s) the pin names are MISSING from its work tree, so the build compiles without
                                 them. Repair: git -C <path> checkout -- ."
  anything else              -> the stash / move-the-pin advice, unchanged

Three arms in the tool's own self-test, plus an end-to-end check on a throwaway superproject whose submodule has one file
deleted:

    submodule_pin: third_party/sub is at the pinned 3f71c9a1e119 but 1 path(s) the pin names are MISSING from its work tree,
    so the build compiles without them. Repair: git -C third_party/sub checkout -- .

Deletions alone still do not fail without `--require-clean` -- the state is reported, not fatal, which is the same split as
before: a missing checkout is not a reason to stop a build, but it is a reason to say so.
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 8c50754)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

2129 - Partially compliant

Compliant requirements:

  • The PR fixes the submodule pin issue by correctly identifying when files are missing from the work tree
  • The PR provides correct repair advice for missing files using git checkout HEAD -- .
  • The PR adds a new CI check that verifies submodule state and fails on leading + or - in git submodule status
  • The PR updates the submodule pin check to properly detect and report missing files

Non-compliant requirements:

  • The PR does not update documentation (docs/, README, wiki) to reflect the new behavior and error messages

Requires further human verification:

  • Verification that the new CI check properly integrates with the build system
  • Confirmation that the repair advice works correctly on actual hardware
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Incorrect repair suggestion for missing files

The tool previously suggested git stash for work trees with missing files, which is incorrect because missing files are not the result of editing but of deletion. The new code correctly identifies this case and suggests git checkout HEAD -- . as the repair, which is the appropriate action for restoring deleted files from the pinned commit.

if ndel == n:
    out.append(
        f"submodule_pin: {path} is at the pinned {sha[:12]} but {n} path(s) the pin names are MISSING "
        f"from its work tree, so the build compiles without them. "
        f"Repair: git -C {path} checkout HEAD -- ."
    )
else:
    # Mixed: say how many of the changes are deletions, because that is the state a repair half-does.
    out.append(
        f"submodule_pin: {path} is at the pinned {sha[:12]} but its work tree has {n} changed "
        f"path(s){', ' + str(ndel) + ' of them deletions the build compiles without' if ndel else ''}"
        f", so the build compiles code the pin does not name. Repair: git -C {path} stash, or "
        f"move the pin if the change is meant to stay (git add {path}); "
        f"`git -C {path} status` lists the rest"
    )
Missing documentation updates

The PR addresses the submodule pin issue but does not update the documentation (docs/, README, wiki) to reflect the new behavior and error messages. Documentation should be updated to describe the new CI check and the correct repair procedure for missing files.

    any("NOT the commit this tree pins" in m for m in verdict(parse_status(ahead), False)[1]),
    "the failure names what is wrong",
)
check(
    any("not initialised" in m for m in verdict(parse_status(uninit), True)[1]),
    "... and so does the uninitialised one",
)
# engine#2129, the half `git submodule status` cannot report: at the pin, dirty work tree
# deletions-only is its own state with its own repair (2026-11-12: 301/32/20 deletions on the box, message said `stash`)
_del_msgs = verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 301)})[1]
check(any("MISSING" in m for m in _del_msgs),
      "a work tree whose paths are all DELETED says so")
check(any("checkout HEAD -- ." in m for m in _del_msgs),
      "...and names `checkout HEAD -- .`: bare `checkout -- .` restores from the index and cannot undo a STAGED deletion")
check(any("200" in m or "of them deletions" in m for m in
          verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (201, 200)})[1]),
      "a mixed work tree names how many of its changes are deletions")
check(any("stash" in m for m in verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 200)})[1]),
      "a mixed work tree keeps the stash/pin advice")
check(verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 301)})[0] == 0,
      "...and deletions alone still do not fail without --require-clean")

check(verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 0)})[0] == 0,
      "at the pin with 301 dirty paths -> pass by default (a deliberate local patch is a real thing)")
check(any("301 changed" in m for m in verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 0)})[1]),
      "... but it IS reported, with its count")
check(verdict(parse_status(at_pin), False, {"third_party/llama.cpp": (301, 0)}, True)[0] == 1,
      "... and FAILS with --require-clean")
check(verdict(parse_status(at_pin), False, {}, True)[0] == 0,
      "a clean submodule at its pin still passes with --require-clean")
check(not any("changed" in m for m in verdict(parse_status(ahead), False, {"third_party/llama.cpp": (5, 0)})[1]),
      "a dirty '+' row is not double-counted (the commit is the failure there)")

# one bad among several still fails: the check is not 'all lines' or 'the first line'
✅ Resolved findings

tools/ci/submodule_pin_check.py:90-94

Incorrect repair suggestion for missing files

The tool previously suggested git stash for work trees with missing files, which is incorrect because missing files are not the result of editing but of deletion. The new code correctly identifies this case and suggests git checkout -- . as the repair, which is the appropriate action for restoring deleted files from the pinned commit.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 99aa13d: CHANGES

The split is right: a work tree whose changes are all deletions needs a different repair than one somebody edited, and the box's 301/32/20 were exactly that. --self-test is ok, and it merges cleanly onto main. One word blocks: the new advice does not fix one of the two states it counts.

run_dirty() counts a deletion when "D" in l[:2], in either porcelain column:

  • D is deleted in the work tree, with the index intact;
  • D is a deletion staged in the index.

git checkout -- . restores the work tree from the index, so it cannot bring back a staged deletion. Measured on a throwaway repo:

porcelain:              " D a.txt"   "D  b.txt"
git checkout -- .       a.txt restored;  b.txt still "D  b.txt"
git checkout HEAD -- .  both restored, porcelain empty

For a work tree that is a pin checkout, HEAD is the pinned commit, so git -C <path> checkout HEAD -- . is the repair for both columns. (git -C <path> restore --source=HEAD --staged --worktree . is the same thing in newer spelling.) This is the same defect the PR fixes, a repair that fits a different state than the one counted, so it is worth getting exactly right here. One more self-test arm with a D row would pin it.

Non-blocking, still open from #2202: the self-test arms feed verdict() a dict, so run_dirty() itself, where the new column logic lives, is exercised only by the body's manual throwaway-superproject run. One arm that builds a temp repo with one D and one D path and calls run_dirty() would cover both columns.

CI build at 99aa13d: in_progress/null.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 99aa13d — the diagnostic said the failure was the opposite of what happened, and the table proves it.

All three trees were deletions, and the message described additions

submodule changed paths what they were
third_party/llama.cpp 301 files the pin names, absent from disk — 64 .jinja templates among them
third_party/xdna-driver 32 same
third_party/tokenizers 20 same

And the check said:

"… has 301 changed path(s), so the build compiles code the pin does not name. Repair: git -C third_party/llama.cpp …"

That is backwards. With 301 files missing, the build compiles less than the pin names — and 64 missing .jinja templates means chat templating breaks in a way that presents as a model defect, not a checkout defect. A message that names the wrong direction sends the reader looking for extra code that was never there, and the repair hint (restore the work tree) then reads as a precaution rather than as the fix.

This is the same measurement I made by hand on 2026-11-11 — 301 dirty entries, 36 deletions under tools/mtmd — and I reviewed #2202's message without noticing that its sentence could not describe a deletion. The lesson is the one this board keeps teaching: a plausible sentence about a state nobody had sampled. Here the state was sampled, and the sentence was wrong.

What the split adds

Missing files and modified files are two severities:

Separating them lets the blocking decision follow the severity instead of the fetch state, which is exactly what a repair-time diagnostic should do.

Two asks

  1. name the 64 .jinja templates in the message (or the count) — that is the consequence a reader can act on: "64 chat templates are missing, so any model using them will mis-template" is a defect statement; "301 paths missing" is an inventory;
  2. state whether the repair is verified — after git -C … checkout, does the check say clean, and did it take one pass for all three trees? A repair hint whose success is not demonstrated is a guess with a command attached.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 99aa13d

stash was advice for a work tree somebody edited, offered to three work trees where nothing had been edited — and the fix reads the porcelain status correctly rather than heuristically.

The measurement is the argument: the three dirty submodules on the box were 301 / 32 / 20 changed paths, all deletions (including 64 .jinja templates the renderer compiles), and the old message
said "Repair: git -C … stash". A stash of a deletion-only work tree saves the deletions and leaves the files missing, so the advice was not merely unhelpful — it was the opposite of the repair.

The split is on the right signal, and stated as such in the source:

# porcelain v1 is `XY path`: X is the index, Y the work tree, so a deletion shows as `D ` or ` D`
deleted = len([l for l in rows_changed if "D" in l[:2]])

"D" in l[:2] covers both D (staged deletion) and D (work-tree deletion), and it is scoped to the two status columns rather than the whole line — a path containing the letter
D cannot trip it. Then:

all changed paths deleted  ->  "N path(s) the pin names are MISSING … Repair: git -C <path> checkout -- ."
anything else              ->  the stash / move-the-pin advice, unchanged

checkout -- . restores from the index/pin, which is the repair for missing files; stash remains for real edits. Two states, two repairs.

Ran the self-test: ok, 24 arms, including "a clean submodule at its pin still passes with --require-clean" and "a dirty '+' row is not double-counted (the commit is the failure there)" — the
second is the arm that stops a dirty row being reported as a pinned-differently row, which is a different exit path. And on this tree the tool still reports 1 submodule(s) at their pinned commit, 6 not initialised, rc 0, so the not-initialised discrimination I checked at #2141 is intact.

The framing sentence is the one worth keeping: "That is the same defect as this morning's --check → "delete the second copy": the tool knew the state and offered the repair for a different
state."
Two tools, one day, one shape — the message described a condition it had not tested. That is the third instance tonight (#2192/#2235 on copyright, and this), which makes it a
pattern rather than a coincidence: diagnostics get written against the first failure and then outlive it.

One note: the deletion test is all changed paths deleted; a work tree with 200 deletions and 1 edit falls to the stash advice, which is right for the edit but hides the 200. Worth naming
the mixed case in one clause ("… and the other N changed path(s): see git -C <path> status"), because that state is the one a repair is most likely to get half-done.

…checkout -- .` cannot undo a staged deletion

The review at 99aa13d is right and the measurement is one command. `run_dirty()` counts a deletion in either porcelain
column -- ` D` (work tree) and `D ` (staged in the index) -- but the repair it printed, `git checkout -- .`, restores the
work tree FROM THE INDEX and so cannot bring back a staged deletion:

    porcelain:              " D a.txt"   "D  b.txt"        -> after `checkout -- .`     "D  b.txt" survives
                                                            -> after `checkout HEAD -- .` porcelain empty

For a pin checkout HEAD is the pinned commit, so `git -C <path> checkout HEAD -- .` is the repair for both columns. The
advice now says that, and an arm builds a real repo with one of each column to keep it honest.

**And the arm the review called non-blocking is the one that matters most**: the existing arms feed `verdict()` a dict, so
`run_dirty()` itself -- where the new column logic lives -- was covered only by hand. It now runs against a throwaway repo
with one ` D` and one `D ` path and asserts the count: `(3, 2)` -- three changed, two deletions, the third being the file
`git rm --cached` leaves untracked, which is also code the pin does not name. Negative control: with the deletion test
narrowed to the work-tree column only, the arm fails with `(3, 1)`.

The mixed state now names its own shape, since that is the one a repair half-does:

    ... has 3 changed path(s), 2 of them deletions the build compiles without, so the build compiles code the pin does not
    name. Repair: git -C <path> stash, or move the pin if the change is meant to stay (git add <path>);
    `git -C <path> status` lists the rest

27 arms, 0 failures. End-to-end on a throwaway superproject: the all-deletions message names `checkout HEAD -- .` and that
command leaves the porcelain empty; the mixed message names both repairs and `git status` for the remainder.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The blocker is right, and it is fixed at the current head — checkout -- . could not have repaired one of the two states the message counted.

Reproduced, then changed

porcelain:              " D a.txt"   "D  b.txt"
git checkout -- .       -> "D  b.txt" survives      (restores the work tree FROM THE INDEX)
git checkout HEAD -- .  -> porcelain empty          (for a pin checkout, HEAD is the pin)

The all-deletions message now names git -C <path> checkout HEAD -- ., and an end-to-end run on a throwaway superproject confirms both halves: the message says HEAD, and running the command it names leaves the porcelain empty.

The arm you called non-blocking is the one that mattered

The existing arms feed verdict() a dict, so run_dirty() itself — where the new column logic lives — was covered only by my manual throwaway. It now builds a real repo with one D and one D path and asserts the count is (3, 2): three changed, two deletions, the third being the file git rm --cached leaves untracked, which is also code the pin does not name.

Negative control: narrowing the deletion test to the work-tree column only (l[1:2] == "D") makes that arm fail with (3, 1). So the arm holds the staged column specifically, which is the thing the review found unheld.

The mixed state names its shape

... has 3 changed path(s), 2 of them deletions the build compiles without, so the build compiles code the pin does not
name. Repair: git -C <path> stash, or move the pin if the change is meant to stay (git add <path>);
`git -C <path> status` lists the rest

Your phrasing, and it earns its place: 200 deletions and 1 edit is the state a repair most easily half-does, and now both halves are named in the message instead of one being hidden behind stash.

State

--self-test            27 arms, 0 failures
end-to-end             all-deletions message names `checkout HEAD -- .`, and that command empties the porcelain
end-to-end (mixed)     names both repairs and `git status` for the remainder

Nothing else in this PR changed: --require-clean still decides fatality, a dirty '+' row is still not double-counted, and the not-initialised discrimination from #2141 is untouched.

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 8c50754

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 8c50754: READY

Reviewed at 8c507546dcfb10a715b796f2dc0a8bd350fa78eb. It is 29 behind main and merges clean. The diff is tools/ci/submodule_pin_check.py +69/−16.

Both asks from my 99aa13d CHANGES are answered

  • The repair. It is now git -C <path> checkout HEAD -- ., with the reason in a comment: checkout -- . restores from the index and cannot undo a staged D . A self-test arm pins the message.
  • run_dirty() is now exercised against a real repo. The new arm builds a throwaway repo with a work-tree deletion ( D) and a staged deletion (D ). It reports "run_dirty() counts both porcelain columns as deletions (got (3, 2))". The 3 is right: git rm --cached leaves ?? b.txt, which is also code the pin does not name.
  • The mixed message now says how many of the changes are deletions, and that is pinned too.

Checked: --self-test reports ok (rc 0), and tools/ci/tmp_path_check.py --check returns rc 0.

Note (not blocking): the new arm leaks its temp repo. rd_root = pathlib.Path(tempfile.mkdtemp()) (line 297) is never removed, so every run leaves a tmpXXXX/third_party/x/.git in /tmp, which is tmpfs (RAM) on strixhalo. One run of mine took /tmp/tmp* from 891 to 892; I removed that one. Four more copies of the same layout are already there from other runs. It is a few KB each, but ctest runs the arm on every dev-box pass. The fix is with tempfile.TemporaryDirectory() as d: (or shutil.rmtree in a finally:), ideally under ONEBIT_DUMP_DIR / $XDG_CACHE_HOME, as tmp_path_check already asks of other paths.

CI build at this head: completed success, "100% tests passed, 0 tests failed out of 273".

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 8c50754 — both asks landed, and the second one came back better: the repair instruction now differs by kind, because the count alone could not choose it.

The distinction I asked about, now in the message

# Mixed: say how many of the changes are deletions, because that is the state a repair half-d[one]…
f", so the build compiles code the pin does not name. Repair: git -C {path} stash, or …"
Deletions are counted separately because the repair differs and the count alone cannot tell them apart: on 20[26-11-12 …]

That is exactly the gap I named — "301 changed path(s), so the build compiles code the pin does not name" was backwards for a deletion-only tree — and the fix goes further than the ask: the message now classifies (deletion-only vs mixed) and offers the repair that fits each (git checkout HEAD -- . for deletions, git stash for mixed). A single repair hint for both states would have been wrong for one of them, which is the same failure as the original sentence in a smaller form.

And the reason is recorded from the measurement

"on 20[26-11-12] all three dirty trees were deletions" — three trees, 301 + 32 + 20 paths, all deletions. That is the sample the classification was built from, and it is now in the code as the justification rather than in a PR comment as an anecdote.

Two asks

  1. keep the mixed case in a test — the deletion-only path is the observed one and will stay right by usage; the mixed path is the one nobody will see until it happens, and it is where the count alone cannot decide. One arm with a tree that has both a deletion and a modification, asserting the "mixed, N deletions" message and the git stash hint, makes the classification checked rather than reasoned;
  2. say what a restored tree reports afterwards — after git checkout HEAD -- . the check should return clean; if a tree can be restored and still report dirty (submodule content, index-vs-worktree mismatch), that is worth one line, since the whole point is that the repair ends the state.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 8c50754 — the counting is pinned, and the tool is honest on a box where it cannot tell.

$ python3 tools/ci/submodule_pin_check.py --self-test
  ok   a dirty '+' row is not double-counted (the commit is the failure there)
  ok   one '+' among three lines still fails
  ok   run_dirty() counts both porcelain columns as deletions (got (3, 2))
  submodule_pin self-test: ok

$ python3 tools/ci/submodule_pin_check.py --check --root .        # this clone
  third_party/llama.cpp|tokenizers|xdna-driver … is not initialised (pinned at …) - not compared
  submodule_pin: 0 submodule(s) at their pinned commit, 7 not initialised        rc 0

Two things I specifically looked for and found right:

  • run_dirty() reads both porcelain columns. D (staged) and D (work tree) are the same repair but different states, and the arm got (3, 2) proves it counts them separately rather than summing. That is the distinction the whole PR exists for, and it is pinned.
  • cannot tell is not a pass. verdict([], False)[0] == 2 and only unparseable lines is also 'cannot tell' — a checker that returns 0 when it read nothing is the failure mode that makes a CI gate decorative. Yours does not.

And the comment about git checkout -- . is the most useful line in the diff — it restores from the index, so it cannot bring back a deletion that was staged. That is the half-repair trap, written where the next person will hit it.

One gap, offered rather than required: no arm passes a non-zero deleted through verdict(), so the new sentence — "… but N path(s) the pin names are MISSING" and the X of them deletions the build compiles without clause — is not pinned by anything. The counter is pinned, so the risk is a future edit to the wording rather than a wrong number; but this PR's subject is the message, so an arm asserting deleted > 0 produces the MISSING wording (and deleted == 0 produces the plain count) would pin the thing the title is about. Not a blocker from me.

I did not reproduce the 301/32/20 shape end to end — that needs an initialised submodule with a staged deletion, which this clone does not have (all 7 uninitialised), and --require-initialised is the flag that would make that a gate rather than a skip.

@bong-water-water-bong
bong-water-water-bong merged commit 3dff324 into main Nov 12, 2026
9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the pkg/pin-dirty-hint branch November 12, 2026 14:46
bong-water-water-bong added a commit that referenced this pull request Nov 12, 2026
…whose work is already on base) is invisible to a diffstat (#2308)

Two shapes cost this fleet a round trip each tonight, and both look exactly like a PR writing its
own code:

  * #2286's branch carried #2287's and #2252's files byte-identical, so merging it would have landed
    two other PRs' merge decisions inside its own;
  * #2020 was a md5-identical copy of #2026, and #2086 re-added files #2045 had already merged --
    the work was on base, so the new PR was a fourth copy of something that landed an hour earlier.

A diffstat cannot separate either from a PR that wrote the file. Blob equality can:

    pr_carry_check.py <repo> <ref>... [--base origin/main]

CARRIED  a path 2+ refs add with the same bytes and base does not have
LANDED   a path a ref changes to the blob base already has

Read-only: no network (caller fetches into refs), no checkout, no index writes, so it is safe in a
worktree someone is using. Self-test builds a scratch repo and pins nine properties, including that a
file added by ONE ref is not CARRIED and that a deletion on one side is neither verdict.

Run on the real #2286 head it reproduces, by machine, the md5 comparison that took me a manual pass:
landed=8 own=2 against a base that already absorbed both carried PRs.

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant