ADR-087 — Kernel "systems" layer: separating guidance/control controllers from physics engines
Status · Accepted · 2026-08-31 · Operator-directed (Physics Lab spaceflight program) · builds on RFC-034 (ascent physics / PEG) · enables the Lab "Systems" lesson family (tasks #28–#30)
Gating sentence. The pure physics kernel (src/lib/physics/) gains a systems/ sub-layer for the guidance/control controllers a real vehicle runs — the algorithms that steer the physics, as distinct from the physics engines they steer. The first extraction moves Powered Explicit Guidance (PEG, pegSolve, pegPitchRad, timeToApoapsisS, PegState) out of ascent/ascent-physics.ts into systems/peg.ts unchanged (byte-identical logic; ascent-physics re-exports for back-compat, so every importer and all 170 ascent tests stay green). Powered-descent guidance and re-entry lift-vector steering join systems/ as new controllers in later slices.
Context
The physics kernel had grown one real closed-loop controller — PEG, the ascent insertion guidance that solves a two-point boundary problem each major cycle so a low-TWR upper stage reaches (r=rT, vr=0) at circular speed — buried inside ascent-physics.ts next to the atmosphere/gravity/thrust physics. The operator's framing of the Physics Lab spaceflight program draws a three-layer picture:
KERNEL SCIENCE (physics engines) mechanics · transfer · ephemeris · ascent/descent integrators
KERNEL SYSTEMS (controllers) PEG · powered-descent guidance · entry lift-steering
LAB INTEGRATION formulas + figures + goals that expose both, and put it togetherThe distinction is real and pedagogically load-bearing: a "Systems" lesson family teaches how a machine flies the physics (the guidance computer solving its own path in real time) — a different question from "what is the physics." To teach and black-box-simulate a controller in isolation, it must be a first-class, pure, self-contained module — not an implementation detail of an integrator.
Decision
A systems/ layer under the pure kernel. src/lib/physics/systems/*.ts holds guidance/control controllers. Same purity contract as the rest of physics/** (framework-free; only $types/*, $data/*, and intra-kernel $lib/physics/* imports). A controller is:
- Pure — a function of state → command; no trajectory integration, no side effects.
- Black-box-simulatable — callable standalone (a Lab formula can drive
pegSolveon a synthetic state to show what it commands), not only reachable through the flight integrator. - Honesty-preserving — a controller only steers; the physics engine still decides truth (PEG's steering can never fabricate an orbit —
integrateAscent's osculating-perigee gate decides SECO/reachedOrbit).
First move — PEG. systems/peg.ts receives PEG, pegSolve, pegPitchRad, timeToApoapsisS, PegState verbatim, importing only MU_EARTH_M3_S2 (its sole external dependency — no circular import with ascent-physics.ts). ascent-physics.ts imports them for integrateAscent's internal use and re-exports them, so peg-guidance.test.ts and ascent/index.ts resolve them unchanged.
Next controllers (later slices, task #30). systems/powered-descent.ts (throttle/retarget landing guidance — currently only implicit inside descent-physics.ts) and systems/entry-steering.ts (bank-angle lift-vector steering — the descent integrator models lift physics via liftToDragRatio but has no steering controller; this also reconciles the ballistic entry-corridor formula with the lift the integrator already has).
Consequences
- No behaviour change. The extraction is mechanical;
integrateAscentproduces byte-identical results (170 ascent tests green, incl.peg-guidance.test.ts). - Enables the Systems lesson family — each controller can be surfaced as a Lab formula/simulation that runs it in isolation (open-loop pitch table vs closed-loop PEG takeover; a suicide-burn solver; lift steering through the entry corridor).
- A clean seam for the "put it together" layer — mission-plan goals compose physics engines + systems controllers end-to-end.
Non-goals
- Not rewriting or re-tuning PEG — verbatim move only.
- Not moving physics helpers (gravity, circular speed, atmosphere) — those stay in the engines.
timeToApoapsisSmoves with PEG only because it is the guidance relight rule's Kepler helper and travels with the controller its callers import together.