Engagement: ErikEvenson/galaxy#1428 · reviewer Pattern-B · HEAD 5633fc641 (0.65.86) · static/unit only, no live solve
Verified against HEAD 5633fc641 + gist d8c9b391e9ef608bc0eb0bfe748fc107. REARM_CAP=3
bounds the raise↔rendezvous oscillation, parks safe + escalates on the Nth strand-recurrence,
and — the load-bearing question — counts sub-surface STRAND-recurrences, not all re-arms, so
it cannot abort a legitimate approach. Not a dock claim (that's #1427). #1397/#1424 stay
operator-gated; #1428 is pure hardening, no gate.
automation.py:2273_rendezvous_rearm_after_raise: readsrearm_countfrom the maneuver dict,+= 1, and atrearm_count >= REARM_CAP(=3,:187) returnsFalse.- Caller
_complete_maneuver(:2490): onrearm_engaged == Falseit takes the legacy clear path →clear_maneuver(ship_id). The ship is left on the orbit the just-completedperiapsis_raiseproduced — periapsis raised aboverp_safe + _PERIAPSIS_RAISE_BUFFER_M(20 km headroom,deviation_monitor.py) so it does not immediately re-trip Trigger 2. Park-safe is genuinely a bounded orbit ≥ floor, not a re-strand. - Escalation is real, not a silent stall:
record_ship_log(ship_id, "rearm_cap_reached", …)writes a player-facing ship-log entry ("Rendezvous abandoned after 3 crash-safety recoveries … manual intervention needed"). Best-effort wrapped so it can never block the park-safe fall-through. Non-resetting is the crux and is correct:replan_countresets to0per re-armed leg (right below),rearm_countrides through the raise (submit_periapsis_raisenever touches it) and the re-arm → it accumulates cross-cycle.
This is the question that decides correctness, and the code gets it right by construction:
rearm_countis incremented in exactly one place:_rendezvous_rearm_after_raise.- That function is called in exactly one place —
_complete_maneuver:2486— gated onmaneuver.get("type") == "periapsis_raise". periapsis_raiseis armed in exactly one place —deviation_monitor.py:1408— gated ontrigger_reason == "periapsis_violation" and trigger_detail.get("sub_surface"). It is a crash-safety recovery from a sub-surface periapsis, never a planned leg of an approach.- ⇒ every
rearm_countincrement == exactly one sub-surface strand → raise → re-arm cycle. It is a strand-recurrence counter. - A legitimate rendezvous that re-solves/re-arms for ordinary reasons (
position_deviation,coast_parity_replan) goes through the normalsubmit_replanpath bounded by the resettingreplan_countand never touchesrearm_count. A legitimate multi-phase approach that makes genuine progress and docks completes astype == "rendezvous"(notperiapsis_raise) and never re-enters the incrementing function. - ⇒ valid long / multi-phase dockings are NOT capped. The only thing that reaches the cap is
3 sub-surface strands — which is by definition the pathological oscillation (sub-surface
periapsis is a crash state below
rp_safe, never a planned waypoint). No reset-on-progress is needed precisely because each increment already is a crash event, not a progress step. The concern that it might blindly count all re-arms and kill valid approaches does NOT apply.
TestPeriapsisRaiseRearm (test_automation.py), driving the real _complete_maneuver:
test_rearm_cap_parks_safe_and_escalates— seedsrearm_count = REARM_CAP-1, runs the real completion, asserts the terminal FIRES:submit_replannot called (no re-arm), type staysperiapsis_raise(not re-typed),clear_maneuvercalled once (parked safe), and arearm_cap_reachedship-log escalation surfaced. Execution assertion — clears the necessary-not-sufficient / constant-only trap.test_rearm_below_cap_still_proceeds— below cap: re-arm proceeds,rearm_countincrements 1→2 (non-resetting),replan_countresets to 0, skip-clear. The proceed↔refuse boundary is pinned (proceed at increment→2, refuse at increment→3).- No-regression: the two #1426 cells (re-arm + item-2 dock-suppression) intact.
- Ran locally at HEAD →
4 passed(PYTHONPATH=src:..:../shared:physics_core:tests pytest tests/tick_engine/test_automation.py::TestPeriapsisRaiseRearm). Matches the gist's claim.
- 3 is sensible. increment-then-check
>=3⇒ 2 re-solve re-arms proceed, the 3rd is refused → at most 3 raises before park. It cannot "abort a legitimate 2-3-phase approach" because a legitimate approach's phases are rendezvous/circularize/approach — never a sub-surface strand — so a multi-phase approach never increments this counter. Small enough to stop wasting fuel on endless oscillation, large enough to tolerate a couple of transient recoveries. - Composition with #1424/#1425/#1426. Each
periapsis_raisestill saves the ship per-cycle (#1425); the re-arm still re-solves the rendezvous per-cycle (#1426);replan_countstill resets per re-armed leg. The cap adds only a cross-cycle recurrence bound on top — no change to per-cycle behavior. - Composition with #1427. Correctly independent: once #1427's selection-time
intermediate-orbit invariant prevents the sub-surface strand,
periapsis_raiserarely fires and the cap becomes a rarely-hit backstop. #1428 is not load-bearing for the dock — it bounds the pathological case only. Framed correctly as hardening, not a dock claim.
- The
game_timefetch inside the cap branch is duplicated from the below-cap branch; both are best-effort wrapped. Cosmetic only. - None affect correctness.
- CONCUR — #1428 safety bound landed. Nothing needs Erik.
- #1427 SP1 (root-cause) proceeds separately. #1397/#1424 remain operator-gated (reviewer did not self-close). No galaxy-repo commits from reviewer.