Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/VALIDATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ the last section.
| ISO 7401 step-steer / 4138 understeer / 3888-2 DLC — run + measured | — |
| L1↔L2↔L3 cross-model consistency where physics overlaps | Dependent axles (twist-beam / solid beam) — configs are stubs |
| FMI round-trip Δ=0 (machine precision); ISO 8608 PSD RMS per class | L3 unsprung lateral-transfer term (small) |
| Full suite: **492/492 ctest green** (`validation` preset, as of 2026-09-18) | — |
| Full suite: **492/492 ctest green** (as of 2026-09-18; `validation` preset — see the currency block below) | — |
| Drivetrain engine inertia (open-diff carrier coupling) | — |
| **ISO step-steer signature gated in CI** (`ctest -R IsoBaseline`, sedan L2 LuGre) | DLC moose gate is a preset property, not a defect (see note) |

Expand Down Expand Up @@ -52,7 +52,7 @@ tests: 492/492
config: cmake --preset validation && cmake --build --preset validation && ctest --preset validation
presets: CMakePresets.json@fb1f0c198a0201fcce2543a9f5b2242a255fb97a
toolchain: cmake 3.31.10
commit: 1fc790e
commit: 13e28de
date: 2026-09-18
excluded: gui_v3_e2e (GUI v3 test group formally deferred -- VDSIM_BUILD_GUI_V3_TESTS=OFF)
excluded: gui_v3_api_smoke (GUI v3 test group formally deferred -- VDSIM_BUILD_GUI_V3_TESTS=OFF)
Expand Down
1 change: 1 addition & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ if(pybind11_FOUND)
${CMAKE_SOURCE_DIR}/python/vdsim_trace.py
${CMAKE_SOURCE_DIR}/python/vdsim_render.py
${CMAKE_SOURCE_DIR}/python/vdsim_render3d.py
${CMAKE_SOURCE_DIR}/python/vdsim_preset.py
${CMAKE_SOURCE_DIR}/cosim/protocol.py
${CMAKE_SOURCE_DIR}/examples/opendrive.py
${CMAKE_SOURCE_DIR}/examples/rd5_route.py
Expand Down
63 changes: 63 additions & 0 deletions tests/scripts/test_render_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
"""
from __future__ import annotations

import ast
import json
import math
import re
import sys
import tempfile
from pathlib import Path
Expand Down Expand Up @@ -267,6 +269,66 @@ def test_layout_guard_catches_an_escape():
plt.close(fig)


def _shipped_module_names():
"""Top-level module names the wheel installs, read from the install rules.

The wheel manifest lives in ``python/CMakeLists.txt`` under
``if(DEFINED SKBUILD)``; parsing it here keeps the check honest when that
list changes, instead of restating the list in a second place.
"""
text = (REPO / "python" / "CMakeLists.txt").read_text()
body = text.split("if(DEFINED SKBUILD)", 1)[1].split("endif()", 1)[0]
names = {"vdsim"} # install(TARGETS vdsim_py ...)
for m in re.finditer(r"\$\{CMAKE_SOURCE_DIR\}/([^\s)]+)", body):
rel = m.group(1)
stem = Path(rel).name
names.add(stem[:-3] if stem.endswith(".py") else stem)
return names


def _first_party_imports(py_path):
"""Top-level names ``py_path`` imports that resolve inside this repo."""
tree = ast.parse(py_path.read_text())
wanted = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
wanted.update(a.name.split(".")[0] for a in node.names)
elif isinstance(node, ast.ImportFrom) and node.level == 0 and node.module:
wanted.add(node.module.split(".")[0])
here = set()
for name in wanted:
for d in ("python", "cosim", "examples"):
if (REPO / d / (name + ".py")).exists() or (REPO / d / name).is_dir():
here.add(name)
break
return here


def test_wheel_ships_every_first_party_import():
"""A shipped module may not import a module the wheel leaves behind.

Measured 2026-09-18 (pre-flight C-2): the wheel carried vdsim_render.py but
not vdsim_preset.py, so ``import vdsim_render`` raised ModuleNotFoundError
for every pip user while the source tree stayed green. The failure mode is
invisible in-tree, which is why it is pinned here rather than left to the
packaging job.
"""
shipped = _shipped_module_names()
check("vdsim_preset" in shipped, "the wheel ships vdsim_preset")
missing = []
for name in sorted(shipped):
for d in ("python", "cosim", "examples"):
p = REPO / d / (name + ".py")
if p.exists():
for dep in sorted(_first_party_imports(p)):
if dep not in shipped:
missing.append("%s imports %s" % (name, dep))
break
check(missing == [],
"every shipped module's first-party imports are shipped too (%s)"
% (", ".join(missing) if missing else "none missing"))


def main():
test_builtin_surface()
test_unknown_and_reserved_names_are_refused()
Expand All @@ -277,6 +339,7 @@ def main():
test_required_channel_is_an_error()
test_panel_geometry_is_fixed()
test_layout_guard_catches_an_escape()
test_wheel_ships_every_first_party_import()
if FAILURES:
print("\n%d check(s) failed" % len(FAILURES))
for f in FAILURES:
Expand Down
Loading