Xenon 2

Autopilot · write-up

Remove unnecessary velocity fitting

xenondoc/AUTOPILOT_EXACT_MOTION_CONSUMERS.MD · 6 KB · updated 2026-09-17

Changes

Known motion now feeds closing-speed estimates and targeting through the selected trajectory predictor instead of the standalone velocity fitter. The controller was missing the standalone predictor's exact shell-oscillator branch; it now handles phase and reversals there as well. The maneuver adapter samples existing shell, formation and script paths, preserving world-coordinate/camera handling.

Closing-speed calculations use the next predicted displacement as their velocity estimate. Aim positions continue to use the trajectory at the estimated flight time. This is not a new exact interception solver; estimating flight time itself remains approximate. Branches that return a fixed firing station do not request an unused velocity first.

Unknown movement retains least-squares fitting, computed lazily and cached against the exact immutable history tuple. Changed histories invalidate the derived value; dataclass replacement does not carry the private runtime cache. Direction-table projectiles retain their exact velocity. The experimental eager C fitter remains off by default: this change does not compute fits for every observed object.

Replay/live display arrows sample predicted displacement at their displayed horizon instead of extrapolating a fitted line. Selection details use the predicted next-frame displacement. This uses the active controller's existing paths where available. Observability remains Python and is outside the replay timing scope.

Timing and work counts

Two opposite-order repeats, CPU 4, Level 1 frames 2367–10059:

Metric Previous fitting path Exact consumers + lazy fallback
Mean observation milliseconds 3.20223 3.22978
Estimator calls (profile) 72,157 26,558
Actual least-squares fits (profile) 65,828 10,786
Estimator cumulative seconds (profile) 0.6784 0.1976

Actual fits are counted from the six sum calls per complete reference fit. This removes 83.6% of fits and 70.9% of profiled estimator time. Overall timing is 0.86% higher, but the new variant's repeats differ by about 3.3%; there is no proved overall speedup or slowdown from these timings. Exact path sampling and other pipeline work offset part of the local saving. Do not equate fewer fits with a measured end-to-end win.

compare_kernels.py --variants c-fitting-old,c retains the previous fitting and linear dispatch for comparison. Deferring unused fixed-station calculations is common to both variants, so the comparison excludes that small additional saving. Artifacts under xenon_tools/run_logs/: - exact-motion-timing-0908/comparison.json: repeated timings. - exact-motion-profile-0908/comparison.json: separate profile and .pstats. - exact-motion-level{2,3,4,5}-0908/comparison.json: cross-level decisions.

Behavior validation

The new trajectory consumers intentionally change some decisions: - Level 1: 13 verdict frames, 2400 and 2402–2413, in combat_hold. - Level 2: 15 verdict frames, 32895–32898, 33427, 33429, 33434–33436, 33438–33442 and 33519, in scroll_spawn_pacing. - Level 3: no changed verdicts. - Level 4: frame 63609, still swarm_sweep with the same action and predicted contact at frame 44; another compared result changed. - Level 5: no changed verdicts.

Level 1/2 changed verdicts report no predicted contact in either variant. This is an inspection of recorded observations, not proof of shield/life outcomes in a fresh closed-loop run. The comparison tool exits with a decision-difference error for the affected recordings; those reports were inspected, not counted as identical replays.

Targeted tests verify shell reversal without a fitter call, prepared-script path reuse, and lazy fallback/history invalidation. The final full suite passes 933 tests; the log is exact-motion-ui-tests-0908.txt. No C source was changed in this waste-removal step; the earlier optional ABI-20 fitter remains in the working tree.

Fresh live validation (2026-09-08)

Run exact-motion-live-0908-02.validation used the native kernel, spans navigation, normal speed and no cheats, starting from assets/xenonplay.sav. The intended stop was Level 2 entry. Progression failed: the user observed shots passing to the left of a shell, and the run was stopped at trace frame 7734.

  • No lives lost; shield 39 to 35 from one directional-projectile hit at frame 5410 (swarm_escape). This corresponds to baseline frame 7246 after the initial frame-number offset of 1836.
  • First shop: 600 cash; purchased SPEEDUP for 500 at frame 3418.
  • Shell #9435 was targeted continuously over frames 5635-7734. Samples from 5800 onward show ship x=239, station x=240, aim x=244.5, unchanged shell health 2 and unchanged score 26200. At the last frame aim x=243.5 and the shell collision bounds span x=240-247. The retained maneuver oscillates vertically rather than correcting horizontal alignment.
  • Inspect frames 5600-5900 for entry into the stall, or 7400-7734 for the stable failure. This is not a successful level validation or evidence that the latest change alone caused the stall; the earlier live baseline predates several changes.

The recording is exact-motion-live-0908-02.x2events inside that validation folder, alongside paired AVIs and periodic emulator/controller checkpoints. The console interrupt ended the Python processes before normal finalization; PAUSE, STOP_AVI, STOP_LOG, SAVE_STATE and RELEASE_INPUT were subsequently sent successfully through the control API. The final emulator save has no matching final controller sidecar; use the complete periodic checkpoint at frame 7652 for a resumable controller state.

Next correction: reconcile the firing station with the actual projectile lane and target hitbox, including movement tolerance, and invalidate a retained attack when sustained firing makes no health/progression change.