Seed Revise's cache source hash with a UInt, so 32 bit runs can revise - #80
Merged
Conversation
davidanthoff
force-pushed
the
revise-hash-seed-32bit
branch
from
August 21, 2026 18:56
80087b7 to
5c4f64d
Compare
Revise passes the precompile cache header's content hash to `hash` as a
`UInt64`. The seed `hash` takes is a `UInt`, 32 bits wide on a 32 bit platform,
so on every `x86` leg Revise's package callback dies with
MethodError: no method matching hash(::UInt64, ::UInt64)
at cache_src_id (packages/Revise/src/pkgs.jl:138)
and every test item that loads a package in that process reports the failed
callback as its own error — which is how it surfaced on JuliaMCP's `rc~x86`
legs, in items that have nothing to do with Revise.
The bug is upstream's and the vendored copy is already at 3.16.4, the latest
tag, so re-vendoring is no help; `packages/` is not edited by hand. The method
is replaced instead where `pkg_imports.jl` assembles the `Revise` module, right
after the vendored `packagedef.jl` is included. Truncating with `% UInt` is
enough: the value only identifies a source snapshot within one session, and on
64 bit it is the value Revise already computes.
No unit test — `cache_src_id` lives in the module the test process assembles,
and reaching it from this suite means loading the whole vendored stack for a
one-line method. The `x86` legs are the check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
davidanthoff
force-pushed
the
revise-hash-seed-32bit
branch
from
August 22, 2026 00:22
5c4f64d to
27c4080
Compare
Redefining `cache_src_id` after the vendored `packagedef.jl` is included has the
signature the vendored definition already has, which makes it a method overwrite —
and Julia rejects method overwriting outright while a package precompiles:
WARNING: Method definition cache_src_id(Any) in module Revise at
packages/Revise/src/pkgs.jl:138 overwritten at
testprocess/TestItemServer/src/pkg_imports.jl:106.
ERROR: Method overwriting is not permitted during Module precompilation.
24769.9 ms ? TestItemServer
Precompilation is warn-only on the path a test process takes, so the package still
loaded — at the cost of reloading the whole vendored stack from source in every test
process, and of a precompile banner on its stderr that landed in whatever a test item
captured. That is what reddened the 64 bit legs: the assertions that a process's output
carries no ANSI escapes, the coverage items whose processes then went unanswered, and
the recycling items that timed out on the extra startup.
Add the method rather than replace it: both call sites pass a
`Base.CacheHeaderIncludes`, so a method on that type is strictly more specific and wins
dispatch without touching upstream's `cache_src_id(::Any)`. Guarded to 32 bit, where the
bug is — on 64 bit the vendored definition already computes the right value, and leaving
its dispatch and invalidation exactly as upstream ships them is one less thing to reason
about. `inc.hash` is a `UInt32`, so `UInt(inc.hash)` is an exact widening on either word
size; `isdefined` covers the internal Base type.
The suite had nothing asserting that TestItemServer's cache is actually built — this
only surfaced through unrelated assertions about process output — so add a test item
that precompiles the version-matched test process environment and fails on a `?`.
`Base.compilecache` rather than `Pkg.precompile`, because it rebuilds unconditionally
and reports failure as a return value instead of exiting 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Revise passes the precompile cache header's content hash to
hashas aUInt64. The seedhashtakes is aUInt, 32 bits wide on a 32 bit platform, so on everyx86leg Revise's package callback dies:Every test item that loads a package in that process then reports the failed callback as its own error, which is how this surfaces on JuliaMCP's
rc~x86legs in items that have nothing to do with Revise.This replaces the first version of this PR, which fixed it by editing
packages/Revise/src/pkgs.jl. That was wrong —packages/holds git subtrees that are never edited by hand. Re-vendoring is no help either: the bug is upstream's, and the vendored copy is already at 3.16.4, the latest tag, whosesrc/pkgs.jl:138still readscache_src_id(inc) = hash(inc.fsize, UInt64(inc.hash)).So the method is supplied where
testprocess/TestItemServer/src/pkg_imports.jlassembles theRevisemodule, right after the vendoredpackagedef.jlis included. It is added, not redefined: a definition with the vendored signature is a method overwrite, which Julia rejects outright while a package precompiles, and the second commit here fixes exactly that regression from the first —Precompilation is warn-only on the path a test process takes, so
TestItemServerstill loaded — at the cost of reloading the whole vendored stack from source in every test process, and of a precompile banner on its stderr that landed in whatever a test item captured. That is what reddened the 64 bit legs: the assertions that a process's output carries no ANSI escapes, the coverage items whose processes then went unanswered, and the recycling items that timed out on the extra startup.Both call sites (
Revise/src/loading.jl:118,Revise/src/pkgs.jl:192) pass aBase.CacheHeaderIncludes, so a method on that type is strictly more specific and wins dispatch without touching upstream'scache_src_id(::Any). Guarded to 32 bit, where the bug is — on 64 bit the vendored definition already computes the right value, and leaving its dispatch and invalidation exactly as upstream ships them is one less thing to reason about.inc.hashis aUInt32, soUInt(inc.hash)is an exact widening on either word size;isdefinedcovers the internal Base type, whose shape is unchanged from 1.11 through nightly.The suite had nothing asserting that
TestItemServer's cache is actually built — the breakage only surfaced through unrelated assertions about process output — sotest/test_testserver_precompile.jlprecompiles the version-matched test process environment and fails on a?. It usesBase.compilecacherather thanPkg.precompile: that rebuilds unconditionally, so a cache another item already wrote cannot short-circuit it, and it reports failure as a return value instead of exiting 0. Verified to fail on the overwriting form and pass on this one.Smoke-tested under both
1.12and1.12~x86: the environment precompiles✓on both, the two methods coexist with the 32 bit one winning dispatch and computing the same value, and the color-output, coverage and worker-recycling items all pass.Found while auditing the stack for Julia 1.13 readiness; like #79 this is a word-size bug the rc legs merely made visible. An upstream Revise PR follows, so the override can be dropped at the next re-vendor.
Note for the
x86legs: they will keep failing "Coverage without coverage roots" after this merges. That failure's stack trace points into~/.julia/packages/TestItemControllers/…, i.e. the registered TestItemControllers thatjuliatiruns the suite on, not the checkout — it is present onmaintoday and clears only once a release carrying this fix is registered.🤖 Generated with Claude Code