Repository navigation
Verify #8078 removes the split-module unknown-wrapper collision #8064
Description
Status
The code fix is merged on main:
- PR: Scope split unknown-function fallback wrappers by module #8078
- audited head:
6772b8111aeeb047d4ebbcebcfce7a0e8a7e9736 - merge commit:
5c27d1ad9b588f69fa2677acd8ae99dc5303e712 - focused emitted-IR regression: passed
- two separately split modules + real shared object link regression: passed
- landing-tree
perry-codegensuite: 996/996 passed
The original global symbol ___perry_wrap_perry_unknown_func is replaced by stable module-scoped fallback names while unsplit copies retain internal linkage.
This ticket now has one bounded purpose: verify that the original production-sized duplicate-symbol boundary is gone. It is not a tracker for every later Next.js, provider, GC, or App Route problem.
Original production boundary
On b0f13fb5ef39eb26463d4bc82f7cd6812acea69f, the pinned Next.js 16.3.0 webpack App Route graph from #8034:
- passed the byte-identical 21-request Node oracle;
- collected and emitted 91/91 Perry module objects;
- cleared the former split-unit
ptrtointfailures; - failed the final app-only dylib link because four objects exported the same
___perry_wrap_perry_unknown_func.
The old local replay log was:
/Users/amlug/cargo-targets/next-prod-gate/evidence/perry-route-compile-b0f13fb5.log
Do not depend on that path existing. Regenerate the pinned fixture from #8034 when necessary.
Remaining worker task
-
Fetch current
mainand record the exact commit/tree. -
Generate/build the pinned Next.js 16.3.0 webpack fixture from [Next.js/dylib] Add a pinned production App Route parity fixture and CI gate #8034. Confirm the Node oracle inputs are the generated production route graph; a direct call to the user
GETexport is not a substitute. -
Build one coherent release artifact set from that same Perry SHA in an isolated target:
cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-static -p perry-ext-http -p perry-ext-net -
Record SHA-256, size, and mtime for
perry,libperry_runtime.a,libperry_stdlib.a,libperry_ext_http.a, andlibperry_ext_net.a; prove no writer remains before the replay. -
Compile the same app-only graph from scratch with the isolated release directory pinned:
PERRY_RUNTIME_DIR=<target>/release PERRY_NO_AUTO_OPTIMIZE=1 PERRY_NO_CACHE=1 <target>/release/perry compile --no-cache --no-auto-optimize --output-type dylib perry-host.js -o next-app-route-current.dylib -
Preserve the full module-emission/final-link log and report the exact final boundary.
Closure rule
Close #8064 after exactly one of these outcomes:
- Success: the 91-module graph reaches the final link and the app-only dylib is produced without a duplicate unknown-wrapper symbol.
- Advanced to a distinct blocker: all former colliding modules emit, the old global duplicate symbol is absent, and the replay fails later for a causally different reason. File that reason as a new narrowly scoped issue with the exact SHA/log/diagnostic, cross-link it here, then close Verify #8078 removes the split-module unknown-wrapper collision #8064 as fixed by Scope split unknown-function fallback wrappers by module #8078.
Do not keep #8064 open for:
- executing the 21 Perry requests;
AppRouteRouteModule.handlebehavior;- provider ABI/runtime behavior after a successful link;
- moving-GC or verifier evidence;
- performance.
Those belong to #8034/#8040 or a new dedicated blocker. This issue is complete once the collision itself is disproved on the pinned production graph.
Activity
[-]Split modules collide on global unknown-function fallback wrapper[/-][+]Verify #8078 removes the split-module unknown-wrapper collision[/+]proggeramlug commentedon Aug 14, 2026
Updated after #8078 merged. This ticket is now intentionally bounded to one current-main replay proving that the original duplicate unknown-wrapper symbol is absent. A later, causally distinct failure must move to a new issue and must not keep #8064 open. The issue body now contains the exact artifact build, replay steps, evidence requirements, and closure rule.
proggeramlug commentedon Aug 14, 2026
Verified: the duplicate unknown-wrapper collision is gone on the pinned production graph
Replay completed against the bounded closure rule. Outcome is Success (first bullet): the 91-module graph reached the final link and the app-only dylib was produced with no duplicate unknown-wrapper symbol.
Artifact set
Built from
5c27d1ad9b588f69fa2677acd8ae99dc5303e712(the #8078 merge commit) in an isolated target. Hashes re-verified after the replay and identical to the pre-replay snapshot (lsof_writers=0at snapshot time):Oracle
The pinned Next.js 16.3.0 webpack App Route graph from #8034, exercised through the generated production route (not a direct call to the user
GETexport):Replay result
Wrote object file:x91), noError compiling module, noPERRY_ALLOW_PARTIAL_CODEGEN.Linking (with stdlib)... Wrote shared library: next-app-route-current.dylib(239 MB).PERRY_RUNTIME_DIRpinned to the isolated release dir, confirmed in-log by thelibperry_ext_http.a/libperry_ext_net.arouting lines resolving under that target.The discriminating evidence
A clean link on its own would be vacuous — it is also what you get if no wrapper is emitted at all. So the wrapper population in the produced dylib was counted directly:
___perry_wrap_perry_unknown_funcis absent (0 occurrences of the unsuffixed symbol).One deviation, stated plainly
Three earlier attempts on this host died from resource exhaustion, not from the product: two SIGBUS and two ENOSPC (the machine was down to a few GiB). The accepted run therefore lowered
PERRY_LL_O0_THRESHOLD_BYTES/PERRY_LL_SIZE_OPTso oversized modules compile at-O0rather than the default-Osdowngrade (#4880).That knob only selects LLVM's optimization pipeline for oversized modules. The unknown-wrapper names are chosen in Perry's own codegen, upstream of LLVM, and external symbols are not DCE'd at any level — so it cannot manufacture or hide the collision. The wrapper census above confirms this directly: the wrappers were emitted, and the four link-visible ones are the exact set that previously collided.
Closing as fixed by #8078. Later App Route behavior, request execution, provider ABI, GC, and performance stay with #8034 / #8040 per the closure rule.