subagent transcript
session 18e25685 · workflow wf_23df5b1c
delegated task
You are an adversarial verifier for a FreeCAD-wasm code review. A reviewer claims: SEVERITY: high CATEGORY: reproducibility-trampoline-patch FILE: /ho
▸ Magik
You are an adversarial verifier for a FreeCAD-wasm code review. A reviewer claims:
SEVERITY: high
CATEGORY: reproducibility-trampoline-patch
FILE: /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Main/CMakeLists.txt
SUMMARY: The load-bearing getPyEMTrampolinePtr->0 fix is a manual hand-edit of the GENERATED FreeCAD.js, not baked into the build; a clean relink silently reintroduces the Python->OCCT trampoline crash.
DETAIL/EVIDENCE: src/Main/CMakeLists.txt:83 and STATUS.md:22 both claim the JS-trampoline force is 'applied post-link'/'baked post-link', but there is NO automation anywhere that applies it. Source /opt/toolchains/src/Python-3.14.4/Python/emscripten_trampoline.c:57 is UNPATCHED (`function getPyEMTrampolinePtr() {` with the original iOS/try body; first `return 0` is only on the error/iOS paths at lines 69,77). Yet /opt/toolchains/src/freecad-gui-build/bin/FreeCAD.js and freecad-port/deploy-gui/FreeCAD.js both begin `function getPyEMTrampolinePtr(){return 0;let isIOS=...` — i.e. `return 0;` was hand-injected into the emscripten-generated JS after link. grep across all *.sh/*.py/*.md finds zero sed/patch step. Consequence: re-running `ninja FreeCADMain` regenerates FreeCAD.js from the unpatched EM_JS and drops the forced-JS-trampoline, so `_PyEM_TrampolineCall` crashes ('unreachable') under ASYNCIFY exactly as R10 describes — the entire 'winning' config silently regresses on any rebuild.
RECOMMENDATION: Make the patch part of the build: either patch emscripten_trampoline.c in the CPython source tree (add a patch file under toolchain/patches/ and apply it during the python build) so the EM_JS emits `return 0;` at compile time, or add a deterministic post-link step (e.g. a --post-js override of setEmscriptenTrampoline, or a checked-in sed run as a CMake POST_BUILD command) so relinking cannot lose it.
Independently verify by reading the actual file(s) and running git/grep as needed (repo at /home/magik6k/lcad-wasm/freecad-port/FreeCAD, toolchain at /opt/toolchains, deploy at /home/magik6k/lcad-wasm/freecad-port/deploy-gui). Default to REFUTED if you cannot confirm the evidence. Adjust severity to what the evidence actually supports.
Fable
thinking
I need to verify whether the getPyEMTrampolinePtr->0 fix is actually part of the build process or just a manual edit to the generated FreeCAD.js file, so I'm going to look at the relevant source files to check.
Fable
⚙ Bash {"command": "sed -n '75,95p' /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Main/CMakeLists.txt 2>/dev/null; echo \"---STATUS---\"; sed -n '15,30p' /home/magik6k/lcad-wasm/freecad-port/STATUS.md 2>/dev/null; echo \"---TRAMPOLINE SRC---\";…
Fable
⚙ Bash {"command": "echo \"===build FreeCAD.js head===\"; head -c 300 /opt/toolchains/src/freecad-gui-build/bin/FreeCAD.js 2>/dev/null | grep -o 'getPyEMTrampolinePtr(){[^}]*' | head -1; echo; grep -o 'function getPyEMTrampolinePtr(){return 0' /op…
Fable
thinking
I've confirmed the evidence: the source file is unpatched with the full iOS logic intact, both generated FreeCAD.js files have the injected `getPyEMTrampolinePtr` returning 0, and the build claims it was applied post-link. Now I'm searching through all shell, Python, and markdown files to check if there's any automated process actually applying this transformation.
Fable
⚙ Bash {"command": "echo \"=== grep getPyEMTrampolinePtr in scripts ===\"; grep -rn \"getPyEMTrampolinePtr\" /home/magik6k/lcad-wasm --include=*.sh --include=*.py --include=*.md --include=*.txt --include=*.cmake 2>/dev/null; echo \"=== grep sed/pa…
Fable
⚙ Bash {"command": "echo \"=== toolchain patches dir ===\"; ls -la /opt/toolchains/patches/ /home/magik6k/lcad-wasm/toolchain/patches/ 2>/dev/null; find /home/magik6k/lcad-wasm /opt/toolchains -name \"*.patch\" 2>/dev/null | head; echo \"=== grep …
Fable
thinking
I need to verify that the CPython patch doesn't modify the emscripten_trampoline.c file, and double-check whether the source code actually lacks a return statement at the top.
Fable
⚙ Bash {"command": "echo \"=== does cpython patch touch trampoline? ===\"; grep -l \"trampoline\\|TrampolinePtr\" /home/magik6k/lcad-wasm/freecad-port/toolchain/patches/cpython-3.14.4-wasm-static-embed.patch 2>/dev/null && echo \"YES\" || echo \"N…
Fable
thinking
I've confirmed the core issue: the emscripten trampoline source file remains unpatched with its full iOS implementation, the cpython toolchain patches don't address it, yet both FreeCAD.js builds have been manually modified to return 0 on the trampoline function. The CMakeLists configuration appears to be part of this puzzle too.
The documentation claims the fix is applied post-link, but there's no automation—no sed scripts, patches, or post-build steps actually implementing this. This means a clean rebuild would regenerate FreeCAD.js from the unpatched source, losing the injected `return 0` and reintroducing the crash. The dead code after the return statement in the generated form confirms …
Fable
All evidence verified independently:
1. **Source unpatched**: `/opt/toolchains/src/Python-3.14.4/Python/emscripten_trampoline.c:57` reads `function getPyEMTrampolinePtr() {` with the full iOS/try-fallback body; `return 0` appears only on the iOS path (line 69) and the catch fallback (line 77). No leading `return 0;`.
2. **Generated JS hand-injected**: Both `/opt/toolchains/src/freecad-gui-build/bin/FreeCAD.js` and `freecad-port/deploy-gui/FreeCAD.js` begin `function getPyEMTrampolinePtr(){return 0` — with the original iOS body following as dead code after the return, proving post-generation injection.
3. **No automation exists**: grep across all `.sh`/`.py`/`.md`/`.cmake` finds zero sed/patch/POST_BUILD/--post-js step touching the trampoline or FreeCAD.js. The only hits for `getPyEMTrampolinePtr` are the two prose claims (CMakeLists.txt:83 "applied post-link", STATUS.md:22 "baked post-link") plus R10 research notes. The one CPython patch under `toolchain/patches/` (cpython-3.14.4-wasm-static-embed.patch) does NOT touch the trampoline.
The claim is fully substantiated: the "applied/baked post-link" wording is aspirational — nothing automates it, so a clean `ninja` relink regenerates FreeCAD.js from the unpatched EM_JS and drops the forced JS trampoline, reintroducing the ASYNCIFY crash. Severity high is appropriate: the patch is load-bearing (its loss = total failure of the documented winning config) and the falsely-documented automation makes the regression silent, though it is a reproducibility/rebuild landmine rather than a defect in the currently-shipped artifact.
Fable
⚙ StructuredOutput {"verdict": "CONFIRMED", "reason": "Verified all evidence: emscripten_trampoline.c:57 in the CPython source tree is unpatched (`function getPyEMTrampolinePtr() {` with full iOS/try body; `return 0` only on iOS path line 69 and catch fallbac…