# Provision the Draupnir geometry engine on irv-ml1. # # scripts/elway irv-ml1 --playbook playbooks/irv-ml1-draupnir-engine.yaml # # Records what was VERIFIED on 2026-09-21, not what was planned. # # ⚠ SUDO IDENTITY. `ssh irv-ml1` is lkraven and has NO NOPASSWD sudo; # `ssh infra-ops@irv-ml1` does. The only step needing root is the artifact # root, so everything else runs as lkraven, where the ssh config and deploy # keys live. # # ⚠ DEPLOY KEY. irv-ml1's ~/.ssh/config pins gitea.phasefinal.com to # `gitea_brokkr_smithy` with IdentitiesOnly yes — its comment is # "irv-ml1-r14-deploy", NOT the arbo key that sorts first in ~/.ssh/*.pub. # Registering the wrong one fails with a message naming the right one, which is # the clue. The key is registered read-only on pfi/draupnir (id 8). # # ⚠ FreeCAD is an AppImage BY CHOICE. The distro package drags a GUI/Qt # dependency tree onto a box running twelve GPU and audio services; an AppImage # is self-contained, pinned, and removable with one rm. Run it as # `FreeCAD.AppImage --appimage-extract-and-run freecadcmd`. # # ⚠ SLICER DEFERRED. PrusaSlicer's latest release ships NO Linux AppImage # (Windows/macOS only), and guessing at a release filename already produced a # 4 KB error page here once. Left undone deliberately rather than done blind. vars: repo: git@gitea.phasefinal.com:pfi/draupnir.git checkout: /home/lkraven/development/draupnir freecad_url: https://github.com/FreeCAD/FreeCAD/releases/download/1.0.0/FreeCAD_1.0.0-conda-Linux-x86_64-py311.AppImage steps: - name: Artifact root on smithy (500 GB budget, per draupnir remote.py) sudo: true shell: mkdir -p /mnt/smithy/draupnir && chmod 2775 /mnt/smithy/draupnir creates: /mnt/smithy/draupnir - name: Clone the engine repo shell: git clone {{ repo }} {{ checkout }} creates: "{{ checkout }}/.git" - name: uv venv on the 3.11 floor shell: cd {{ checkout }} && uv venv --python 3.11 creates: "{{ checkout }}/.venv/bin/python" - name: Install the engine extra (build123d + OCP + numpy + trimesh) shell: cd {{ checkout }} && uv pip install -e '.[engine]' # Idempotent on the INSTALLED package, not on the venv existing. when: "! {{ checkout }}/.venv/bin/python -c 'import build123d' 2>/dev/null" - name: FreeCAD headless AppImage shell: mkdir -p ~/opt && curl -sL -o ~/opt/FreeCAD.AppImage {{ freecad_url }} && chmod +x ~/opt/FreeCAD.AppImage creates: /home/lkraven/opt/FreeCAD.AppImage verify: - name: build123d, numpy and trimesh all import shell: "{{ checkout }}/.venv/bin/python -c 'import build123d, numpy, trimesh, OCP'" changed_when: "false" - name: FreeCAD runs headless shell: ~/opt/FreeCAD.AppImage --appimage-extract-and-run freecadcmd --version changed_when: "false" - name: artifact root is writable by the docker group shell: test -w /mnt/smithy/draupnir changed_when: "false" # The real gate. Both control parts must BUILD and both volumes must match # construction-known arithmetic — not a render, not an opinion. - name: acceptance — contrastive control pair builds with correct volumes shell: >- cd {{ checkout }} && .venv/bin/python -c "import math,runpy; g=runpy.run_path('parts/plate-good/model.py')['result']; t=runpy.run_path('parts/plate-thin-wall/model.py')['result']; wg=40*40*5-math.pi*5**2*5; wt=40*40*5-math.pi*19**2*5; assert abs(g.volume-wg)<1e-6*wg, (g.volume,wg); assert abs(t.volume-wt)<1e-6*wt, (t.volume,wt); assert (round(g.bounding_box().size.X,6),round(g.bounding_box().size.Z,6))==(40.0,5.0); print('acceptance OK')" changed_when: "false"