Skip to content

BUG: make every step_simulation call advance the flight - #26

Merged
thc1006 merged 1 commit into
developfrom
fix/a-step-that-always-steps
Aug 2, 2026
Merged

BUG: make every step_simulation call advance the flight#26
thc1006 merged 1 commit into
developfrom
fix/a-step-that-always-steps

Conversation

@thc1006

@thc1006 thc1006 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Closes #20, taking the direction you described there.

I think we can fix the places that return without advancing a step, so we don't need to have extra checks to make sure .step_simulation() actually steps.
We can refactor this so it moves to the next phase in the same step to correctly advance one step

The change

The phase transition set phase_index += 1, marked the phase uninitialised and returned, so that call moved neither t nor y_sol. It now carries on into the new phase in the same call, so the only path that returns without advancing is the one that has just set finished, which you said was fine to leave.

Ignoring whitespace it is a while loop and a continue. The rest of the diff is the indentation that loop adds, so git diff -w is the readable version.

Measured

On flight_calisto:

calls calls that did not advance final t
before 5 2 48.4363
after 3 0 48.4363

Same flight, fewer calls. The existing test_stepped_trajectory_matches_simulate compares the whole solution against simulate() at rtol=1e-8 and still passes, so the nodes being walked are the same ones.

What it does to the Challenge

A caller that counts one step per call records one fewer step, since the transition no longer costs one. Checked rather than assumed, on scenario 0 with the shipped example agent:

steps recorded popped final flight.t
before 6012 10 60.0968
after 6011 10 60.0968

Scenario 1 is 5964 to 5963, also with the score unchanged.

The step that goes is a degenerate one. The last three recorded rocket positions are identical, (45.155, -0.048, 20.0), because the rocket has landed, so the sweep that disappears has zero length and cannot reach a balloon the previous sweep did not.

The Challenge's golden masters pass. Its step-count check allows an absolute two steps of drift, which is deliberate and documented there, and the whole suite is green at 557 passed.

Things I went looking for afterwards

The loop terminates. continue is only reached after phase_index += 1, and the bound is len(self.flight_phases) - 1, so it is strictly increasing towards an exit. Phases can be added during a flight, but only from __simulate and from the parachute triggers that are not migrated into the stepping path, and neither is reachable from the continue branch, which runs no node. Checked with the apogee and non-apogee cases as well.

No mid-flight call is affected. On both shipped Challenge scenarios the calls that did not advance are the last two and nothing earlier:

scenario 0: 6012 steps, stalls at [6011, 6012], mid-flight stalls 0
scenario 1: 5964 steps, stalls at [5963, 5964], mid-flight stalls 0

So an agent sees the same observations for the whole flight, and only the two calls after landing change.

Nothing else in the file moved. Comparing the two flight.py at the AST level, the only function that differs is step_simulation, and the difference is one While, one Continue and the True constant. ruff format touched the indentation and no logic.

Submissions made before this still verify after it. A file packed against the current develop and checked by a copy of the Challenge running this branch passes all nineteen checks, with the balloon trajectories matching to 0.000e+00 m over 6012 steps. Worth knowing because the leaderboard already holds submissions made against the old behaviour.

Tests

Three added, and the one that matters fails on the obvious mutation:

put the early return back fails
test_no_call_returns_without_advancing yes, and the other ten still pass

The other two are controls: that more than one phase is still visited, so returning early on every call would not pass, and that the flight still ends where simulate() ends, so absorbing the transition does not skip the node it was standing on.

Local run of CI: ruff check, ruff format --check, pylint rocketpy/ tests/ docs/ exiting 0, and 149 unit plus 152 integration tests passing.

A call that landed on a phase boundary advanced the phase index, left the new
phase uninitialised and returned, so it moved neither t nor y_sol. A caller
counting one step per call, which is what the Balloon Popping Challenge
environment does, then ran ahead of the flight's own clock.

The phase transition now carries on into the new phase in the same call, so
the only path that returns without advancing is the one that has just set
finished, and by then there is nothing left to advance.

Measured on flight_calisto: 5 calls with 2 that did not advance, against 3
calls with none. Final t is 48.4363 either way, so the same flight is being
walked in fewer calls rather than a different one.

Ignoring whitespace the change is a while loop and a continue; the rest of the
diff is the indentation that loop adds.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
@zuorenchen

Copy link
Copy Markdown
Member

Thanks for the fix

@thc1006
thc1006 merged commit c80f0dc into develop Aug 2, 2026
10 checks passed
@thc1006
thc1006 deleted the fix/a-step-that-always-steps branch August 2, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants