torch, torchvision, Pillow, and open_clip all import and function correctly on Clone (CentOS 6.10, Python 3.8.18, devtoolset-7). A real OpenAI CLIP ViT-B-32 checkpoint downloaded and loaded successfully via open_clip.create_model_and_transforms(). Andrew is imaging Clone NOW (full VM shutdown + disk copy) to preserve this exact working state before anything else touches it./usr/local/bin/python3.8) on a Linux environment./opt/rh/devtoolset-7/root/usr/bin/c++), CMake 3.25.2.This closes out a build effort that spanned multiple sessions (2026-08-23 through 2026-08-30) and three AI collaborators (Claude, Gemini, ChatGPT), starting from the original hard constraint: Live's CentOS 6 glibc 2.12 categorically cannot run torch (ImportError: GLIBC_2.14 not found), and a direct glibc upgrade on Live was ruled out as too dangerous. The entire effort moved to a disposable "Clone" VM to trial builds safely.
Multiple full build attempts failed across earlier sessions on a genuine, hard-to-diagnose multiple definition of DispatchStub linker error. The real root cause (found 2026-08-29): PyTorch's per-CPU-capability dispatch codegen writes wrapper files (Activation.cpp.DEFAULT.cpp, Activation.cpp.AVX2.cpp, etc.) directly into the source tree (aten/src/ATen/native/cpu/), not into build/. Every earlier session's rm -rf build/ never touched this pollution, so it silently compounded across restarts into absurd stacked filenames and eventually broke linking. Fixed via a three-layer git clean (Claude's targeted clean โ Andrew's broader top-level git clean -fdx โ Gemini's git submodule foreach --recursive git clean -ffdx, which also caught staleness hidden inside individual submodules).
libpython3.6.3 for linking despite finding the 3.8.18 interpreter correctly. Fixed by explicitly pinning -DPYTHON_LIBRARY / -DPYTHON_INCLUDE_DIR to the real 3.8 paths.git submodule foreach clean was too thorough and deleted genuinely tracked files (not just build cruft) from third_party/foxi, third_party/QNNPACK, and third_party/python-enum. Fixed with git reset --hard HEAD inside each affected submodule.cc1plus OOM kill on VariableType_2.cpp: PyTorch's huge generated autograd files need several GB per compile unit; MAX_JOBS=4 briefly pushed memory to the edge. Rebooted, increased swap to 6GB, retried โ completed clean.distutils.version AttributeError: tools/setup_helpers/cmake.py used from setuptools import distutils without importing the version submodule explicitly โ newer setuptools no longer auto-attaches it. Fixed with an explicit import distutils.version line.Unix Makefiles; pip install -e . hardcodes -GNinja internally (env var override does NOT work โ it's hardcoded in the build script, confirmed by testing). Resolved by wiping build/ and letting pip install -e . do a full from-scratch Ninja build.third_party/breakpad missing directory: -e .'s default cmake invocation doesn't pass -DUSE_BREAKPAD=OFF the way the manual command did, and the actual breakpad submodule directory is gone (deleted upstream at some point). Fixed by passing USE_BREAKPAD=0 as an environment variable to pip install -e ..cmake.py: at some point during troubleshooting, distutils.version.LooseVersion(x) calls were incorrectly rewritten as tuple(map(int, ...))(x) โ literal Python Ellipsis left in as a placeholder, called as if it were a function (TypeError: 'ellipsis' object is not iterable). Fixed with correct tuple-based version comparison: tuple(int(x) for x in line.strip().split(' ')[2].split('.')), compared against plain (3, 10, 0) tuples โ no distutils dependency needed at all.torch._C extension: cmake --build . --target install succeeded fully and installed all compiled .so libraries (confirmed present in torch/lib/), but the actual importable Python extension module (torch._C, built as _C.cpython-38-x86_64-linux-gnu.so directly inside the torch/ package folder) was never generated, because the packaging/metadata step that normally triggers this crashed first on the distutils bug above. Once that was fixed, running python setup.py build_ext --inplace directly (bypassing pip's packaging wrapper) built and placed _C.cpython-38-x86_64-linux-gnu.so correctly. This was the final blocker โ import torch succeeded immediately after.import torch$ python -c "import torch; print(torch.__version__)"
1.10.0a0+git71f889c
open_clip_torch โ Rust-toolchain wall, worked aroundNo Rust compiler exists on this box; building one from source was explicitly ruled out as its own multi-hour project. Two packages in the dependency chain wanted a Rust build with no available prebuilt wheel for this platform (safetensors, and huggingface-hub's newer hf-xet accelerator):
open_clip_torch --no-deps, then added dependencies individually, skipping/pinning around the Rust wall:
ftfy, regex, tqdm, timm โ installed clean, no issueshuggingface-hub<0.24 โ pinned below the version that introduced the hf-xet Rust dependencytorchvision==0.11.1 --no-deps โ pinned to match PyTorch 1.10's real compatibility matrix (unpinned, it tried to pull its own torch==1.13.1, an 887MB download that would have silently shadowed the custom-built torch)safetensors โ skipped entirely; not needed for standard .bin/.pt format CLIP checkpoints, only for the newer .safetensors weight formatpip install Pillow failed compiling _imagingft.c (the optional font-rendering submodule) against this CentOS 6 box's ancient system FreeType, which predates constants added in FreeType 2.5+ (FT_LOAD_COLOR, FT_PIXEL_MODE_BGRA โ used for color emoji/bitmap font support, unrelated to basic image loading). Not needed at all for CLIP's actual image preprocessing pipeline. Resolved via PILLOW_DISABLE_FREETYPE=1 pip install "Pillow<10", skipping the font module during build.
import torch, open_clip, PIL
model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='openai')
tokenizer = open_clip.get_tokenizer('ViT-B-32')
# SUCCESS: OpenCLIP is fully operational!
The real OpenAI CLIP ViT-B-32 checkpoint downloaded and loaded successfully โ confirming Clone's own internet access is NOT blocked the way the original sandboxed environment's egress allowlist was (that allowlist blocked huggingface.co/openaipublic.azureedge.net in an earlier, different environment months ago).
/usr/local/bin/python3.8readelf -p .comment on compiled objects when in doubt, not just gcc --version (which reflects $PATH resolution, not what CMake's pinned absolute compiler paths actually invoke)~/bin/python and ~/bin/pip symlinked to the 3.8 binaries, with ~/bin prepended to $PATH โ made 3.8 the effective default for interactive use WITHOUT touching /usr/bin/python, which yum hardcodes and depends on (this distinction mattered โ directly repointing /usr/bin/python would have broken yum)/swapfile), 40GB disk (was at ~28GB used mid-build)v1.10.2 (git tag noted; a companion Gemini checkpoint said v1.10.0 โ worth treating v1.10.2 as authoritative since it came directly from git status output, not a manual note)USE_BREAKPAD=0 CMAKE_C_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/gcc CMAKE_CXX_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/c++ MAX_JOBS=4 pip install -e . --no-build-isolation, followed by python setup.py build_ext --inplace to produce the missing _C extensionAndrew is shutting Clone down cleanly and copying the full VM folder to a new sibling directory (matching the proven backup pattern from the earlier glibc-upgrade saga: plain file copy of a powered-off VM, simpler and more reliable than live snapshots) โ to preserve this exact working state before anything else touches this box.
model.encode_image() test against one of Andrew's actual uploaded test attachments (not yet done โ the success test above used the model/tokenizer only, not a real image encode)MediaIndexer.py's two remaining stubs (resolve_attachment_dir(), attachment-id-from-filename derivation), which have been blocked on exactly this "torch actually works" milestone since 2026-08-23MediaSearch.py/RankingEngine.py's v9.0 SimilarityRule scoring logic was already built and tested against mock data months ago โ it can now be fed real embeddings instead of synthetic ones