Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
0b6d28f
docs(handoff): thesis plant on VDSim-Thesis branch — beta, evaluate→i…
Onlyti Jun 17, 2026
60ae7ca
feat(plant): VLA thesis plant v0 [BETA] — Ld2 CmdL1 direct-torque, fr…
Onlyti Jun 17, 2026
da7dc99
fix+test(plant): brake must not reverse the wheel; strengthen VLA acc…
Onlyti Jun 17, 2026
5e2b33e
test(plant): dry handling == linear bicycle (4%) + faster-than-realti…
Onlyti Jun 17, 2026
fc14a71
docs(handoff): VLA plant beta v0 verified — brake fix + 6 acceptance …
Onlyti Jun 17, 2026
e3d6192
docs(plant): customer follow-along tutorial manual (code + YAML examp…
Onlyti Jun 17, 2026
d79a954
feat(plant): MF2002 .tir tyre for the VLA plant — load-dependent stif…
Onlyti Jun 17, 2026
0a48180
docs(plant): update tutorial + quick-ref to MF2002 .tir tyre [BETA]
Onlyti Jun 17, 2026
4482fd9
docs(plant): add thesis-side delivery note (BETA #1 handover)
Onlyti Jun 17, 2026
94aa7d7
docs(plant): BETA #1 feedback — external-interpreter rebuild section …
Onlyti Jun 17, 2026
18e3e96
feat(plant): expose realized peak mu per wheel — fixes useGT>1 (optio…
Onlyti Jun 17, 2026
4cd5e2f
docs(plant): changelog section + BETA #1 round closed (mu_peak synced…
Onlyti Jun 17, 2026
5e47606
docs(plant): record declined grip_usage obs field (keep raw-GT-only s…
Onlyti Jun 17, 2026
927d7ea
docs(plant): rename useGT -> sat (friction saturation ratio) + not-a-…
Onlyti Jun 17, 2026
2dc31fd
feat(plant): expose per-wheel peak slip (alpha_peak/kappa_peak) — raw…
Onlyti Jun 17, 2026
fec1fd1
feat(plant): complete the standalone tyre evaluator for offline combi…
Onlyti Jun 18, 2026
268038c
feat(plant): reach the live tyre model via the object graph (plant.ti…
Onlyti Jun 18, 2026
139ea59
feat(plant): hierarchical data-access view (plant.vehicle.tire.model/…
Onlyti Jun 18, 2026
2aa8f67
docs(plant): TODO for the remaining parts on the data-access view
Onlyti Jun 18, 2026
83a26bd
docs(catalog): add computational cost per dynamics level (K-L5 benchm…
Onlyti Jun 18, 2026
178fac3
docs(plant): promote peak-slip safety metric + warn conda rebuild + r…
Onlyti Jun 18, 2026
8f79c3a
docs(plant-delivery): warn conda Python rebuild (critical entry barrier)
Onlyti Jun 18, 2026
3bd2dc0
docs(roadmap): log VLA Plant API P1/P2 customer requests + link PLANT…
Onlyti Jun 18, 2026
6623f55
feat(plant): P1 roll/pitch obs + 2D polygon friction; P2 smooth 1D tr…
Onlyti Jun 18, 2026
c4b5c0a
feat(core): TireSetup per-wheel, session factory, friction canonical,…
Onlyti Jun 20, 2026
e5fb2c6
feat(plant): wire VDSimPlant to direct_control session + SimOutput obs
Onlyti Jun 20, 2026
5a0877e
docs(handoff): thesis freeze tag + core port to main note
Onlyti Jun 20, 2026
1f280ee
feat(review): structured agent review process + catalog/session fixes
Onlyti Jun 21, 2026
8d81c07
docs(governance): demand-gate via VDSim-PO for new fidelity
Onlyti Jun 25, 2026
a44b593
feat(gui): preserve GUI v3 at P0 parity gap 0
Onlyti Jun 25, 2026
4f948a5
fix(plant): CmdL1 per-wheel torque binding + Fx plant path
Onlyti Jun 25, 2026
fe6cd6c
ci(wheels): P0-1 cibuildwheel + PyPI publish pipeline
Onlyti Jun 25, 2026
31ab596
chore(cursor): add copyedit and personalize rules
Onlyti Jun 25, 2026
7f2328d
feat(quickstart): P0-2 wheel-native pip quickstart
Onlyti Jun 25, 2026
0219b2c
feat(demo): P0-3 headless grip-loss GIF + README timing fix
Onlyti Jun 25, 2026
6cca449
docs(validation): P0-4 currency and credibility forward placement
Onlyti Jun 25, 2026
ac81535
feat(trace): .vdtrace run container + headless trace renderer
Onlyti Aug 20, 2026
dae1752
fix(demo): put in-tree modules ahead of any installed vdsim_plant
Onlyti Aug 20, 2026
483bec7
docs(readme): document .vdtrace recording and headless render usage
pacificsunfish Aug 20, 2026
eb085e6
feat(render): overlay several .vdtrace runs in one comparison view
Onlyti Aug 20, 2026
9914e71
feat(render): separate waypoint / target / prediction in the BEV view
Onlyti Aug 20, 2026
7a16939
docs(readme): document controller horizons — waypoint / target / pred…
Onlyti Aug 21, 2026
ad41e5a
Render angular channels in degrees
Onlyti Aug 25, 2026
75fe64a
docs(p0-4): front-load validation currency and verification scope
Onlyti Aug 31, 2026
ffe4be7
feat(comms): implement json and nmea_gga TX templates
Onlyti Sep 1, 2026
369697d
fix(comms): exact WGS84 ENU inverse + degenerate-state guards for tex…
Onlyti Sep 1, 2026
a4a30ea
fix(comms): reject non-invertible ENU states instead of emitting an i…
Onlyti Sep 1, 2026
cb76552
test(cosim): add the cmrosif compat sources the ctest registration al…
Onlyti Sep 1, 2026
1d05017
fix(comms): test the whole evolute, not just the spin axis, in the EN…
Onlyti Sep 1, 2026
034a1da
feat(cosim): parse scene sensor mount pose/id/rate into WorldScenario
Onlyti Sep 1, 2026
85fb328
fix(cosim): a mount-only sensors: block must not suppress the scenari…
Onlyti Sep 1, 2026
02ccdbf
fix(comms): reject out-of-range GGA origin latitude
Onlyti Sep 1, 2026
272f1cb
docs(cosim): formalize scene sensor parser contracts
Onlyti Sep 1, 2026
d976b19
fix(cosim): reject null scene sensor options
Onlyti Sep 1, 2026
49fb2f8
feat(render): add steering and speed instruments
Onlyti Sep 1, 2026
ba1bbc3
fix(render): isolate T6 instrument layout
Onlyti Sep 1, 2026
4c1fcb6
feat(tools): import AC fast lane M1 paths
Onlyti Sep 1, 2026
fb9817d
fix(tools): validate AC AI spline grid tails
Onlyti Sep 1, 2026
8306853
test-core-freeze-D0-flat-contact-baseline
Onlyti Sep 1, 2026
97a9a21
test-core-add-L4-D0-baseline
Onlyti Sep 1, 2026
4f900fa
feat-core-D1-contact-frame
Onlyti Sep 1, 2026
2e8f91c
fix(core): apply full D1 contact wrench
Onlyti Sep 1, 2026
5c740dc
fix(core): close non-flat vertical load path
Onlyti Sep 1, 2026
1054890
fix(core): subtract legacy load on world z
Onlyti Sep 1, 2026
ac15b33
feat(core): resolve grade and bank loads on the road frame
Onlyti Sep 1, 2026
ee63484
fix(core): close D2 road-load verification gaps
Onlyti Sep 1, 2026
aa2c3d5
test(core): replace brittle D1 road-load oracle
Onlyti Sep 1, 2026
e10611d
feat(trace): declare the run's role in schema 0.2
Onlyti Sep 2, 2026
f1f2006
feat(render): add the overview render preset and its config loader
Onlyti Sep 2, 2026
aee9835
build(ctest): gate deferred and optional tests out of the canonical c…
Sep 4, 2026
1ad89a5
docs: record the canonical ctest count and gate it against drift
Onlyti Sep 4, 2026
155479b
ci: pin one CMake for the canonical measurement and record it
pacificsunfish Sep 4, 2026
70234e5
docs: gate the recorded commit on an unchanged registration surface
Onlyti Sep 4, 2026
f215e5d
docs: refresh MkDocs product status
Onlyti Sep 4, 2026
158ad14
chore: remove personal agent config from the open-core repo
pacificsunfish Sep 4, 2026
9ec30ce
chore: remove personal agent config from the open-core repo
pacificsunfish Sep 4, 2026
824d2fc
chore: remove personal agent config from the open-core repo
pacificsunfish Sep 4, 2026
3f3b12d
merge: feature line A (scene-sensors/trace/render/D0-D2) into main
Onlyti Sep 6, 2026
708c1d4
merge: feature line B (render presets) into integration
Onlyti Sep 6, 2026
94ca585
merge: feature line C (canonical validation config) into integration
Onlyti Sep 6, 2026
5f13cba
fix: make the merged tree pass under the canonical validation preset
Onlyti Sep 6, 2026
38d86d5
ci: install the Python deps the merged suite needs in both jobs
Onlyti Sep 6, 2026
f9cf765
test: state the plant speed budget per build configuration
Onlyti Sep 6, 2026
c70b3a9
docs: record the canonical suite figure for the integration tree
Onlyti Sep 6, 2026
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
2 changes: 1 addition & 1 deletion .cursor/rules/vdsim.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ alwaysApply: true
# VDSim — conventions & guardrails (any Cursor agent must follow)

Before working, read `docs/HANDOFF.md` (current state / next task) and the relevant
`docs/design/*.md` (the spec). Cursor-usage rules: `docs/design/CURSOR_USAGE.md`.
`docs/design/*.md` (the spec).

## Conventions
- Wheel index order: FL=0, FR=1, RL=2, RR=3 (all code/docs/plots).
Expand Down
100 changes: 97 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ on:
pull_request:
branches: [main]

env:
# Single pinned CMake for every job in this workflow, matching the version
# recorded on the `toolchain:` line of docs/VALIDATION.md. Never `latest`:
# a toolchain bump is a re-measurement trigger, so it has to be an explicit
# edit that lands in the same commit as the refreshed numbers.
VDSIM_CMAKE_VERSION: 3.31.10

jobs:
build:
runs-on: ubuntu-22.04
Expand Down Expand Up @@ -39,12 +46,16 @@ jobs:
- name: Install Python dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install "pybind11==2.13.6" numpy pyyaml
python3 -m pip install "pybind11==2.13.6" numpy pyyaml matplotlib pillow

- name: Report toolchain
run: |
python3 --version
python3 -c "import pybind11, numpy, yaml; print('pybind11', pybind11.__version__); print('numpy', numpy.__version__); print('pyyaml', yaml.__version__)"
- name: Pin CMake
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: ${{ env.VDSIM_CMAKE_VERSION }}

- name: Cache FetchContent
uses: actions/cache@v4
Expand All @@ -69,8 +80,91 @@ jobs:
# optimisation, so they are given the budget that matches what they are,
# not an exemption: the assert still runs and still fails on a real
# regression.
- name: Test
- name: Test (Debug budget)
if: matrix.build_type == 'Debug'
working-directory: build
env:
VDSIM_PERF_BUDGET_S: ${{ matrix.build_type == 'Debug' && '10.0' || '1.0' }}
VDSIM_PERF_BUDGET_S: '10.0'
run: ctest --output-on-failure

# Release states no budget: it runs on the defaults compiled into the
# tests, which are the Release contract. Injecting a value here would
# quietly relax the only configuration that can detect a real regression.
- name: Test
if: matrix.build_type != 'Debug'
working-directory: build
run: ctest --output-on-failure

# Canonical configuration (the `validation` CMake preset). This is the only
# job whose ctest numbers docs/VALIDATION.md is allowed to record, and the
# gate below fails if the document no longer matches what was measured.
# See VDSimMarketing 07_p0_demo.md 6.4 / 6.5 / 6.6.
validation:
runs-on: ubuntu-22.04
name: validation preset / currency gate

steps:
- uses: actions/checkout@v4
with:
# Full history so the currency gate can test whether the commit
# recorded in docs/VALIDATION.md is an ancestor of what was built.
fetch-depth: 0

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build python3-dev

# The validation preset builds the Python bindings, and the canonical
# suite includes the catalog, plant and trace/render tests, so the same
# pinned dependency set as the build job has to be present here too.
- name: Install Python dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install "pybind11==2.13.6" numpy pyyaml matplotlib pillow

- name: Pin CMake
# CMakePresets.json is version 3, which needs CMake >= 3.21, so the
# runner image default is deliberately not relied upon.
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: ${{ env.VDSIM_CMAKE_VERSION }}

- name: Record toolchain
run: cmake --version | tee cmake-version.txt

- name: Cache FetchContent
uses: actions/cache@v4
with:
path: build-validation/_deps
key: ${{ runner.os }}-deps-validation-${{ hashFiles('third_party/CMakeLists.txt') }}

- name: Configure (validation preset)
run: cmake --preset validation -Dpybind11_DIR="$(python3 -m pybind11 --cmakedir)"

- name: Build (validation preset)
run: cmake --build --preset validation

- name: List registered tests
run: ctest --preset validation -N | tee ctest-list.txt

- name: Run tests
id: run
continue-on-error: true
run: ctest --preset validation | tee ctest-run.txt

- name: VALIDATION.md currency gate
run: |
python3 scripts/check_validation_currency.py \
--doc docs/VALIDATION.md \
--ctest-list ctest-list.txt \
--ctest-run ctest-run.txt \
--cmake-version-file cmake-version.txt \
--commit "${{ github.sha }}" \
--repo .

- name: Fail if the suite did not pass
if: steps.run.outcome != 'success'
run: |
echo "ctest reported failures in the canonical configuration"
exit 1
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Build directories
build/
build-*/
build_*/
out/
cmake-build-*/

Expand Down Expand Up @@ -76,6 +77,7 @@ apps/jump_demo/*/frames/
*.tir
# Exception: public synthetic coefficients for the Chrono Pac02 parity gate (no measured data)
!external/chrono_parity/sample_pac02.tir
!configs/parts/tire/ioniq5_pac2002.tir
# Chrono parity build artifacts (the reference CSV IS committed; these are not)
external/chrono_parity/build/
external/chrono_parity/_pac02_chrono.json
Expand All @@ -91,3 +93,11 @@ apps/validation/results/
# Catalog: generated resolve cache + GUI-runtime-registered package stub
configs/.resolve_cache/
configs/catalog/packages/gui_custom/

# Per-agent / personal tooling config (not part of the open-core product)
AGENTS.md
.cursor/rules/00-personalize.mdc
.cursor/rules/copyedit-en.mdc
.cursor/rules/copyedit-ko.mdc
.cursor/rules/over-eng-review.mdc
.cursor/rules/temp-debt.mdc
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,41 @@ All notable changes to VDSim are documented here. Format follows

## [Unreleased]

### Added — `.vdtrace` run container + headless trace renderer
- **`.vdtrace` container** (`python/vdsim_trace.py`): one zip per simulation run —
`manifest.json` + `channels/<name>.f64` (C-order little-endian float64, stored
uncompressed so loading is a `np.frombuffer` reshape) + `overlays/<name>.json`.
Ten channels (`t`, `pose`, `v_body`, `yaw_rate`, `u_steer`, `u_fx`, `wheel_F`,
`wheel_mu`, `wheel_kappa`, `wheel_alpha`); the channel table is self-describing,
so consumers select fields from the manifest instead of hardcoding a list.
- **Opt-in recording** (`VDSimPlant.enable_trace(path, decimation=N)` /
`finalize_trace()`), default OFF. `decimation=None` targets a 100 Hz record rate,
so a 1 kHz control loop stores 1 sample in 10 and a 20 Hz loop stores all of them.
- **Overlay pass-through** (`vdsim_trace.attach_overlay`): reference paths, lateral
error, events and regions are attached after the run and stored verbatim. VDSim
validates the `kind`/`name` envelope and never interprets the content, so
scenario concepts stay out of the plant.
- **Reproduction metadata**: `repro` carries `vdsim_version`, `git_sha`, `param_hash`,
`seed`, `dt_s` and `run_id`. `param_hash` covers plant parameters only (vehicle,
tyre, road mu, dt) — runs of the same vehicle over different scenarios share a hash.
- **Headless renderer** (`python/vdsim_render.py`, `vdsim-render` CLI): BEV tracking
camera with driven path, body rectangle, steered front wheels, velocity arrow,
fixed HUD, per-wheel friction-utilization colour and a command time-series panel
with a time cursor. GIF + preview PNG through the existing `[plot]` extra; MP4 only
when `imageio-ffmpeg` is present. No GUI, no node/npm/browser.
- **Friction utilization is derived, not recorded**:
`sqrt((Fx/(k_lon*mu*Fz))^2 + (Fy/(k_lat*mu*Fz))^2)` with `k_*` from manifest
`tire.mu_aniso`, measured per tyre by `vdsim_plant.measure_mu_aniso()`. A trace
without a `tire` block is rejected rather than defaulted to `[1, 1]`, which would
under-report saturation on an elliptic tyre.
- `examples/demo_grip_loss.py` now records a trace and renders it — the contract's
first consumer, and its self-check.
- Tests `trace_roundtrip` / `trace_render` on a committed golden fixture
(`tests/fixtures/trace/golden_v0_1.vdtrace`); both run without the compiled core.
Recording OFF costs -0.4 % of `step()` vs. the pre-hook baseline (gate: <= 1 %),
ON at the default decimation +0.9 %; a 30 s trace renders in 51 s at 20 fps
(`tools/bench_trace_overhead.py`).

### Added — load-dependent Re, camber contact migration & inverted tire interface
- **Effective rolling radius `Re(Fz)`** (Pacejka BREFF/DREFF/FREFF) across L1/L2/L3/L5:
slip `= (omega*Re - vx)/vx`, so a free-rolling loaded tire reports `kappa = 0` (matches
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@

## 빌드
- CMake (CMakeLists.txt). docs = mkdocs (github.io 배포)
- 공통: ~/.claude/CLAUDE.md (wheel FL=0, ISO 8855)
- 전역 규약: wheel index FL=0/FR=1/RL=2/RR=3, ISO 8855 RH (+x fwd, +y left, +z up) — 상세는 .cursor/rules/vdsim.mdc
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ option(VDSIM_BUILD_PYTHON "Build Python bindings" OFF)
option(VDSIM_BUILD_CARLA_PLUGIN "Build CARLA integration" ON)
option(VDSIM_BUILD_COSIM "Build UDP co-simulation server" ON)
option(VDSIM_WITH_ERGACCESS "Build with CarMaker ERGAccess" OFF)
# GUI v3 is a deferred (node-stack) component. Its whole test group is outside
# the canonical `validation` preset; see the `excluded:` lines in
# docs/VALIDATION.md. Exclusion is per component, not per target, so future
# GUI v3 tests attach to this same switch (07_p0_demo.md 6.4(2)).
option(VDSIM_BUILD_GUI_V3_TESTS "Register the GUI v3 test group" OFF)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-parameter)
Expand Down Expand Up @@ -70,3 +75,4 @@ message(STATUS "Build examples : ${VDSIM_BUILD_EXAMPLES}")
message(STATUS "Build Python : ${VDSIM_BUILD_PYTHON}")
message(STATUS "Build CARLA plugin : ${VDSIM_BUILD_CARLA_PLUGIN}")
message(STATUS "ERGAccess : ${VDSIM_WITH_ERGACCESS}")
message(STATUS "GUI v3 tests : ${VDSIM_BUILD_GUI_V3_TESTS}")
33 changes: 33 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version": 3,
"cmakeMinimumRequired": { "major": 3, "minor": 21, "patch": 0 },
"configurePresets": [
{
"name": "validation",
"displayName": "Canonical validation configuration",
"description": "The single configuration whose ctest count docs/VALIDATION.md is allowed to record. See VDSimMarketing 07_p0_demo.md 6.4.",
"binaryDir": "${sourceDir}/build-validation",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"VDSIM_BUILD_TESTS": "ON",
"VDSIM_BUILD_EXAMPLES": "ON",
"VDSIM_BUILD_PYTHON": "ON",
"VDSIM_BUILD_COSIM": "ON",
"VDSIM_BUILD_CARLA_PLUGIN": "ON",
"VDSIM_WITH_ERGACCESS": "OFF",
"VDSIM_BUILD_GUI_V3_TESTS": "OFF"
}
}
],
"buildPresets": [
{ "name": "validation", "configurePreset": "validation", "jobs": 0 }
],
"testPresets": [
{
"name": "validation",
"configurePreset": "validation",
"output": { "outputOnFailure": true },
"execution": { "noTestsAction": "error" }
}
]
}
17 changes: 15 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,23 @@ openly.

```bash
cmake -DVDSIM_BUILD_PYTHON=ON -B build && cmake --build build -j
cd build && ctest --output-on-failure # 191 checks, must stay 100% green
cd build && ctest --output-on-failure # must stay 100% green
```
Before quoting a suite count anywhere, reproduce it in the canonical
configuration — that is the only one [docs/VALIDATION.md](docs/VALIDATION.md)
records, and the `validation_currency` test fails if the two disagree:
```bash
cmake --preset validation && cmake --build --preset validation && ctest --preset validation
```
Building VDSim needs CMake ≥ 3.16; reading `CMakePresets.json` (schema v3) needs
**CMake ≥ 3.21**, so the canonical run has the higher floor. CI pins one exact
CMake (`VDSIM_CMAKE_VERSION` in `.github/workflows/build.yml`) and the same
version is used on the measurement host — changing it means re-measuring in the
same commit.

Python package: `pip install ".[plot]"` (Python ≥ 3.10 with a modern `pip`).
CI (GitHub Actions) builds gcc-9 + clang-10 and runs ctest on every push/PR.
CI (GitHub Actions) builds gcc-11 + clang-14 on Ubuntu 22.04 and runs ctest on
every push/PR.

## Conventions (non-negotiable — they keep results comparable)

Expand Down
Loading
Loading