# Test Plan: Invalid Parent Assignment Bug ## Overview Comprehensive test suite to capture and validate parent-child relationship bugs in orbital mechanics simulation. **Date:** January 20, 2026 **Status:** Complete (Tests 1-3 resolved) **Related:** `docs/mission_planning.md` FIXME section --- ## Bug Diagnosis ### Root Cause Identified **The Bug (Fixed):** In `tests/configs/earth_mars_simple.toml`, spacecraft had placeholder values: - `position = {1.496e11, 0, 0}` (IDENTICAL to Earth) - `velocity = {0, 0, 0}` (zero velocity) - `SOI = ~17.3 meters` (calculated from mass=1kg) **What Happened:** 1. Config loaded with spacecraft at Earth's exact position 2. During `find_dominant_body(1)` for Earth: - Checks all bodies - Finds spacecraft at distance = 0 - `0 < 17.3` is TRUE - Sets Earth's parent to spacecraft! **Why Test Failed But GUI Failed Worse:** - Test calls `initialize_spacecraft_leo()` → spacecraft moved to proper LEO orbit (200km from Earth) - GUI never called this → placeholder values caused immediate bug ### Solution Implemented **Config Validation in `src/config_loader.cpp`:** - Added validation loop after parsing bodies, before `initialize_bodies()` - Validates that distance between body and parent ≥ parent.radius + body.radius - Provides clear error message with actual and required distances - Prevents loading invalid configs with bodies too close to their parents **Config Fix in `tests/configs/earth_mars_simple.toml`:** - Changed spacecraft position from `1.496e11` (same as Earth) to `1.49606571e11` - This places spacecraft at proper LEO altitude: Earth position + 6,571,000 m - 6,571 km = Earth radius (6,371 km) + 200 km altitude --- ## Test Cases ### Test Case 1: Earth→Spacecraft Parent Switch **Purpose:** Directly detect when Earth's parent becomes spacecraft (the exact bug from FIXME) **Actual Result:** ✅ **PASSES** **How It Was Fixed:** - Config validation now rejects bodies starting at parent's position - Spacecraft properly positioned at LEO altitude (6,571 km from Earth center) - `find_dominant_body()` never finds spacecraft at distance=0 - Earth's parent remains Sun throughout simulation **Config:** `tests/configs/earth_mars_simple.toml` **Key Assertion:** ```cpp REQUIRE(sim->bodies[EARTH_IDX].parent_index != SPACECRAFT_IDX); ``` --- ### Test Case 2: Mass Hierarchy Validation **Purpose:** Validate that massive bodies never become children of small bodies **Actual Result:** ✅ **PASSES** **How It Was Fixed:** - Config validation ensures proper parent-child distance - Mass hierarchy preserved throughout simulation - Earth never becomes child of spacecraft or other bodies **Config:** `tests/configs/earth_mars_simple.toml` **Key Assertions:** ```cpp // Parent must be more massive REQUIRE(mass_ratio >= 1.0); // For planets: parent should be significantly more massive if (not spacecraft) { REQUIRE(mass_ratio >= 1000.0); } // Massive bodies should never have small bodies as parents if (child_mass > 1e20) { // Planet-scale REQUIRE(parent_mass > child_mass); } ``` --- ### Test Case 3: Config Placeholder Validation **Purpose:** Detect invalid config initialization (bodies starting too close together) **Actual Result:** ✅ **PASSES** **How It Was Fixed:** - Test updated to use radius-based validation (matches config_loader logic) - Spacecraft now at proper LEO position: 6,571,000 m from Earth center - Validation: distance (6,571,000 m) ≥ Earth.radius + spacecraft.radius (6,372,000 m) - Config validation catches any bodies positioned within parent's radius **Config:** `tests/configs/earth_mars_simple.toml` **Key Assertion:** ```cpp double min_distance = sim->bodies[EARTH_IDX].radius + sim->bodies[SPACECRAFT_IDX].radius; REQUIRE(distance >= min_distance); // parent.radius + body.radius ``` --- ### Test Case 4: Mutual SOI - Similar Mass Planets **Purpose:** Edge case: two Earth-like planets positioned within each other's SOI **Actual Result:** ❌ **STILL FAILS** (separate issue, not fixed by spacecraft validation) **Config:** `tests/configs/mutual_soi_close.toml` **Setup:** - PlanetA: mass = 5.972e24 kg, position = {1.496e11, 0, 0} - PlanetB: mass = 5.972e24 kg, position = {1.501e11, 0, 0} - Separation: 5e8 meters (500 million km) - Planet SOI: ~9.25e8 meters (925 million km) - **Both planets within each other's SOI** **Why This Fails:** - Both planets start with parent=0 (Sun) - Both are within each other's SOI - `find_dominant_body()` logic selects closest body within SOI - Result: PlanetA selects PlanetB as parent, PlanetB selects PlanetA as parent - Config validation passes (both are ≥ parent.radius + body.radius from Sun) **Key Assertions:** ```cpp // Both should orbit Sun (not each other) REQUIRE(sim->bodies[PLANET_A_IDX].parent_index == SUN_IDX); REQUIRE(sim->bodies[PLANET_B_IDX].parent_index == SUN_IDX); // Planets should never have each other as parents for (int parent : history.planet_a_parents) { REQUIRE(parent != PLANET_B_IDX); } for (int parent : history.planet_b_parents) { REQUIRE(parent != PLANET_A_IDX); } ``` **Expected Behavior (Option A):** - Both planets should continue orbiting Sun - Neither should become other's parent - This requires future fix to `find_dominant_body()` logic (mass hierarchy check) --- ## Test Matrix | Test Case | Config | Tests | Expected (Before Fix) | **Actual Result** | |-----------|--------|-------|----------------------|--------------------------------| | **1. Earth→Spacecraft** | earth_mars_simple.toml | Parent assignment | **FAIL** | **✅ PASS** | | **2. Mass Hierarchy** | earth_mars_simple.toml | Mass ratios | **FAIL** | **✅ PASS** | | **3. Config Validation** | earth_mars_simple.toml | Separation distance | **FAIL** | **✅ PASS** | | **4. Mutual SOI** | mutual_soi_close.toml | Edge case behavior | **FAIL** | **❌ FAIL** (separate issue) | --- ## Implementation ### Test File `tests/test_invalid_parent_assignment.cpp` ### Test Config Files - `tests/configs/earth_mars_simple.toml` (existing) - `tests/configs/mutual_soi_close.toml` (new) ### Build Integration Add to CMakeLists.txt or Makefile test targets --- ## Implementation Summary **Solution Applied (Jan 20, 2026):** 1. **Config validation in `src/config_loader.cpp`**: - Validates parent-child distances before initialization - Requires distance ≥ parent.radius + body.radius - Prevents loading invalid configs 2. **Config fix in `tests/configs/earth_mars_simple.toml`**: - Spacecraft position corrected to proper LEO altitude - Position: 1.49606571e11 m (Earth position + 6,571,000 m offset) - Velocity calculated by `initialize_bodies()` using `semi_major_axis = 6.571e6` 3. **Test updates in `tests/test_invalid_parent_assignment.cpp`**: - Test 3 updated to use radius-based validation - Matches config_loader validation logic --- ## Future Work ### Current Status Tests 1-3 are now passing. Test 4 continues to fail, documenting a separate mutual SOI issue. ### Potential Fixes for Test 4 1. Add mass hierarchy check to `find_dominant_body()` 2. Prevent mutual SOI assignments for similar-mass bodies 3. Detect and reject invalid configs at load time 4. Implement proper N-body interaction or restricted 3-body solution ### Enhanced Detection - SOI overlap detection at config load time - Automatic correction of invalid parent assignments - Validation warnings for edge cases --- ## References - `docs/mission_planning.md:125-135` - FIXME section describing bug (now resolved) - `src/config_loader.cpp:138-157` - Config validation implementation - `tests/configs/earth_mars_simple.toml` - Corrected spacecraft position (LEO altitude) - `src/simulation.cpp:64-107` - `find_dominant_body()` implementation - `src/simulation.cpp:212-233` - `initialize_bodies()` implementation - `tests/test_invalid_parent_assignment.cpp` - Test suite implementation ## Commits - `0239cc1` - Add test suite for invalid parent assignment bugs - `899fa3b` - Add config validation for parent-child distances