Tools/shadow_gap.py measures the vertical pixel gap between an object's lowest pixels and the top of its shadow, as a fraction of the object's height, and calls it contact or floating. It classifies a shadow by per-channel scaling - a shadow darkens every channel by the same proportion, an object does not - which separates the two where an absolute delta cannot. Four unit tests cover contact, floating, an empty box and the border median. On the real spawn view it returns 'unknown': the crop contains two surfaces (pale wall behind, dark road below) and one global background cannot classify both. Recorded as the next step, not presented as working. The spawn height is measured and cleared: tracing down from 30 m, the topmost surface under the player is Z 366 and the capsule's feet are at 369 - 3 cm, the capsule skin. If the character still reads as floating, the gap is between the rendered pavement and its collision surface, not the spawn Z, and that is what to measure next.
Tooling tests
Standard-library unittest tests for the host-side tools in Tools/. They never start Blender, Unreal, or the game; anything that needs those processes is verified by the tool itself and recorded in Docs/release-checks.md instead.
Run from the repository root:
python3 -m pip install -r requirements-tools.txt
python3 -m unittest discover -s Tools/tests -t Tools -p 'test_*.py'
The -t Tools top-level directory is required: the tests import the tool modules by their plain names (import input_emulation), which is why Tools/tests/ carries an __init__.py.
Individual test:
python3 -m unittest Tools.tests.test_input_emulation -v
What belongs here
Test the pure parts — argument parsing, key/coordinate encoding, geometry maths, licence gating, report formatting, decision classification. Network, Blender and Unreal calls stay out: a test that needs a paid API, a display, or an engine process is a manual check, not a unit test.
When a tool's logic is buried in main(), extract it into a function so it can be tested directly. That is a tooling improvement, not test scaffolding.
Geo (Geo/tools/) and Blender (Art/blender/*/) builders are tested the same way once their pure parts are extracted; note the module path in the test.