Decisions and the roadmap
This page is the way into the project’s three records: the decision log, the roadmap and the
lessons from Loft. They are files in the repository, not pages of this site, because they are
written as the work happens. Every label you meet on the other pages, such as a decision record
(ADR- and a number), a milestone (M and a number) or a Loft lesson, links into one of them. For
how hpr behaves today, trust the model pages; the records say why it behaves that way and what
comes next.
Decision records
A decision record, or ADR (architecture decision record), explains one significant choice: the
problem, the options that were considered, what was chosen and why, and what it costs. Records
are numbered in order and never renumbered. A record is not rewritten when a choice changes; a
new record replaces it and points back. Each record is a file of its own; the decision log
is their index, one row per record with its summary and status. The table below gives each one in
a line and is kept by a command (cargo xtask records), so a new record appears here as soon as
it is written. From the 126th record on, a row shows the record’s own summary, which is more technical,
until someone rewrites it in plainer words.
| record | what it decides | where it shows |
|---|---|---|
| ADR-000: Kickoff decisions | A Rust library first; physics and validation before interfaces; the license; a clean room (no GPL source is read); commercial solid motors only | Start here |
| ADR-001: License and workspace layout | MIT OR Apache-2.0, and how the code is split into crates | Start here |
| ADR-002: The reference library | How published sources and reference programs are pinned by hash, fetched and checked | Checking a claim |
| ADR-003: Frames, attitude, geodesy and gravity | The axes and sign conventions, WGS 84 gravity, and the Earth’s rotation | Frames, Gravity |
| ADR-004: Atmosphere, wind and turbulence | The standard atmosphere, wind by height above sea level, and seeded turbulence | Atmosphere, Wind, Turbulence |
| ADR-005: Solid motors | How a thrust curve becomes impulse, mass and inertia over the burn, and which curves are bundled | Solid motors |
| ADR-006: Component geometry and mass properties | How each part’s shape, walls, fins and material give its mass, center of gravity and inertia | Mass properties, Shapes |
| ADR-007: The design tree | Where parts sit, automatic sizes, overrides, motor mounts and design checks | Design tree |
| ADR-008: Subsonic normal force and centre of pressure | The body and fin lift models behind the center of pressure | Aerodynamics |
| ADR-009: Subsonic drag | The drag buildup, surface finishes and drag tables that override it | Aerodynamics |
| ADR-010: Time integration | The adaptive integrator, and how events such as burnout and apogee are found | Time integration |
| ADR-011: Rigid-body flight | The equations of motion, the launch rail, the phases of a flight and when it stops | Rigid-body flight |
| ADR-012: Recovery | Parachute drag areas, when devices open, how they fill, and the descent | Recovery |
| ADR-013: Streamer and tumble drag | Which published data sets give a streamer’s and a tumbling body’s drag | Recovery |
| ADR-014: Separation | How a rocket splits into bodies that each descend on their own | Recovery |
| ADR-015: The validation harness | How comparisons with other programs are run, gated and reported | Accuracy, Checking a claim |
| ADR-016: The documentation site | This site: how it is built, and the checks every page passes | Start here |
| ADR-017: In short, traced numbers and this page | How every model page opens, how Accuracy’s numbers are checked against their sources, and why these records are files rather than pages | Accuracy |
| ADR-018: Examples and quotes | Every example program runs in CI and must print its committed output, and a page’s quote of a file must match it line for line | Getting started |
| ADR-019: Publishing the site | How this site and the API reference are built together, link each other, and are published from main | The API reference |
| ADR-020: The reader test | How the site was tested on a new reader, and why every milestone and lesson label links a row of plain words on this page | Decisions and the roadmap |
| ADR-021: Whole flights against RocketPy | What a whole-flight comparison measures and how, why a sixth rocket was added, and how a case declares a limit of hpr’s as a known gap | Accuracy |
| ADR-022: Validation in CI, and regenerating references only by hand | How every pull request reruns the validation cases on three operating systems, and why the references change only when a person regenerates them and reviews the diff | Checking a claim |
| ADR-023: Predicted mode | How hpr’s own aerodynamics are compared with RocketPy flying each example’s own drag, and why those results are reported against a target rather than gated | Accuracy |
| ADR-024: The time-series RMS | How each whole flight’s height and speed over time are compared with RocketPy’s, on what clock, and why each is held to 3% of its apogee or max speed | Accuracy |
| ADR-025: The calm-air cases | Juno III, Calisto and Bella Lui flown with no wind, and why Juno III’s drifts were at first reported but not scored: the two codes free the rocket from the rail at different points | Accuracy |
| ADR-026: The path in wind | Why hpr turned into the wind less than RocketPy: RocketPy’s equations took the turning moments about the wrong point during the burn (corrected upstream, and in the comparison), and hpr’s body lift, which RocketPy leaves out, pushes a slow rocket downwind | Accuracy |
| ADR-027: The normal force through Mach 1 | How the fins’ normal force and center of pressure carry through Mach 1: Barrowman’s subsonic method to Mach 0.8, supersonic linear theory once it holds, a straight-line join between, and how they compare with a wind tunnel and with RASAero II | Aerodynamics |
| ADR-028: Drag through Mach 1 | How noses, shoulders and steps drag through Mach 1: Niskanen’s method with Stoney’s measured nose curves, and how the drag compares with NASA’s wind tunnel | Aerodynamics |
| ADR-029: Drag against RASAero II through Mach 2 | How hpr’s drag compares with RASAero II’s curves by speed band, why it misses faster than sound, and a second reference with every input known: MIL-HDBK-762’s worked example | Aerodynamics |
| ADR-030: The afterbody faster than sound | A boattail’s supersonic wave drag from MIL-HDBK-762’s chart held to the Prandtl–Meyer limit, separation on steep boattails, the base pressure behind them, and a lip in a boattail’s wake; checked against measured boattails, and why its targets aren’t met | Aerodynamics |
| ADR-031: Roll from canted fins | Roll forcing from canted fins and roll damping by Barrowman’s strip theory with his body factors, the fin’s own slope in the damping, and the comparison with NASA’s measured roll effectiveness and the Basic Finner’s roll damping | Aerodynamics |
| ADR-032: Normal-force overrides | Flying RASAero II’s normal force and center of pressure: how its export is read, the slope at 0°, the angles past its last, and why the damping stays hpr’s | Aerodynamics |
| ADR-033: The body faster than sound | The lift a body’s cylinder carries behind its nose faster than sound, by the second-order shock-expansion method: the report’s tangent body, its limit, and the cone slopes read by hand | Aerodynamics |
| ADR-034: The body’s supersonic normal force in flight | How a flight uses that method: a table of each part’s share every 0.05 in Mach, joined in a straight line from slender-body theory over Mach 1.2 to 1.5 | Aerodynamics |
| ADR-035: Drop the orhelper dependency | The GPL-2.0 wrapper for the OpenRocket jar is removed from the oracle environment, unused; how the OpenRocket oracle milestone drives the jar is decided when it starts | How correctness is proven |
| ADR-036: The Arcas Robin’s supersonic body gap | How hpr’s body faster than sound is compared with NASA’s wind tunnel from now on (as the tunnel measures, at its angles), and why M1.8e6 takes the size of crossflow lift and the boattail’s share together | Aerodynamics |
| ADR-037: Body lift by Jorgensen’s crossflow | Body lift’s size at every speed from Jorgensen’s crossflow drag, how his two η figures are combined, a boattail’s share faster than sound from Washington and Pettis’s measurements, and why blunt tips moved to M1.8e7 | Aerodynamics |
| ADR-038: Blunt tips by a Newtonian cap | How a nose with a blunt or vertical tip (power-series, Haack, elliptical) flies the shock-expansion method faster than sound: NASA TN D-4865’s Newtonian cap and handover, the method started behind it from the tangent cone rather than the report’s own start, and how both were checked | Aerodynamics |
| ADR-039: A lip in a boattail’s wake carries nothing | Why a short flare at the very base, behind a boattail, gets no normal force faster than sound, what the tunnel’s pitching moment says about that, and how far the shelter reaches | Aerodynamics |
| ADR-040: A steep boattail’s correlation, and the 15% target judged | How steep a boattail hpr still reads its measured share for, how footnote 8 and the tube behind it were integrated by hand, and where the Arcas Robin’s body alone still misses its 15% target | Aerodynamics |
| ADR-041: A lip’s shelter weighed, not switched | Why a lip rising out of its boattail’s wake now moves a rocket between the two supersonic body models smoothly, and how big the switches that remain are | Aerodynamics |
| ADR-042: Cone slopes past Fig. 2’s edge, from Sims | Where the slopes for tangent cones of 24° to 30° come from, how they were checked against the chart they extend, and what a cone steeper than 30° still costs | Aerodynamics |
| ADR-043: The blunt tip’s handover cap | What moving a blunt tip’s handover from 24° to the cone tables’ 30° would be worth on the report’s own sphere-cone, what it does to the march on a nose that flattens fast, and why the cap stays where it is | Aerodynamics |
| ADR-044: What the answer follows when it follows the mesh | That it is the surface pressure crossing its tangent cone’s, not the method being reduced, that marks a reading whose answer moves with the element count: how far that goes, and what it re-aims issue #108 at | Aerodynamics |
| ADR-045: Where a flare’s march stops | That what stops the march is the corner’s isentropic turn, not the flare’s shock detaching; that the two limits cross near Mach 1.55, so neither bounds the other; and that above Mach 2.13 neither binds: the cone tables’ 30° does | Aerodynamics |
| ADR-046: Debrief folded in, and analysis that stands on its own | That a universal flight log analyzer becomes part of this project, and that reading a log never needs the simulator: hpr-flightdata may not depend on hpr-sim, a check enforces it, and comparing a flight with a simulation lives in hpr-forensics | Start here What the analyzer is being built from is written up in the log formats, the readings and what may be ported. |
| ADR-047: A flare flies the method where its corner’s shock is attached | That a flared body now flies the shock-expansion method; that the test for the corner’s shock is NACA 1135’s wedge limit read at the flow reaching it, the same one a blunt tip’s cap already uses; that a steeper flare is read as one of the same radii drawn out to that limit, so nothing jumps across the boundary; and what still switches: a band of flares a third of a millimeter tall the march refuses (read through since ADR-050) | Aerodynamics |
| ADR-048: What a marched flare is worth | That TN D-4865 model 2’s readings are committed and compared: an 18.5° flare read −1.9% and +7.0% against the wind tunnel at Mach 1.9 and 2.3, +13.4% at 2.96 and about +51% at 3.95 and 4.63, whose flare the report’s shadowgraphs show separated; with no reading at all below Mach 1.5289, where drawing the flare out to its shock’s limit lands past the march’s own | Aerodynamics |
| ADR-049: What a step in radius costs | That a step’s cost is measured and published rather than modeled: it takes the whole body off the shock-expansion method, worth −8.65% and 1.03 calibres at its threshold and −12.55% and 1.36 calibres at a 2 mm step down, and −11.34% and 1.10 calibres on a boattailed body, whose threshold is 1.3e−13 m rather than 2.7e−11 m; and that stopping the march at the step instead was built, measured and rejected, because the mixed reading lands outside both pure models and misses the boattail’s band | Aerodynamics |
| ADR-050: A reduced element read by the generalized method | That where the second-order method’s exponential form cannot hold (the pressure behind a corner on the far side of its tangent cone’s from where its own gradient points), the element is read by the generalized method wherever it has a tangent cone of its own, so a near-flat flare no longer takes the whole body off the method; that the region’s two edges are solved from the corner’s own state rather than bisected, reproducing all three published angles; and that what is left is the loading’s step at the crossing, +0.129% and 0.0051 calibres on the tests’ rocket but not bounded by it: +4.3% and 0.19 calibres on a body with a short shoulder, and −2.8% between two adjacent Mach rows | Aerodynamics |
ADR-051: M3.1 split, and a .ork document kept whole | That reading an OpenRocket file is split into four increments, the container and the document first; that the document is read into a tree and interpreted by nobody, because with no schema for .ork keeping the whole file is the only way to be sure nothing was dropped; that reading it, writing it and reading it again gives the same document, checked over generated trees and over all 76 corpus files that open; that nesting is counted before the text is parsed, since the XML parser underneath overflows the stack past 120 levels; and that the corpus survey names the two files that are not XML rather than skipping them quietly | OpenRocket .ork design files |
ADR-052: What a .ork value means | That an automatic dimension keeps both its flag and the number OpenRocket last worked out, rather than becoming a hand-typed one; that either name may be read of the two renames that are only renames, because where OpenRocket writes both it agrees with itself on the number and on the frame every time (642 and 109 elements), while two more pairs that look the same are left unread, their newer name carrying a frame the older never does; that a stated zero is a value, which is what an override to no drag at all needs; and that the single flag the three subcomponent-override flags replaced is read as setting all three, out loud, since no file carries both forms (the warning since dropped by ADR-095, which measured OpenRocket’s reading) | .ork design files |
ADR-053: The parts on and inside a .ork body | That .ork angles are degrees, which nothing in the file says and 178 of its 188 non-zero ones show by exceeding a whole turn; that radialposition and radiusoffset are each read on the parts that carry them, which no element carries both of, so the question ADR-052 left open need not be answered to read them; that a part this reader cannot shape honestly is left out with its reason rather than guessed at (5 in the corpus); that a tube of no wall carries no mass, which is OpenRocket’s own geometry, where a body component’s ambiguous zero is read as solid; that an inner tube’s automatic outer radius is its parent’s bore, resolved in a pass before any ring’s bore so no answer depends on sibling order; and that the five surface-finish words take the roughness heights OpenRocket’s author published, with polished flagged as possibly moved in a newer OpenRocket (the zero-wall reading was replaced by ADR-061: every part of no wall weighs nothing) | .ork design files |
| ADR-054: An automatic radius with nothing to take | That an automatic body radius with no fixed radius anywhere along its chain takes OpenRocket’s default radius, 25 mm, which OpenRocket’s maintainers call “the default radius” and OpenRocket 24.12 settles on in a committed oracle run, never the number cached after auto, which OpenRocket itself ignores; that hpr departs from OpenRocket only where OpenRocket answers −1 m, a radius no shape can have; that hpr is held to OpenRocket’s settled answer rather than its first reading, which settles the Dual parachute example’s odd cache in hpr’s favour (67 of 67 body radii agree over 18 designs); and that a <rocket> holding nothing is a document with no design rather than a design that fails | .ork design files |
ADR-055: M3.1c split, and the motors a .ork flies | That reading a .ork file’s motors, recovery, stored results and pods is split into four increments. That a motor’s thrust curve comes from the file first and hpr’s bundled catalog second, matched on manufacturer and designation both. That none is a plugged motor and 0 a charge at burnout. And that the rocket flies a configuration only when every motor in it has a curve and lights at launch, on a one-stage rocket read without a warning, because hpr lights every motor at launch and flies one body until staging arrives: 2 of the library’s 170 configurations do | .ork design files |
ADR-056: A .ork design’s recovery and separation | That when each parachute and streamer opens, and when each stage separates, is read as the file wrote it and not yet flown. That the words are OpenRocket’s own, measured by a committed probe. That a deploy height is above the ground. And that two choices are left open, in plain view, for the step that flies a .ork: a deploy height the rocket never reaches, which OpenRocket never opens, and an automatic drag coefficient | .ork design files |
ADR-057: A .ork design’s stored simulations | That the simulations OpenRocket last ran on a design are read back as it wrote them: the launch conditions, the summary, and each stage’s time series and events. That their units are measured by a committed probe: the rod’s angle and direction in degrees, a compass bearing; the wind’s direction in radians, where it blows from. And that they are OpenRocket’s answers to compare against, not flights hpr makes | .ork design files |
ADR-058: What a .ork holds that hpr does not model | That the parts and sections of a .ork hpr does not read (pods, parallel stages, OpenRocket’s 3D-view settings, a simulation’s plug-ins) are kept whole beside the design, in an extension called x-openrocket, at a path that leads back to where each was, so that writing the file back can put them back; that a design missing parts this way says it is reduced; and that the same goes for every tag and attribute no reader asks for, recorded as hpr reads | .ork design files |
| ADR-059: The RocketSerializer cross-check | That hpr’s reading of a design’s key geometry (the nose cone, transitions, fin sets, where each sits, and the body radius) is held to RocketSerializer’s, a second program that reads .ork files, with OpenRocket itself run on the same file to settle any difference; that “agrees” means no number of hpr’s is apart from both; that a cause is named only where the record proves it; and that an import error is a file that does not read or a design that does not lay out | .ork design files |
| ADR-060: M2.2 split, and the structure’s mass held to OpenRocket’s | The OpenRocket comparison goes mass first, then OpenRocket’s mass conventions, the motors OpenRocket flies, flights on public designs, and the corpus. Each design’s structure is held to OpenRocket’s within 1% in mass and 1% of length in center of mass, thresholds set before measuring, and every design outside is given its cause. Which of OpenRocket’s inertias is roll is measured on a tube worked out by hand | Mass properties |
ADR-061: What a .ork leaves unsaid, read as OpenRocket reads it | Probe designs measure what OpenRocket makes of a wall or shoulder of no thickness (nothing), a part with no thickness written (a 2 mm wall) or no material (its default by kind), and which override wins. hpr reads each the same way. Two override rules stay hpr’s own, each pinned by a test: the center under a mass override that covers the parts inside, and inertia under an override | Mass properties |
| ADR-062: Fins and rail buttons against OpenRocket; roll inertia explained | Probes of one tube and one part find the fins behind the roll inertia’s gap: OpenRocket’s shortcut for a fin set, inferred from its output, accounts for the corpus’s 2.1%, and hpr keeps its exact integral. hpr keeps its rounded and airfoil sections and its exact ellipse, each pinned against OpenRocket’s; a .ork rail button now sits where OpenRocket puts it (issue #151). M2.2b2, the fins and rail buttons, split their remaining clusters, fillets and unread parts into M2.2b4 | Mass properties |
| ADR-063: Packed parts read and weighed as OpenRocket packs them | A parachute, streamer, shock cord or mass component whose file writes no packed size is 25 mm long and 12.5 mm in radius, as OpenRocket packs it, and a mass override on one that weighs nothing is spread over its packing, not put at a point; both measured on probe designs | Mass properties |
| ADR-064: Clusters, fillets and unread parts remain visible departures | A 3-ring cluster is read as one tube and pinned as a measured departure (superseded for clusters by ADR-075); 5 mm and 10 mm fin fillets are omitted and pinned (superseded for fillets by ADR-096); unread parts remain in x-openrocket and mark the design reduced. The 2026-09-23 scratch-excluding corpus rerun gives 58 of 71 within 1% in mass, 59 in center, 50 in pitch inertia and 56 in roll with OpenRocket’s fin rule | Mass properties |
| ADR-065: Stored results are references only when current and structurally plausible | Stored results remain readable, but only current runs with RK4Simulator and BarrowmanCalculator provenance markers and complete finite, internally consistent ascent summaries pass the stored-reference screen; the 2026-09-25 survey found 91 of 174 eligible and 83 excluded (47 inconsistent, 17 external, 11 outdated, 7 not-simulated and 1 missing simulator). Hpr reproduction is separate: 1 of those 91 is reproducible and 90 are not (40 reproducible once ADR-067 supplies OpenRocket’s motor database). | .ork stored simulations |
| ADR-066: Every curve hpr flies is integrated as OpenRocket integrates it | The oracle hands OpenRocket the same bytes hpr reads, so the comparison is of two integrations of one file: hpr’s total impulse, peak thrust, 5% burn-time window and curve duration are all bit for bit OpenRocket 24.12’s on all 32 bundled curves. The one real difference is the average thrust, hpr’s being +0.0107% to +0.3147% higher because its numerator is the whole curve’s impulse where OpenRocket’s is the window’s: a written departure, not held. The reference library’s own curves stay private, counted in M2.2c2. | Solid motors: validation |
| ADR-067: Curves come from OpenRocket’s own database by digest, each held to its impulse | Most designs name their motor’s curve by its digest and do not carry it. An oracle records the motor database OpenRocket 24.12 ships, and cargo xtask ork supplies each solid curve for its digest, never by name. Every curve’s total impulse is within 0.1% of OpenRocket’s, and bit for bit: the 3 the library embeds are two independent readings, and the 1,288 database curves check the hand-off. In all 67 configurations hpr flies with a supplied curve, OpenRocket places each supplied curve too. Of the 162 configurations the bundled catalog left without a curve, 66 now fly, 72 are held back for another named reason and 24 still have none, each with its reason. Where each motor’s weight sits still differs from OpenRocket’s. | The .ork format: motors |
| ADR-068: OpenRocket’s flights of the public designs, and what its metric words mean | M2.2d, flights against OpenRocket, splits in two. OpenRocket 24.12 flies the public designs in calm air: 56 complete flights and one aborted run, which is no reference. A record keeps each summary word beside the quantities of its own time series: nine of ten words are defined, among them the deployment speed as the last deployment’s; the optimum delay is not measured and is withheld, as are other versions’ words (L80). A metric whose event is missing is never scored: withheld when neither flight had the event, failed when only one did (L81). | .ork: what the summary words mean |
| ADR-069: hpr’s flights of the public designs against OpenRocket’s | M2.2d2: cargo xtask ork-flights flies the 21 configurations of OpenRocket’s examples that hpr can fly, in OpenRocket’s recorded conditions, and a committed report sets each against OpenRocket’s apogee, largest speed and margin at rod clearance, by ADR-068’s definitions. The margins are within 0.016 calibres. With no named cause, hpr’s apogees are 0.06% to 4.34% low. Each apogee more than 5% off has a named cause: a parachute OpenRocket opened before apogee (hpr flies none from a .ork yet), or a part set to no drag, which hpr ignores (#165). | .ork: hpr’s flights against OpenRocket’s |
| ADR-070: M2.2e split: mass and centre of mass first, then the corpus | M2.2e is cut into four: M2.2e1 adds the spread of hpr’s mass and center of mass against OpenRocket’s to the flight report; then OpenRocket flies the private designs (the corpus), hpr flies them, and each apogee more than 5% off gets a written cause. On the 21 public flights the launch mass is within 0.21% and the center of mass within 0.016 calibres. | .ork: hpr’s flights against OpenRocket’s |
ADR-071: The corpus OpenRocket flies is its .ork files | M2.2e2 flies the private library’s 27 .ork files: 88 of 89 configurations to the end. Its 4 RASAero and 4 RockSim files wait until hpr reads those formats. | .ork: OpenRocket’s flights of the private designs |
| ADR-072: hpr’s flights of the private library, under anonymised ids | M2.2e3 tries the 12 private designs that are not copies of public ones and publishes only differences, under ids like C09/2. hpr flies 17 configurations of 4 of them, so the two reports hold 9 designs, not the 20 that M2.2 (the OpenRocket comparison) asks for. That bar is now M2.2e9 (ADR-094 split the tilted rod off as M2.2e5, which added one design, and ADR-095 the old override flag as M2.2e6, another). The rest can come from the staging and cluster designs (M1.9), the airframe readings (#174, two designs left), or the four public designs held by pods and parallel stages (OpenRocket’s pod examples, unflown for reasons outside the pods though M1.13 is done) or tube fins (#133). | .ork: hpr’s flights of the private designs |
| ADR-073: Each named cause sized by OpenRocket’s own flight without it | M2.2e4 sizes the two causes named for the five apogees more than 5% from OpenRocket’s: OpenRocket flies each flight again with nothing deployed and, where a part is told it has no drag, with that setting cleared (matching what hpr flies, since hpr reads the setting but can’t apply it yet) or the part removed. Four of the five come within 5% of every such flight. The fifth stays 7.80% high like for like (the no-drag part removed from both programs), and what is left on its design has a lead, not an explanation (#177, a very blunt nose’s drag). | .ork: the two named causes, and their size |
| ADR-074: Ignition times and powered staging: the sustainer flies on as a rigid body | M1.9a lets each motor light at its own time (at launch, at a time, after another motor’s burnout, or after its stage’s separation). A separation with the forward part still to burn is powered: that part, the sustainer, flies on with its own shape and mass while the booster falls to its own landing. The sustainer keeps the nose, so its aerodynamics are an ordinary rocket’s; nothing needs a model of a rocket without a nose. Checked by tests, not yet against another simulator. | Staging |
| ADR-075: A cluster is one tube repeated, and a motor in it one motor per tube | M1.9b makes a cluster a list of tube places on one inner tube: the tube and what it holds are repeated in each, and its motor is one motor per tube, so thrust, mass and moments add up as for any motors. A tube can be marked as a motor out. A .ork file’s pattern is read as OpenRocket places it, measured on 25 probes; OpenRocket weighs the tubes stacked on the cluster’s axis, which hpr does not copy. | Clusters |
ADR-076: A .ork file’s ignitions and one powered separation flown against OpenRocket | M1.9c reads each motor’s ignition in a .ork file into hpr’s (at launch, at a time, or after the stage below burns out or fires its charge) and flies one powered separation, a cluster with a motor in every tube, and an air start. The tolerance, set before measuring: every flight of a design within 5% of OpenRocket’s apogee and largest speed. OpenRocket’s two-stage, cluster and air-start examples all are (three cluster apogees against OpenRocket’s flight with no parachute, because its parachute opened before apogee) | Staging |
| ADR-077: Flight metrics: peaks on the dense output, margins only where they mean something | M1.10a finds each peak (speed, Mach number, dynamic pressure, the boost’s acceleration and, apart, the opening shock) between the integrator’s steps rather than in a recorded table. It keeps the static margin and the margin at the flight’s Mach number from the rail exit to apogee, and gives none where the parts’ normal-force slopes nearly cancel, since the margin is then noise. The optimum delay comes from a flight with the charges held, so it doesn’t depend on the delay flown. Anything that didn’t happen is None. Tests pin each against a hand calculation; nothing is checked against a real flight. | Flight metrics |
| ADR-078: Fin flutter by NACA TN 4197, the lower reading wherever the source leaves room | M1.10b gives a fin’s flutter speed and margin by Martin’s 1958 criterion, which reproduces both of his worked examples at the precision he printed them. It fixes a flutter dynamic pressure, so a flight’s least margin is at its max q. Martin’s own line between safe and failed wings, a band measured off his figure 3, puts the flutter speed at 1.8 to 2 times the speed of sound, so a flutter speed just above the flight’s speed is not shown to be safe. Where the source allows two readings (the thickness ratio, a flat fin’s stiffness), hpr takes the one with the lower flutter speed. 14 built-in materials carry a shear modulus from a cited source; G10/FR-4 has none. Nothing is checked against a hobby rocket’s flight. | Fin flutter |
| ADR-079: Exports as text built in the core, heights on each format’s own datum | M1.10c1 writes a recording as CSV or JSON, and the flight path and landings as GeoJSON or KML. Each function returns text and writes no file. Numbers are written so they read back exactly; a value that isn’t finite is refused. GeoJSON heights are above the WGS 84 ellipsoid and KML heights above sea level, as their standards say. GeoJSON is checked against the published schema and KML by parsing. Parquet is split off to M1.10c2. | Exporting a flight |
| ADR-080: Parquet written in-house, read back by Apache’s library | M1.10c2 writes a recording as an Apache Parquet file, behind the parquet cargo feature. hpr-sim writes it from the format’s specification, with no added library, and the tests read it back with Apache’s own Parquet library, every number bit for bit. The file is uncompressed and has no per-page statistics; pyarrow and DuckDB read it once, by hand, not in CI. | Exporting a flight |
ADR-081: ERA5 weather read from netCDF classic in hpr-io; M2.3 split a to c | M2.3a reads the weather over a launch site from an ERA5 file. hpr reads netCDF classic files itself, from Unidata’s specification; the newer netCDF-4 files are converted first with three lines of Python. Values are interpolated between the four grid points around the site as RocketPy does, and between the two hours around the launch, where RocketPy takes the nearer hour. Heights use the World Meteorological Organization’s formula at the site’s latitude, where RocketPy uses ECMWF’s; both are approximations, and the page compares them. Real flights in that weather are M2.3b, and the private designs with flight logs M2.3c. | ERA5 weather files |
| ADR-082: Real flights read from refs, compared over the ascent, with checked explanations | M2.3b flies seven of RocketPy’s documented rockets in the weather of their day, with hpr’s own aerodynamics and each example’s own motor file, and compares each with its team’s altitude log: the apogee, and the climb to it. hpr’s height is read the way the log’s barometric altimeter reads the air, which on a hot day is several per cent below the height climbed. The logs and motor files are other people’s, so they are read from a pinned copy and only the numbers are committed. The mean absolute apogee error is reported against a 5% target; each flight outside it carries an explanation that the report checks against its own numbers: a second flight on the team’s own drag, or on the thrust file as recorded. | Accuracy: real flights |
| ADR-083: M2.3c blocked: no private design is the rocket of a logged flight | M2.3c was to fly the private designs that have a flight log. None does: the private logs match no design in the private library, and the only designs there with a logged rocket are copies of RocketPy’s public examples, whose logs are RocketPy’s and were already flown in M2.3b. One design shares a source with some logs, but nothing ties it to any of those flights, and a comparison against a guessed pair would measure nothing. So it waits for a design and its flight’s log to be added to the private data, and work moves on to M2.4. | Accuracy: real flights |
| ADR-084: The accuracy census: the reports’ numbers held to the ones accepted | M2.4 counts the numbers the validation reports hold hpr to, once each, naming for each group what it was compared with, the kind of comparison, how many flights and how fast they flew. The census accepted last is committed, and CI holds each of those numbers to it: one that moves by more than 0.1% of its bar, better or worse, fails until the change is accepted with a written reason. That catches what a regenerated report could otherwise carry in, such as hpr’s own drag getting worse inside a target. | Accuracy: the census |
| ADR-085: Ejected pieces: an airframe that parts at any joint | M1.11a lets the airframe part anywhere: at the joint aft of any body component, as a nose cone pushed off does, or around a payload carried inside. Each piece flies on to its own landing under its own parachute. The pieces are fixed before the flight, so a body’s number never depends on which trigger fires first, and the nose’s body is always body 0. Each parting adds no impulse, so masses and momenta add up. An override that doesn’t say how its mass divides between pieces is refused rather than guessed. The push of an ejection charge, and a tumbling piece, are M1.11b (ADR-086). | Recovery: ejected pieces |
| ADR-086: Ejection impulse and tumbling pieces | M1.11b lets an ejection push its two sides apart with an impulse, equal and opposite, so each changes velocity by the impulse over its own mass and the momentum is unchanged. While the airframe flies whole with nothing open the push is along its axis. A body with no attitude to go by is assumed to point against its velocity through the air when it hangs from an open parachute, and along it when nothing is open. A piece can tumble by the tumble model over its own parts, and that model now integrates a curved nose’s side area rather than taking its end diameters. | Recovery: ejected pieces |
| ADR-087: Mass that moves along the airframe | M1.12a lets ballast or a payload slide along the airframe during the flight, on the triggers a parachute has, along a smooth curve that starts and ends at rest. The rocket’s center of mass and inertia follow it exactly. The equations of motion gain one term, the moving part’s angular momentum relative to the airframe, which is zero for a part on the axis; its rates are exact rather than differenced. A mass released in flight is M1.12b. | Moving mass |
| ADR-088: Mass released in flight | M1.12b lets ballast or a payload go during the flight, on the triggers a parachute has. The rest of the rocket flies on in six degrees of freedom from the same state with its mass, center of mass and inertia stepped to the rest’s; the part leaves with the velocity it had in the airframe, so mass and momentum are kept, and falls to the ground as a point mass under a drag area the user gives. | Released mass |
| ADR-089: A pod is a stack of body components repeated around the axis (superseded for aerodynamics and tumbling by ADR-092) | M1.13a adds pods: a pod set on a body tube holds the pod’s own body components, which stack along the pod, and hpr repeats that one pod, with everything in it, evenly around the axis, each copy turned with its pod as a fin set’s fins are. Each copy is weighed where it sits, with its parallel-axis term, and a motor in a pod is one motor per pod. The aerodynamics and the tumble model refuse pods until a cited method for their normal force and drag is in (M1.13c). | Pods |
ADR-090: .ork pods placed as OpenRocket places them; pods of no length left out | M1.13b1 reads a pod set’s pods and puts them where OpenRocket 24.12 does, measured on probes: a relative offset is from the tube’s surface to the pod’s widest part. A flipped nose cone is read as the tail cone it is. Pods of no length, drawn to hang fins off the axis, were left out with a warning until M1.13b2 read them (ADR-091). | .ork: Pods |
| ADR-091: A pod of no length weighs nothing and holds its parts on its axis | M1.13b2 reads the pods OpenRocket draws to hang winglets or a lug off the axis: a pod whose only part is a tube of no length, no wall and usually no radius. That tube weighs nothing, and fins or a lug on it sit on the pod’s own axis, as OpenRocket 24.12 places them on probes. A pod set that holds nothing is read, and weighs nothing. | .ork: Pods, Pods |
| ADR-092: A pod’s parts are Barrowman’s, once per pod, on the axis | M1.13c1 flies pods: each pod’s nose cones, transitions and tubes get the normal force and drag they would have on the airframe, at the pod’s own fineness, and each pod’s fins are its own, turned with it; every pod adds its share. The forces act on the rocket’s axis, exact for two pods or more to first order, and the roll damping the pods’ offsets give is added. How the pods and the body disturb each other’s flow is left out, with its size stated, and a single pod’s off-axis moments are left to issue #213. | Pods |
| ADR-093: Pod probes flown as the public designs are, and listed apart | M1.13c2 checks pods against OpenRocket on six probe designs, one airframe carrying pods of bodies, fins, tail cones, winglets or motors, or none, flown as the public designs are and listed apart from them. Each is within 5% of OpenRocket’s apogee and largest speed, and what the pods change is held too, since a straight-up flight tests drag more than normal force. The close agreement shows the two codes apply the same rules; it cannot size the interference both leave out. | Pods |
| ADR-094: A tilted launch rod flown as OpenRocket records it | M2.2e5 flies a tilted rod as OpenRocket records it: hpr’s rail takes the same compass bearing and an elevation of 90 degrees minus the tilt. Four public probes check it: the bearing at apogee agrees within 0.03 degrees and the apogee the tilt takes off within 0.27 percentage points. OpenRocket’s rocket clears a tilted rod at a small angle of attack, which on the probes and on the one private design explains most of a margin gap that grows with the tilt. | The .ork format: a tilted launch rod |
| ADR-095: The single pre-1.9 override flag read as OpenRocket reads it | Older .ork files use one flag to say a part’s overrides cover the parts inside it. M2.2e6 reads it as OpenRocket 24.12 does: as all three per-quantity flags, the later tag winning where a file writes both. Eleven probe designs measured it, and a test holds hpr to them. One private design now flies, within 0.26% of OpenRocket’s apogee. The other the flag was blamed for does not: it also has a stage separation hpr can’t fly yet (#184), so that part of the bar is recorded as not met. | The .ork format: the values inside the tags |
| ADR-096: Fin fillets and an automatic radius inside a nose cone read as OpenRocket reads them | M2.2e7 weighs a fin fillet as a prism of its section along the root chord, one each side of every fin, in its own material or OpenRocket’s cardboard. An automatic outer radius inside a hollow nose cone or transition is the bore at the part’s narrower end; an innertube written auto keeps OpenRocket’s 9.5 mm, as OpenRocket does, with no warning. 21 new probes measure it. On 9 fillet probes (7 new), the fillets’ mass and center of mass are OpenRocket’s to 1e-15, the whole probe’s pitch inertia up to 0.64% apart. On 14 bore probes, 13 of which hpr flies, every part inside but one packed mass component (#186) is at OpenRocket’s mass to 1e-14 and station to 1e-15; a coupler at a nose’s tip is refused. Two private designs now fly, 18 designs compared across both reports, of the 20 M2.2e9 needs | Mass properties: fin fillets, the .ork format: inside a nose cone |
| ADR-097: A cause in the drag sized by hpr flying OpenRocket’s drag | The first supersonic flight in the OpenRocket reports climbs 13.60% higher in hpr. An oracle records OpenRocket’s drag coefficient along its flight, and hpr flies it: +1.11%, so the cause is the drag. OpenRocket keeps the whole base’s drag under power, measured on its own examples, which hpr can now fly for comparisons; hpr’s supersonic pressure drag is about twice OpenRocket’s. Which of each is right is open (#222: supersonic pressure drag and base drag under power) | The .ork format: a supersonic flight, Aerodynamics: drag |
| ADR-098: A tube fin set’s automatic radius read as OpenRocket reads it | M2.2e8 reads a .ork tube fin set whose radius OpenRocket works out from the body. For three tubes or more, the radius is the one at which each tube touches the body and its neighbours; for one or two, it is the body’s radius. OpenRocket 24.12 gives the same radius, within 1e-15, on 19 probe designs. More than 8 tubes are read as 8, as OpenRocket reads them. Both inertias are departures, kept on purpose: OpenRocket’s roll inertia is larger than any mass inside the ring could have, and its pitch inertia leaves out how far the tubes sit from the axis; hpr keeps its own. A design with tube fins is weighed, and its configurations are left out of flight. The tube fin example still does not fly: that waits on an aerodynamic method for tube fins, now M2.2e9 | |
| ADR-099: Tube fins flown as ring wings | M2.2e9 flies each tube of a tube fin set as a ring wing: Weissinger’s slope, within 3% of five rings NACA measured, Fletcher’s measured aerodynamic center, joined to the leading edge by hpr’s own slender-body derivation (his longest ring, A = 1/3, left out, a judgement); and friction inside and out with a square edge’s drag on the wall, below Mach 0.8 and for three tubes or more. OpenRocket’s tube fin example flies: its apogee is 6.95% above OpenRocket’s, and within 0.03% on OpenRocket’s own drag, so the net gap is hpr’s drag. OpenRocket’s tube-fin drag was refined against measured flights, so hpr’s probably reads low (#228). Its margin is 1.08 calibres below OpenRocket’s; a first look, since kept as a record by ADR-102, put OpenRocket’s tube-fin slope at 1.62 times the long-ring limit of six isolated rings (1.65 times hpr’s) | |
| ADR-100: A motor whose ignition never comes flown unlit | M2.2e10 flies a .ork motor set never, or lit at an event that never comes (burnout or ejectioncharge in the bottom stage, or a plugged motor’s charge), unlit and loaded, as OpenRocket does on five probes of its two-stage example; a separation at such a motor’s burnout or charge never comes. One more private design flies, 0.88% above OpenRocket in apogee, which makes the 20 designs M2.2 asks for. It corrects ADR-076’s reading of one private record | |
| ADR-101: OpenRocket’s mass conventions rolled up | M2.2b closes: each mass convention OpenRocket was found to follow is hpr’s rule or a departure pinned by a test. The corpus survey, run again on 71 files (51 distinct by content), has mass and center of mass within 1% on 68, pitch inertia on 56 and roll inertia on 57 with OpenRocket’s fin shortcut; each file outside in mass, center or roll has a named cause (mass page). The comparison as a whole stays open for two Loft lessons, L19 and L82, moved to M2.2f | |
| ADR-102: Tube fins’ centre of pressure measured against OpenRocket | M2.2f keeps OpenRocket 24.12’s answers for tube fins as a record: 14 probe designs and its Tube fin rocket, at five Mach numbers. Its tubes lift 1.26 to 1.86 times what hpr’s ring wings do, the same per tube whatever their number, and act a quarter of their length aft of the leading edge up to Mach 0.5, its flat fins’ rule. No measurement supports either, so hpr keeps its model; slender-body theory adds a body interference that hpr leaves out and OpenRocket does not vary with the count (#234). L19’s quarter-calibre bar is not met: up to Mach 0.5 hpr’s center of pressure is 0.42 to 3.0 calibres forward of OpenRocket’s, 1.07 on the Tube fin rocket, and a test pins each gap (tube fins) | |
| ADR-103: The builder API wraps the crates’ own types, with no default materials | M4.1 is split: the builder first (M4.1a), then models of your own and a guide in the API reference (M4.1b). The builder’s Environment, Motor, Rocket and Flight make the crates’ own design tree and simulation and hand them over, so no physics is written twice. Every part names its material and wall, since a default would be a guess at the rocket’s mass. Degenerate numbers are refused where they are given, each by name (L95; The builder) | |
| ADR-104: A drag model replaces the zero-lift drag only, as a drag table does | M4.1b closes M4.1: a drag model of your own, a Rust trait, gives the rocket’s zero-lift drag coefficient at each flow, with hpr’s own drag at hand to adjust. The flight scales it for the angle of attack as it scales a table’s; the normal force, center of pressure and damping stay hpr’s. A model and a table replace each other, and a powered separation refuses either. A model handing back hpr’s drag flies the same flight bit for bit. Three examples join the builder’s, and hpr::guide is the guide in the API reference (Models of your own) | |
| ADR-105: The command line’s surface: every command registered, JSON by schema, a generated table | M4.2 is split in four: the command surface and hpr motors first (M4.2a), then flying a design (M4.2b), the validation cases and file conversion (M4.2c), and reading a flight log (M4.2d). Every command is registered from the start, and one not yet available refuses with exit status 3 and the milestone that brings it. With --json a command prints one JSON document, even when it fails, and each document has a published schema. The README’s command table is written from the tool’s own list of commands, so it can’t claim one that doesn’t exist (The command line) | |
ADR-106: hpr sim flies the library’s flight, the stack whole, from a stated launch | M4.2b: hpr sim flies a .ork or a rocket’s JSON with the library’s own code, so its numbers are a program’s to the last bit. Without options it launches at 0° N, 0° E, sea level, from a vertical 1.5 m rail in calm air, and prints what it used. It flies no parachute or separation yet, and says so in its notes; a rocket whose stages come apart under power is refused (The command line) | |
ADR-107: hpr validate shares the project’s own validation check; hpr convert translates .eng and .rse by the format notes | M4.2c: hpr validate re-runs the RocketPy validation cases and makes the check the project’s automated tests make, with the same code, so the two fail together; it needs a copy of the repository (since replaced by cargo xtask validate --check, ADR-187). hpr convert writes a motor as .eng or .rse: the thrust curve, size and masses come back bit for bit, what .rse adds is filled the way ThrustCurve.org’s .rse files are, and what .eng can’t hold is dropped with a warning (The command line) | |
ADR-108: A flight log read alone: PerfectFlite’s .pf2 first, heights after a running median, an invented log in CI | M4.2d: hpr analyze reads a PerfectFlite altimeter’s log, with no design file, and prints liftoff, apogee, the top speed and landing, each saying where it came from or why the log can’t support it. Heights come from the altitude after a running median, not the Hampel filter Debrief used, because on a real log the Hampel filter kept an ejection charge’s pressure pulse as the apogee. The tests read an invented log whose every reading is known; the one public real log, whose terms are unclear, is read only where it has been fetched (Flight-log readings) | |
ADR-109: M3.2 split, and a .ork written from the design | M3.2 is split: the writer first (M3.2a), then OpenRocket loading and flying what it writes (M3.2b). hpr writes a .ork from its own design, each value as the reader reads it, and puts back everything it keeps but doesn’t model where it was. A value the reader drops, such as a rail button’s screw height, is kept and written back, so OpenRocket still reads it. Each number is written as the shortest decimal that reads back to the same bits. Ids that aren’t UUIDs are left out, since OpenRocket refuses a file holding one (Writing a .ork) | |
| ADR-110: M3.2b: OpenRocket flies the export; only counts are published | OpenRocket 24.12 tries to fly each of the 75 .ork files hpr’s checks use twice, as written and as hpr writes it back out, and only counts are committed. Every design it opens as written must open as exported, a design it refuses must be refused for the same reason, and every configuration flown both ways must reach the original’s apogee within 0.5% (Checked in OpenRocket) | |
| ADR-111: M3.3: the hpr design format, its extensions, versions and crate | M3.3 is split: the JSON document first (M3.3a), then the zip container, migrations and the comparison (M3.3b), then generated types (M3.3c). A design is a .hpr file, the container a .hprz. A document names its format and a major.minor version, checked first; a key its version doesn’t define is refused, not dropped. The document holds the design as the .ork reader models it, with the source file’s other files, so hpr-format builds on hpr-io (The hpr design format) | |
ADR-112: M3.3b: the .hprz container and migrations | Version 0.2 renames the source file’s other files source_files, so “attachment” means a file in a .hprz, and records why a .ork’s airframe wasn’t read as written, which the .ork written from a document can’t say. A change that stops old documents reading takes a new version and a migration, tested on a committed older document. A .hprz is a zip whose first entry is the .hpr; attachment names are relative paths, refused otherwise. hpr convert and hpr sim take all three design formats (The hpr design format) | |
| ADR-113: M3.3c: TypeScript and Python types | xtask generates the types and a reader for each language from the schema, not a third-party generator. A reader checks a document against the schema embedded in its file, and tests hold both readers to a separate schema checker on 4,892 altered documents. Not on npm or PyPI (TypeScript and Python) | |
| ADR-114: M4.3: the Python package | M4.3, the Python bindings, is split in three: the package, RocketPy’s example flown from Python, and models written in Python. The package wraps the Rust builder and adds no physics; it keeps RocketPy’s shape (a flight flies when it is made, its recording comes back as arrays) but the Rust API’s unit-named arguments. One wheel per operating system serves CPython 3.10 on; nothing is published to PyPI | Python |
| ADR-115: M4.3b: a drag table, and Calisto from Python | The flight builder takes another program’s drag table, and the Python package gains it with RocketPy’s gravity formula and a parachute cut away when another opens. RocketPy’s ways of measuring a flight (from the dry center of mass, its rail exit at the forward button) stay in the Calisto example rather than the library; a test holds the example to 3% of RocketPy and to the validation suite’s own numbers | Python |
| ADR-116: M4.3c: drag and wind as Python functions | A flight takes a drag, and an environment a wind, written as Python functions. hpr calls them as it flies; an exception one raises stops the flight and reaches the caller unchanged, not as hpr’s own error. A constant drag function flies exactly as a table of the same number | Python |
| ADR-117: M5.1 split; the cache and offline mode | The online layer ships in two parts: first the cache and the offline rule over a transport you plug in, then HTTP. Offline never calls the transport; online, a copy younger than the source’s time to live is served without fetching, and a failed fetch falls back to an old copy marked stale | Online data and the cache |
| ADR-118: M5.1b, HTTP over the cache | The HTTP client is ureq with rustls, behind a cargo feature, so no OpenSSL. Its size limit counts the unpacked answer, since a small compressed one can unpack to gigabytes. The platform’s cache folder is found by hand, because the usual crate for it pulls in a weak-copyleft (MPL-2.0) dependency | Online data and the cache |
| ADR-119: M5.2 split; Open-Meteo’s pressure levels as a sounding | The weather milestone ships in four parts: Open-Meteo first, then weather-balloon soundings, then NOAA’s model files, then files you download and the hpr weather command. Open-Meteo’s answer becomes a sounding whose lowest level is the ground, with the 10 m wind as the wind on the rail. Levels the models report below the ground are left out, and the heights are read as geopotential, which a check on the recorded answers bears out | Launch-day weather |
| ADR-120: University of Wyoming soundings | A weather balloon’s sounding from the University of Wyoming’s archive is read from its comma-separated text, whose column names carry the units. Rows are kept from the longest chain from the ground in which each row fits the thickness the hypsometric equation gives the layer from the row before it; of each run of rows with the same rounded pressure the middle one is kept; a row kept must lie above the last one kept. The first row is the ground; the answer is refused when a chain without the ground beats every chain with it. A saved copy is fetched again once the sounding has settled. Only soundings from U.S. stations, U.S. government works, are committed as test data | Weather-balloon soundings |
| ADR-121: GFS and RAP from NOMADS’ grib filter, read by an in-house GRIB2 decoder | NOAA’s GFS and RAP forecasts are fetched as a small GRIB2 cut from NOMADS’ grib filter, 0.3° each way around the site, and blended bilinearly between the four grid points around it. The ground and the levels above it follow ADR-119 (the Open-Meteo sounding), and RAP’s winds, given along its map’s grid, are turned to east and north at the site. hpr reads GRIB2 with its own decoder (latitude/longitude and Lambert grids, simple packing) rather than the grib crate, which gives single-precision values and binds C libraries; every value matches ecCodes’ to one rounding. Whole NCEP files, with complex packing or JPEG 2000, are refused and left for files you download | NOAA forecasts: GFS and RAP |
ADR-122: hpr weather, and M5.2d split | The command line fetches a launch day’s weather from any of the sources, one subcommand each, through the same cache as the library. --offline answers from the cache alone, and --from reads an answer saved earlier, held to the same checks as a fetched one. The profile is written as the library’s own sounding type, which reads it back with its checks. NOAA’s whole files, with their other compressions, follow in two more steps | The command line |
| ADR-123: Complex packing, and a whole GFS file | hpr’s GRIB2 decoder reads the tighter packing of NOAA’s whole GFS files, and totals over a time span (such as accumulated rain; read, not used in a profile). Every value of one whole file was checked against ecCodes by a script, run once outside CI; CI checks eight of its messages and a recorded cut ecCodes packed the same way. A whole file’s profile is its NOMADS cut’s to 1.04e-7, with the levels above 10 hPa as well | A whole GFS file |
ADR-124: JPEG 2000 packing, through hayro-jpeg2000 | hpr’s GRIB2 decoder reads fields stored as JPEG 2000 images, as NOAA’s whole RAP files are, using a JPEG 2000 decoder written in Rust rather than one of its own. Only lossless images of up to 21 bits a value, coded as NCEP codes them, are read, which its 32-bit floats keep exact; the rest are refused by name. CI checks four public RAP fields against ecCodes | Files in JPEG 2000 |
ADR-125: Site data split, and WMM2025 in hpr-core | M5.3 split a to c; WMM2025 in hpr_core::magnetic, finite at the poles, refused outside 2025 to 2030 and −1 to 850 km; NOAA’s 112 test values, NCEI’s file’s X to its measured 7.18e-4 nT residue, shown to lie in the file’s X′ | |
| ADR-126: M5.3b, Open-Meteo’s elevation through the cache | M5.3b: Open-Meteo’s elevation in hpr_net::elevation, up to 100 places a request, coordinates to 5 decimals in the URL, a year’s TTL, heights refused outside −1,000 to 9,000 m, a surface model above the EGM2008 geoid with N left to the caller; no command yet | |
| ADR-127: M5.3c1, geodesics through GeographicLib, held to Karney’s test set | M5.3c split c1, c2; geodesics in hpr_core::geodesic through geographiclib-rs, flattening past 1/150 refused; Karney’s 500,000-line test set within his 15 nm on five measures, either azimuth pair on its 21 mirror lines | |
| ADR-128: M5.3c2, a site’s height from a user’s GeoTIFF, held to rasterio’s reading | M5.3c2: a user’s GeoTIFF in hpr_io::geotiff over the tiff crate; geographic CRSs within a few meters of WGS 84 only, projections and far datums refused; the containing pixel placed as GDAL places it; GDAL’s scale and offset, units the file states, else meters; held to rasterio 1.5.2 on seven fixtures and a whole USGS tile | |
| ADR-129: M5.4 split, and M5.4a, the motor finder’s API through the cache | M5.4 split a to c; M5.4a: motor.fusionspace.co’s five files in hpr_net::motor_finder through the cache, an hour’s TTL, its structural rules refused and its derived ones pinned on the recording; eight answers of one build committed as fixtures; the credit with the site’s caution on every answer | |
| ADR-130: M5.4b, ThrustCurve searches and curves through the cache, and the in-stock join | M5.4b: ThrustCurve.org’s search and download in hpr_net::thrustcurve through the cache, a day’s TTL; the join by exact maker and designation, misses reported not guessed; three makers’ searches and two public-domain files committed as fixtures; the join’s report in validation/reports/thrustcurve-join.md | |
ADR-131: M5.4c, hpr motors search, stock and prices at the command line | M5.4c: hpr motors search, the finder’s list from the network, the cache or a saved file; five filters, --max-price in exact cents on the cheapest in-stock offer; cheapest first; both credits on every list; the example tested on an edited copy, as the recording lists nothing at $150 | |
ADR-132: M5.5a, OpenRocket’s .orc parts catalogues, held to OpenRocket’s reading | M5.5 split a and b; M5.5a: hpr_io::orc reads OpenRocket’s .orc parts catalogs; the 16 files OpenRocket 24.12 ships bundled unchanged (Apache-2.0); held part by part to OpenRocket’s preset loader, run as an oracle; exact unit definitions, the file’s makers’ names and densities kept, a stated mass kept beside them; unreadable parts left out with a warning, not the file | |
| ADR-133: M5.5b, catalogue parts in the builder, weighed as OpenRocket builds them | M5.5b: catalog parts in the builder (from_catalog on Nose, Tube, Transition, MotorTube, and the new Fitting); what the file leaves unsaid as OpenRocket 24.12 builds it, but a hollow part’s shoulder takes its wall; a stated mass scales the part’s density; a part with an undefined material refused; every part held to OpenRocket’s built mass and center, the two codes’ hollow walls each checked | |
| ADR-134: Monte Carlo dispersion: independent normals, one stream per sample and input | M6.1a: Monte Carlo dispersion in hpr_analysis::montecarlo; each input an independent normal about its nominal value; one random stream per sample, input and copy, keyed by SeededRng::for_stream; impulse dispersed with the propellant mass; a drag scale in the aero model; failed samples kept; M6.1 split a to d | |
| ADR-135: Landing ellipses: the normal ellipse, the next flight’s, and a count of what each holds | M6.1b: landing ellipses in hpr_analysis::ellipse; the normal ellipse of the sample’s mean and covariance, scaled by k² = −2 ln(1 − p); a prediction ellipse for the next flight by Hotelling’s T²; the landings each ellipse really holds counted, failures as bounds; tested against normal spreads with known answers | |
| ADR-136: Sensitivity analysis: Morris paths and Saltelli’s Sobol’ estimates, with their standard errors | M6.1c: sensitivity analysis in hpr_analysis::sensitivity; uniform independent factors; Morris’s paths with μ, μ*, σ and μ*’s standard error, and the exact grid moments by Morris::population; Saltelli 2010’s first-order and Jansen’s total estimates on pseudo-random rows, with delta-method standard errors; held to Ishigami and Sobol’s g in closed form and calibrated over seeds | |
| ADR-137: Ten thousand flights: a run’s flights share the nominal’s layout and supersonic table | M6.1d: a Monte Carlo run’s flights share the nominal design’s supersonic table (AeroModel::share_supersonic_table, when the covered segments and reference area are equal) and its layout (Rocket::lay_out, LaidOut::relay, Simulation::from_laid_out); evaluations borrowed, not copied; 10,000 flights timed on Valetudo (the flight benchmarks’ Level 2 rocket) and on a supersonic K940 rocket, by a bench target; per-evaluation speed-ups left to #285 | |
| ADR-138: Optimization: CMA-ES first, held to test functions and to pycma | M6.2 split a to e; M6.2a: CMA-ES (Hansen’s tutorial, Table 1, positive weights only) over continuous variables, worked in each variable divided by its step, with optional bounds by resampling, ask-and-tell (Run::tell), Jacobi eigen-decomposition each generation; held to four test functions’ minima, to pycma 4.5.0’s evaluation counts (medians within 25%) and to a dense recomputation of every generation; the 3,048 m problem re-flown from a fresh build and at 100× tighter tolerances | |
| ADR-139: Optimization constraints by Deb’s feasibility rules | M6.2b split b1, b2; M6.2b1: constraints for CMA-ES by Deb’s (2000) feasibility rules (Evaluation, Run::tell_constrained), no penalty weight; infeasible candidates ranked, not redrawn; a target and TolFun count only feasible points; held to the sphere with x₀ ≥ 1, the tangent problem and CEC 2006 g06 from 20 seeds | |
| ADR-140: Discrete choices by CMA-ES with margin | M6.2b2: integer variables (Variable::integer) by CMA-ES with margin (Hamano et al., GECCO 2022), α = 1/(nλ); Φ by libm::erfc, Φ⁻¹ by AS 241; held to SphereInt, EllipsoidInt and SphereOneMax at 10 and 20 variables and to cmaes 0.13.1’s CMAwM; the rocket example hits 3,048 m with the motor and nose free, its body length fixed so designs share a supersonic table | |
| ADR-141: Several goals by NSGA-II | M6.2c: several goals by NSGA-II (Deb et al. 2002) with bounded SBX and polynomial mutation, constrained domination; held to ZDT1 to ZDT3’s exact fronts and to pymoo 0.6.2 (every run’s GD and IGD within twice pymoo’s worst, medians within a factor of 1.25 either way), tournaments paired as pymoo pairs them; a rocket’s apogee against static margin, its front flown again and matched by CMA-ES at 2.5 calibres | |
| ADR-142: Few evaluations by EGO | M6.2d: EGO (Jones, Schonlau and Welch 1998) with a kriging surrogate fitted by likelihood and the expected improvement searched by CMA-ES; M6.2d split d1 (Branin, Hartmann 3: within 1% of the minimum in 50 evaluations from 20 seeds, worst 0.12%) and d2 (Hartmann 6, which d1’s version leaves at a local minimum in 7 runs of 10) | |
| ADR-143: The operating envelope and a stop rule for accuracy work | The bands are set by Mach number alone. Accuracy work goes to the core band first, Mach 0 to 2.5, where nearly all commercial-motor flights are. Mach 2.5 to 3.5 is the extended band, which hpr flies with its accuracy checked less; the envelope is Mach 0 to 3.5 at any angle of attack. The angle is a separate condition: accuracy work assumes 15° or less. Faster flights still fly, and M1.14a will flag any flight beyond the validated range, at high angle of attack, outside the core band or beyond the envelope. An accuracy step counts as progress when it shrinks a measured error against an independent reference, or adds a reference that will; two steps in a row that do neither end the milestone, gaps written down. M1.8 closes with its drag target missed, and that target moves to M1.14; only the work above Mach 4 is deferred | Validation plan: the operating envelope |
| ADR-144: The 2026-10-03 check-in | What runs next (M0.5, leaner bookkeeping, then M6.2d2, M4.5, M1.14 and M6.2e), CAD interop added as M8.3, how issues are labelled and ordered, the writing standard for these pages, guardrails on safety-relevant numbers, and licensing questions settled | Writing these pages |
| ADR-145: Recorded answers and their licences: stand-in ThrustCurve searches, CC BY 4.0 for the motor finder | Recorded answers and their licenses: ThrustCurve.org’s three searches replaced by stand-ins (five invented motors per maker, and the in-stock motors’ records carrying the motor finder’s CC BY 4.0 values); motor.fusionspace.co’s answers under CC BY 4.0, credited “Motor stock data from motor.fusionspace.co” | |
| ADR-146: Leaner bookkeeping split, and one file per decision record | M0.5 in nine increments, one per item of its plan; each decision record in its own file, with this site’s links and the generated index pointing at it, and every older link still landing on the record’s row | Decisions and the roadmap |
| ADR-147: A roadmap of open work, an archive, and a queue | The roadmap now holds only open work, in an order set by a queue at its top that the checks follow; done milestones move, word for word, to an archive file, by a command rather than by hand | Decisions and the roadmap |
| ADR-148: M0.5c, a short STATUS with a shape the guard checks, and its notes moved to on-demand files | The status file is now short and checked: 12,000 bytes, 110-character lines, a short note for Neer first, a 15-line handoff and 5 done entries; its long working notes and caveats moved word for word to two research notes read on demand | |
| ADR-149: M0.5e to g, reviews while CI runs, a faster gate and CI, and a lighter session start | Reviews start once the PR is open and CI runs, with explicit models and effort, a shared bar for blocking findings, and cheap scoped re-reviews; the gate runs tests in parallel and adds the private-data checks when physics changes; CI’s slowest job is split; a session starts from the status file and its roadmap entry | |
| ADR-150: Peak thrust and the burn-time crossings come from delivered samples | A thrust-curve sample strictly inside a run of three or more equal times is never delivered, so it no longer sets the peak thrust or a 5%-of-peak burn-time crossing; no surveyed ThrustCurve.org file changes | |
| ADR-151: hpr-sim-fixtures joins the reference library as private data | Neer’s collection of designs paired with the logs of the same flights is pinned in the reference library and kept private under refs/; only aggregate statistics are published; it stays out of the default .ork survey until an increment brings it in | |
| ADR-152: Hartmann 6 by EGO’s log transform | M6.2d2: EGO fits its surrogate to −ln(−y) (or ln y) of the values when the caller asks, as Jones, Schonlau and Welch did on Hartmann 6; all 20 runs (seeds 1 to 20) end within 1% of the minimum in 250 evaluations, worst 0.29%, against 6 of 20 without; the 20-run check is a release-build program the local gate runs, as it takes hours in CI’s debug build | |
ADR-153: A .ork’s recovery flown as OpenRocket flies it, held to its descents | M4.5a: a .ork configuration’s parachutes and streamers become flight devices: the stated drag coefficient, or OpenRocket’s own (0.8 on the canopy for a parachute, appendix C for a streamer), opening at once; apogee, altitude, ejection and launch triggers with the file’s delay. Targets, set before any hpr descent was measured: each deployment within 0.1 s or 2% of OpenRocket’s time, landing speed and flight time within 5% | |
| ADR-154: Motors fetched from ThrustCurve.org by name, cached, and named when offline | M4.5b: hpr sim fetches a motor the bundled catalog lacks from ThrustCurve.org, by name for --motor and by manufacturer and designation for a .ork motor with no curve, through hpr_net’s cache; hpr motors fetch pre-loads; offline and uncached, the refusal names the exact command. One rule picks the file; nothing is bundled | |
| ADR-155: Design checks that match reality: a part through the skin, a case that can’t fit | M4.5c: an internal part wider than its parent’s bore but inside the airframe warns; one that reaches past the airframe’s outside by more than 0.005 in is an error. A nominal motor size wider than its mount’s bore warns while AeroTech’s drawn case fits it, and is an error past that. OpenRocket’s examples raise no design error; the private library’s errors fall from 13 flights to 5 | |
ADR-156: hpr sim reads by name: configurations by their motors, a lead summary | M4.5d: hpr sim‘s text names configurations, mounts and the design checks’ parts by name, never by UUID; an unnamed configuration is called by its motors and delays in brackets, such as [C6-5]; --config takes a configuration’s number, name or id, and --mount a mount’s name or id; the checks print as sentences; the summary leads with margin, apogee, rail exit speed, delay and descent. --json keeps the ids | |
ADR-157: hpr sim --plot draws one fixed SVG figure | M4.5e: hpr sim --plot FILE.svg writes one SVG: altitude, speed and acceleration against time in three panels over one time axis, each instant with events a numbered marker listed underneath, and the fall on the airframe alone shaded “not a prediction”. It is drawn by hand in hpr-cli, with no plotting dependency, from its own sampling of the flight, which adds every step’s start and end to the recorder’s times so a parachute’s opening is drawn at full height | |
ADR-158: Three how-to guides run like the command-line guide, on a rocket of their own, with --delay for --motor | M4.5f: the guides “Fly your .ork”, “Pick a motor” and “Check stability for a certification flight”, and the README’s “Install and first flight”, show hpr’s output made by running each command, as docs/cli.md does, so CI fails when one goes stale. They fly a hand-written public design, validation/fixtures/ork/guides/level-1.ork, whose two motors are in hpr’s catalog, so they run offline. hpr sim --delay sets --motor’s ejection delay. Guidance numbers are quoted from their sources, dated, never stated as hpr’s | |
ADR-159: A .ork’s powered separation flown in hpr sim, each part under its own devices, a part with none tumbling | M4.5g1: hpr sim flies a .ork configuration whose booster drops away under power. hpr::ork::separated_recovery puts each parachute and streamer on the part its stage is in, and adds the tumbles the flight needs: the booster tumbles from the split until its first own device opens and releases the tumble, and a sustainer with no device tumbles from its apogee. FlightBuilder::separation takes the separation, so the command flies the library’s flight, bit for bit. Each part’s landing is printed. The sustainer’s descent is held to OpenRocket’s with ADR-153’s targets; the booster’s is not validated | |
| ADR-160: Several powered separations, each handing the flight on to a sustainer cut at its boundary | M4.5g2: the flight takes a list of separations, in the order they fire, each at a stage boundary further forward than the one before (Simulation::with_separations). With more than one, each must leave the nose’s body a motor to burn: at each, the stages behind drop away as the next body and the flight flies on as a sustainer cut from the whole design at that boundary. The .ork reader returns every powered separation, from the tail forward. OpenRocket’s Three stage low power rocket flies in hpr sim and in cargo xtask ork-flights. In the report, on OpenRocket’s own curves, its three configurations are within 1.48% of OpenRocket’s apogee and 1.64% of its largest speed, both separations at OpenRocket’s times; in hpr sim, on the curves it fetches (ADR-161, OpenRocket’s curves by digest), within 2.48% and 1.67% | |
ADR-161: A .ork motor fetched from ThrustCurve takes the file holding OpenRocket’s curve for its digest | amends ADR-154 §2 and §4: a fetch may name a ThrustCurve data file to take ahead of the rank’s order (Wanted::prefer, hpr motors fetch --file). hpr sim names one for a .ork motor whose digest a committed table holds: the file whose curve is the one OpenRocket flies. cargo xtask ork-curves writes the table for the motors of OpenRocket’s examples by comparing curves; it holds ids alone. With it, OpenRocket’s three-stage example’s first configuration reads +0.31% of OpenRocket’s largest speed in hpr sim, not +5.7%, and every configuration is within 2.48% of OpenRocket’s apogee | |
| ADR-162: The suite and its releases: what ships when, and the order of the new product lines | Neer’s 2026-10-04 ideas: hpr-sim becomes a suite of six products built in one workspace and joined by shared formats (simulator, flight analyzer, app, motor designer, recovery designer, avionics). Releases come at product boundaries: 0.1 the simulator once M4.5 and M1.14a are met, 0.2 accuracy, 0.3 the flight analyzer, 0.4 competitions, 1.0 the first app. The UI phase no longer waits for every library phase. COTS solids stay the only scope until 1.0. After it, the new lines come one at a time: experimental solid motors, then custom parachutes, then avionics, then hybrids and liquids. Each line gets its own guardrails | |
| ADR-163: The second pass: six products, the analyzer before the accuracy campaign, and what each release must hold | amends ADR-162 §1 to §4 after a review of the whole project, its 95 open issues, its throughput, its users and its competitors. The six products are defined by who uses them; the competition kit is a product and avionics starts as a test bench for any flight computer. Release 0.1 adds Monte Carlo from the CLI and Python, an apogee check on the logged flights, and named issue fixes. 0.2 becomes the flight analyzer (logs, a flight against its simulation, drag fitted from logs), ahead of the accuracy campaign it feeds; 0.3 is accuracy and fault diagnosis; 0.4 the competition kit, with RASAero and RocketPy files and ejection-charge sizing; 0.5 an app preview whose center is the 3D ghost replay; 1.0 the app with the editor. After 1.0: the motor designer, the recovery designer, pad day on a phone, then avionics | |
ADR-164: hpr-sim follows the FusionSpace product system, as FS · SW · TOOL 005 | hpr-sim adopts the FusionSpace product system (nrdptel/fusionspace-design, product/, Rev A, pinned at 32770a4) for its command line, documentation site, plots, exports, writing and every later app and device. It takes the designation FS · SW · TOOL 005. Apache-2.0 files from the system are copied in with their license lines; brand files only as README banners, outside the repository’s license. Milestone M0.6 makes the existing surfaces comply, after M4.5 and before release 0.1; later milestones and every release checklist take the system’s rules and checklists. The CLI keeps SI first with US units in brackets, and carries no brand banner | |
ADR-165: A .ork’s separation with nothing left to burn flies in hpr sim when each part has drag from the split | M4.5g3: a .ork configuration whose only separation comes with nothing ahead of it left to burn, such as a payload dropped at its booster’s ejection charge, is read and flown. From the split every part flies as a point with only its own devices’ drag, ADR-014’s model unchanged, so hpr::ork::tumbling flies it only when the part that keeps the nose has a device of its own open by the split, and refuses it by name otherwise. lowerstageseparation opens a device on the split’s own trigger. OpenRocket’s Deployable payload and ARC payload rocket fly: the payload’s apogee within 1.05% of OpenRocket’s record and every descent within ADR-153’s targets. The coast with no drag that the rule refuses would put one payload 4.00% above OpenRocket’s own free flight of it | |
| ADR-166: A fin set on a nose cone or a transition, its root along the surface | M4.5g4: a freeform fin outline’s last point may stand above its first, and the planform gains root_m, the root’s points between its trailing and leading edges. On a body tube the root stays level. A fin set may now sit on a nose cone or a transition: the tree checks that each of its root’s points lies within a micron of the surface and that it has no tab or fillet. Its body radius is the surface’s at the root leading edge, from which its heights are measured. The .ork reader draws the root through 63 points on the parent’s profile. OpenRocket’s Pods–airframes and winglets flies all five configurations, each apogee within 0.5% of OpenRocket’s record; its cockpit’s area, mass and center of mass match OpenRocket’s on OpenRocket’s own root points | |
| ADR-167: A part’s drag override, as OpenRocket flies it | M4.5h: a .ork part’s or stage’s stated drag coefficient flies in hpr as OpenRocket 24.12 flies it, measured on 25 probes; a step down belongs to the part ahead of it; Base drag hack (short-wide) within 2.1% on a C11-5, but 13% and 11% high on a D12-3 and an E12-4 for its nose (#177), not the setting: not met for those two, recorded. | |
| ADR-168: Pods–powered flies, and the margin is the weakest plane’s | M4.5i: a rail button’s screw head weighed as half an ellipsoid; the thrusting motors’ area told apart per pod set; a device at the charge of a stage where no motor lights never opens, as in OpenRocket; the margin reported in the rocket’s weakest plane (#329); OpenRocket’s Pods–powered with recovery deployment flies its three complete configurations, two within 1.9% of OpenRocket’s apogee, the third turning over before apogee in both tools | |
| ADR-169: A ring around its tube needs room in the part around it | M4.5k: a centering ring on its tube’s axis whose bore takes the tube’s outside wraps the tube, and is measured in the part around it at its own station that holds it whole; amends how two earlier decisions read the pods examples’ rings, which now fly as saved | |
| ADR-170: A packed part wider than its bore warns | M4.5l: a packed part (a mass component, parachute, streamer or shock cord) drawn wider than the room in its parent warns, by any amount, while its center is in that room, and flies as drawn; its width sets only its own inertia. A ring, tube or packed part centered past the room stays an error. OpenRocket’s Deployable payload flies its five configurations as saved | |
| ADR-171: A parallel stage is a pod set that separates | M4.5m: hpr’s design gains a parallel stage, a stage laid out as a pod set beside a body tube of an axial stage before it, weighed to its own stage and dropped by its own separation as a part that tumbles. The .ork reader reads OpenRocket’s <parallelstage> on a rocket of one axial stage; a motor in it lights as one in that stage does, and a parallel stage with no motor that lights stays on. OpenRocket’s Parallel booster staging flies both configurations as saved, each apogee within 1.3% of OpenRocket’s | |
| ADR-172: A stage’s first burnout, and a booster dropped still burning | M4.5n: a .ork stage whose motors sit in several mounts burns out when its first motor does, by the motors’ ignitions and curves, as OpenRocket 24.12 flies it (measured by a committed probe). The stage above lights there, and the stage separates there, when the file says so. A split at that first burnout may drop the stage’s other motors still burning. The flight then leaves their thrust out of the dropped part’s flight as a point, and says how much impulse that is. OpenRocket aborts its own flight of Pods–powered with recovery deployment’s first configuration, so hpr’s flight of it is checked against OpenRocket’s up to the abort: at the separation and at OpenRocket’s last row, within 5% | |
| ADR-173: A blunt ellipsoid’s subsonic pressure drag, from Hoerner’s measurement | M4.5o: an elliptical nose or shoulder takes Hoerner’s measured forebody pressure drag below Mach 0.8 (a hemisphere 0.01, a round head one diameter long −0.05, a flat face the step’s), held at 0 from 7/12 calibre on, and rises in a straight line from Mach 0.8 to Stoney’s scaled curve at Mach 1.2. Base drag hack (short-wide)’s 0.577-calibre nose gets 0.0008, so its E12-4 stays 7.80% above OpenRocket’s apogee with recovery in both: the 5% bar would need about 0.015, which no measurement supports. Not met, recorded; M4.5 is closed with that gap. | |
ADR-174: The command line’s colors, help: lines and title block | M0.6b: hpr colors its streams by the product system’s cli.md (the --color flag, then NO_COLOR, then FORCE_COLOR or CLICOLOR_FORCE, then auto, each stream on its own), in the system’s fs_style.rs roles, copied in unchanged; never in --json output or a file. Every hint is a help: line after the fact it is about, and an error document’s help array; clap’s tip: and “For more information” lines are rewritten to match. hpr --version, every --json document (a tool object first), and every file hpr writes name hpr-sim, its version and FS · SW · TOOL 005, each in the place its format keeps for it; a CSV’s goes in a .meta.json sidecar. A converted design file names this program, its source kept as read, amending ADR-112 §6. | |
| ADR-175: The plot in the product system’s chart style | M0.6c: hpr sim --plot draws in the light theme’s color roles of the product system’s foundations (Rev A) and no other color; every series is simulated, so dashed in the predicted color, a quantity’s size thick and its vertical part thin; events are dotted lines under numbered balloons with a table of every event’s number, time, altitude and name; the ground is a chain line; axis titles are QUANTITY · unit; no legend box, the line types said once in a caption whose first line, also the SVG’s <desc>, gives the summary’s apogee, its time and top speed. The fall that is not a prediction is hatched, its label outside the hatching. Amends ADR-157 §2, §3 and §5. | |
| ADR-176: The spelling check: what it reads and what it leaves alone | M0.6d is split in two: M0.6d1 adds cargo xtask spelling and clears the pages, the README and the scripts; M0.6d2 widens its scope to the crates, xtask, the schema and the pages’ fenced code blocks. The check reads a file’s writing (a page’s prose, a source file’s comments and strings) and skips code identifiers, string literals that are one bare word, link targets and URLs, HTML tags, links quoting a decision record’s title, and the frozen records, which now include docs/DECISIONS.md. Quotations, source titles and names that keep their spelling sit on a short list in the check, each with the phrase that holds it; the check counts them on every run and fails on an entry that matches nothing. | |
| ADR-177: The spelling check in the crates: words first, em dashes next | M0.6d2 is re-split in two before it shipped: M0.6d2 widens cargo xtask spelling to crates xtask schema and the pages’ fenced code blocks, read by each block’s language, and clears every UK spelling there; M0.6d3 rewrites the 266 em dashes left in them, which the check counts and prints until then. A name in a format string and a key quoted inside a string are identifiers; the check’s own file isn’t read; probe names an oracle’s recording keys by are allowed names. | |
| ADR-178: US names, and the spelling check reads them | M0.6e renames the 63 names that held a word on M0.6d’s list (center_of_pressure_m, MorrisDesign::analyze, VerticalUnit::Meter and the rest, as they are now called) to their US forms, and cargo xtask spelling now reads names as well as writing, so a new one fails CI. Seven serialized types keep each renamed key’s old spelling as a serde alias, read and never written, with tests that read the old form back; the design format’s keys never held a word on the list. GDAL’s own names for a unit are another program’s data and stay. | |
| ADR-179: The envelope flags, and when an angle of attack counts | M1.14a splits in two: a1 the four envelope flags of ADR-143 §1, a2 the warnings for ADR-163 §4’s issues. The flags come from a flight’s summary: three by its top Mach number against 1.1467 (the fastest public reference, pinned to the committed reports by a test), 2.5 and 3.5, and one by a new peak, the largest angle of attack more than 1 s after the rail exit and before apogee or the first deployment, counting only instants whose dynamic pressure is at least a tenth of the largest so far. Each edge is exclusive. The library, hpr sim (text and JSON) and Python all report them. | |
| ADR-180: The drag issue warnings, and M1.14a2’s split | M1.14a2 splits in two: a2 the warnings for the five drag issues on ADR-163 §4’s list (#67, #68, #70, #72, #222), a3 the four stability ones (#87, #120, #121, #172). A drag warning comes from the flight’s top Mach number and the design’s parts: a cone or ogive nose past Mach 0.8 (#67); every rocket past Mach 0.8, saying low from 1.2 (#68); airfoil fins past Mach 1 (#70); a boattail steeper than 10° past Mach 1 (#72); an ogive nose or airfoil fins past Mach 1 (#222). Each Mach edge is exclusive; a NaN top Mach number raises every warning the design’s shape allows. The library, hpr sim (text and JSON) and Python report them. | |
| ADR-181: The stability issue warnings | M1.14a3’s four stability warnings. #87, #120 and #121 warn past Mach 1.2 when hpr_aero’s supersonic body run, which is otherwise silent about why it stops, names that switch as the one that stopped it: a new public SupersonicFallback on AeroModel. #172 states no condition, and its cause is unmeasured, so it warns on every flight on hpr’s own aerodynamics that reports a smallest static margin, quoting the largest measured gap (0.073 calibres high) and no threshold. | |
ADR-182: hpr mc, Monte Carlo from the command line | M4.6 is split: M4.6a hpr mc, M4.6b Python. A Monte Carlo run’s FlightInputs now carry the flight’s separations, so a staged .ork is scattered as hpr sim flies it, and a tumble hpr adds to a separated part is not given a dispersed lag. hpr mc takes one option a dispersion, in the command line’s units, flies its samples on every core, prints the nominal flight beside the apogee’s and landing distance’s spreads and three landing ellipses, counts its failed flights by reason, and exports every flight as a CSV table (hpr_analysis::table::RunTable) whose numbers read back to the run’s bits. | |
| ADR-183: Monte Carlo in Python | hpr.MonteCarlo flies the library’s run on every core and returns its RunTable as NumPy arrays: numbers as float64 with NaN for a missing value, index as uint64, words as string arrays. Its eleven arguments are hpr mc’s options under the names its JSON uses. Rocket.from_file(..., recovery=True) flies a file’s recovery devices as hpr sim does, so a Python run and hpr mc can fly the same design, and a test holds them equal bit for bit with both release builds. | |
| ADR-184: Logged apogees of the private collection | M2.3c1 flies the 83 tier-A flights of hpr-sim-fixtures whose design is a .ork, in hpr and in OpenRocket 24.12, each in its day’s ERA5 weather with nothing deployed, and compares each apogee with the flight’s logged one, turned into the height climbed in that day’s air. A hand-read manifest under the gitignored corpus/ holds what each flight’s free-text row says; only aggregates are published, with the collection’s credit and the Copernicus attribution. | |
| ADR-185: Release 0.1 split, and its first fixes | M10.1 is split in four: a, the flight and design fixes; b, the data, network and Python fixes; c, the release workflow; d, the release notes and ADR-162’s checklist. M10.1a refuses a separation or ejection timed before the rail exit instead of firing it late, records one apogee, counts only errors in SimError::DesignChecks’s message, makes DragTable::with_reference_diameter_m check its diameter (#79’s decision), and measures a part in a nose cone or transition against the room where it sits: an error past the fit tolerance of the widest room along it, a new warning when it fits there but runs into the wall where the profile narrows. | |
| ADR-186: The data, network and Python fixes of release 0.1 | M10.1b fixes five issues. The bundled motor catalog is written from its 32 public-domain curve files alone by cargo xtask motor-catalog, every figure the file’s own (#295). .hprz attachment names are compared after canonical decomposition as well as case folding (#252). Open-Meteo and NOMADS write a site’s coordinates to 5 decimals so a radians round trip keeps the cache key (#272). Three pages’ accuracy figures are the report’s, and the site’s number trace now checks them (#298). A pytest pins Python’s recovery=True flight to hpr sim’s bit for bit (#308). | |
ADR-187: The release workflow, its license texts, and hpr validate left to xtask | M10.1c: a Release workflow builds and smoke-tests the command line’s archives for three operating systems, the Python package’s abi3 wheels and its source package, each carrying both licenses, THIRD-PARTY-NOTICES.md and its dependencies’ license texts written by cargo-about; it publishes only from a dispatch that asks to, after approval in the release environment. Every library crate and hpr-cli become publishable. hpr validate leaves the command line, because a published crate can’t depend on the unpublished harness; cargo xtask validate --check makes the same check. | |
| ADR-188: Release 0.1’s notes, and the flattering-side issues without a warning | Release 0.1’s last increment splits in two. M10.1d1 writes CHANGELOG.md and the install pages, and lists by number every open env-core issue on the flattering side or of unknown sign; M10.1d2 adds a warning for each flattering-side issue that has none (#18, #64, #73, #179, #325, #326, #354, #367), settles or warns each unknown sign, fixes #335, and then shows the whole checklist at a commit on main. The changelog links pages by the site’s address and is held to the site’s link and label checks. | |
| ADR-189: The unstable-under-power flag and four shape warnings; M10.1d2 split in three | M10.1d2 splits in three: d2 the flag for a flight unstable under power (#335) and the warnings read from the design’s shape (#64, #73, #325, #367) with #172’s bound raised to 0.1108 calibres; d3 the warnings for separated parts, laminar friction and kinked fins (#18, #179, #326, #354) and the seven unknown signs; d4 the checklist and its Release dispatch. Each new warning’s condition takes in the unmeasured range next to its measured one. | |
| ADR-190: The friction and freeform fin warnings; M10.1d3 split in three | M10.1d3 splits in three: d3 the warnings read from the design and the drag alone (#18 on every flight on hpr’s drag, #326 on every freeform fin set, both at any speed); d5 the separated parts’ warnings (#179, #354); d6 the seven unknown signs. Each takes in its issue’s unmeasured range. | |
| ADR-191: Neer’s 2026-10-06 ideas: the four web tools, watches, the repo layout and the hardware line | the four FusionSpace web tools (Motor Finder, Charge, Window, Muster) are rebuilt as library code and app screens in M9.6, after mobile; Motor Finder’s scraper stays a hosted service whose API hpr keeps reading. hpr stays one repository with several workspaces, split only by named triggers. Watches wait until after mobile, with the phone as hub. The hardware line is ordered by regulation, and active-control firmware or hardware waits for Neer’s export-control answer. | |
| ADR-192: Neer’s 2026-10-06 follow-up: the best product over the first, no legacy contracts, and three export tiers | Neer’s answers to ADR-191’s three asks. The old web tools get no more work and constrain nothing: Motor Finder’s API is not a contract, and hpr’s stock service is designed fresh even if release 0.1’s reader breaks. The best product outranks the first release. Export control sorts the work into three tiers (public, held, never): the simulator and its control models stay public; firmware or hardware that moves a control surface is held off GitHub and out of cloud AI tools until a ruling; target guidance, thrust vector control and lifted GPS caps are never built. | |
| ADR-193: Neer’s 2026-10-07 control scope: drag-only airbrakes, roll-only canards and fin tabs | hpr’s active control, simulated or built, is limited to airbrakes that only add drag and to canards and tail-fin tabs that only roll the rocket, stable with every surface inert and with any one surface stuck. The controller has two commands, brake deployment and roll, through a fixed mixer, so nothing can command pitch or yaw. Active pitch and yaw control joins the never tier, and the backlog’s thrust vector control and active fins leave it. Roll tabs come before roll canards, because a tail spanning as much as the canards removed most of their roll in NASA’s supersonic tests. M6.5 becomes roll control (queued before the flight computer logic); new M13.6 holds the control hardware for a ruling. Hardware stays in the held tier. | |
| ADR-194: Neer’s 2026-10-07 field tools: checklists, equipment and ground tests | Neer’s launch-field ideas land in three places. Release 0.4 gains M6.8, a field kit in the library and the CLI: a launch checklist and guide built from the rocket’s configuration, a check of each altimeter’s settings against the simulated flight, and a ground-test log that M6.7’s charge sizing reads. M6.7 is tightened by the one measured source found (Fetter, 2025): a packed bay needed several times the calculated charge to separate, so a packed bay is sized to his measured outcomes, never from the empty-bay pressure; the bulkhead load takes the empty-bay peak’s high side; the charge grows with altitude, and above 20,000 ft no black-powder size is printed. After the mobile apps, M9.7 adds an equipment register and a cross-vendor frequency board. M13.7 is a ground-test bench (a pressure logger and a wired firing box), in the public tier. The roadmap’s budget rises to 36,000 bytes. | |
| ADR-195: Neer’s 2026-10-07 guides: rocketry explained, illustrated and live | Neer’s guides to all of high-power rocketry become M0.7, Rocketry explained, a section of the existing docs site in four increments. M0.7a, right after release 0.1, sets the format and writes four guides on the largest gaps that hpr already models: stability, fin flutter, drag through Mach 1, and how far to trust a simulation. M0.7b, before release 0.4, adds recovery, wind and rail exit, and motors. M0.7c, after release 0.5, makes the figures live, run by hpr itself in the browser. M0.7d, after 1.0, covers the rest of the hobby, mostly by linking out. Every number a guide shows comes from hpr or a cited source, every figure is checked for clipping, and nothing is copied from copyrighted or share-alike sources. The roadmap’s budget rises to 38,500 bytes. | |
| ADR-196: Neer’s 2026-10-07 product guides: each product, illustrated | Each of the suite’s products gets a guide on the docs site: a landing page and an illustrated tour that ends on a public real flight, in M0.7’s format and checks. Every picture is made by a command CI reruns, never taken by hand: CLI output as terminal figures, plots from hpr, app screens from end-to-end tests, with phone and watch captures checked against the device’s safe area. M0.8a writes the simulator’s guide after M0.7a; from release 0.2 on, the release checklist requires that release’s guide, read by Neer; each line after 1.0 ships its guide with its first milestone. The roadmap’s budget rises to 40,500 bytes. | |
| ADR-197: Neer’s 2026-10-07 parts catalog: commercial parts, and a catalog of hpr’s own | OpenRocket’s catalog, bundled since M5.5, stays as the base. M5.6 adds a catalog of hpr’s own in four increments. M5.6a adds the format, where every value carries its source and date, plus hpr parts search and a parts list to buy from. M5.6b adds parachutes and recovery hardware, each Cd stored with its reference area and a descent rate given as a range, the flattering side pinned. M5.6c adds motor hardware and rail buttons, never counting a mass twice. M5.6d adds more airframe makers and electronics, masses carried as ranges. Only facts go in, each cited; no vendor text or photos are copied. M9.1’s design editor gets a part picker and the parts list. M5.6a comes after release 0.5, ahead of M8.2. The rest comes before 1.0, with M5.6b ahead of M8.1’s parachute sizing. The roadmap’s budget rises to 43,000 bytes. | |
| ADR-198: Neer’s 2026-10-07 project name: Eridanus, its stars, and the design system’s catch-up | the project is Eridanus, FS-ERI, and the repository becomes nrdptel/fusionspace-eridanus when Neer renames it. Each product takes one of Eridanus’s stars as its internal name: the simulator is Achernar (FS-ACHERNAR), the app Zaurak, the flight analyzer Angetenar, avionics Sceptrum, the competition kit Acamar, the motor designer Rana and the recovery designer Cursa. External names don’t change: the program is still hpr-sim, the command hpr. The designation FS · SW · TOOL 005, which the design system lists as retired, becomes FS-ACHERNAR · SW · TOOL 001, and files stamped with the old one still read. GitHub doesn’t redirect a project site after a rename, so the rename comes before release 0.1 publishes anything. M10.1d7 and M10.1d8 do the code side, and catch up with the 21 design-system commits since the pin. | |
| ADR-199: Neer’s 2026-10-07 public name: FusionSpace HPR, on every product and package | the suite’s public name is FusionSpace HPR, and each product is “FusionSpace HPR ·” and its role: Sim, Analyzer, Competition Kit, Motor Designer, Recovery Designer, Avionics, with the app and its store listing called FusionSpace HPR. Packages carry the brand: PyPI fusionspace-hpr imported as fusionspace.hpr, crates fusionspace-hpr and fusionspace-hpr-*, npm @fusionspace/hpr. The command stays hpr, and its help, version and banner open with FusionSpace HPR. Stamps read FusionSpace HPR 0.1.0 · FS-ACHERNAR · SW · TOOL 001, and files stamped by hpr-sim still read. The docs move to hpr.fusionspace.co. M10.1d9 renames everything before release 0.1 publishes, because a published name is permanent. Star names stay internal codes. |
The roadmap
The roadmap is the ordered plan of work. It is split into phases, and each phase into
milestones. A milestone’s id is M, a topic number, a dot and its place in that topic. The topic
is not the phase: 0 is foundations, 1 physics, 2 validation, 3 file formats, 4 library interfaces,
5 online data, 6 Monte Carlo and optimization, 7 flight logs, 8 design help, 9 the app, 10 releases,
11 motor design, 12 parachute design and 13 avionics. Phases
mix topics, so M2.3, the real-flights milestone, sits in Phase 1 beside
M1.8, the second aerodynamics milestone. A milestone too big to ship at once is split
into increments with a letter, and sometimes a digit after it, such as M2.1b2. Each one
ends with done when conditions, and it is checked off only when all of them hold. Every
milestone has a row in the table below.
The roadmap file holds open work only. A queue at its top sets the order of work, and the
project’s automated checks fail if the running progress notes name any other milestone as current.
When a milestone is finished, cargo xtask records moves its entry, word for word, to
the archive of finished work, which opens with an index of one line per milestone.
The work runs in this order: the physics and its validation first, then the ways to use it and the analysis tools, with a release at each product boundary, then the app as release 1.0, then the suite’s new product lines one at a time (ADR-162, the suite and its releases).
- Phase 0: Foundations: the workspace, the reference library, the lessons from Loft and this site.
- Phase 1: Physics core, with validation interleaved: the models on this site, then transonic and supersonic aerodynamics, staging, and flight outputs such as the stability margin, with comparisons against RocketPy, OpenRocket and real flights along the way.
- Phase 2: Library surfaces and interop: a simpler interface, a command-line tool, Python bindings, and design files in and out.
- Phase 3: Uncertainty, optimization, challenges: Monte Carlo runs and design optimization for competitions.
- Phase 4: More formats and embeddings: RockSim, RASAero and RocketPy files, and use from C and the web.
- Phase 5: Flight data and forensics: reading flight logs and taking a flight’s readings off them (planned to work on its own, with no design file and no simulation) and then comparing a real flight with its simulation.
- Phase 6: Design experience: a design assistant for apps to build on.
- Phase 7: UI, 3D, web, mobile: a desktop app, 3D flight replay, a web app and mobile, started once release 0.4 is out.
- Phase 8: Releases: 0.1 the simulator (the library, the command line and Python), 0.2 the flight analyzer, 0.3 accuracy and diagnosis, 0.4 the competition kit, 0.5 an app preview with a 3D replay that draws the simulated flight as a “ghost” beside the real one, and 1.0 the app with its editor.
- Phase 9: The suite’s new lines: after 1.0, one at a time: designing experimental solid motors, then custom parachutes, then avionics (a test bench for flight computers, a ground station, a GPS tracker), then hybrids and liquids. Pad day on a phone (M9.4, mobile) comes after the parachute designer and before avionics.
What is done so far, and what is not, is on Start here. Ideas that are not on the roadmap yet, each with a tier, are in the ideas backlog.
Every milestone
Each milestone and increment has a row here, so a milestone label on any page leads to a line of
plain words. The label in the first column opens its phase in the roadmap, or in the archive once
it is done, where its full plan and its done when conditions are. The rows, their statuses and
those links are written by cargo xtask records; only the plain words are written by hand, and
the site check fails if a row is missing or its status disagrees.
| milestone | what it covers | status |
|---|---|---|
| M0.1 | The code workspace, the automated checks (CI) and the licenses | done |
| M0.2 | The library of published sources and reference programs, each pinned so results can be reproduced | done |
| M0.3 | The lessons from Loft, the project that came before this one | done |
| M0.4 | This documentation site | done |
| M0.4a | The site itself, and the checks on its links and labels | done |
| M0.4b | The model pages’ In short, Accuracy, the Glossary and Checking a claim | done |
| M0.4c | Getting started, and How a flight is simulated | done |
| M0.4d | Publishing the site and the API reference on the web | done |
| M0.4e | A new reader answers ten questions from the site alone, and what they find unclear is fixed | done |
| M0.5 | Leaner bookkeeping: one file per decision record, a roadmap of open work in queue order, shorter status notes, these tables generated rather than hand-edited, and reviews while CI runs (ADR-144) | done |
| M0.5a | One file per decision record, with a generated index | done |
| M0.5b | A roadmap of open work only, with an explicit queue order, and an archive of what is done | done |
| M0.5c | A short status file, with budgets the checks enforce | done |
| M0.5d | Indexes and tables like this one generated, not hand-edited | done |
| M0.5e | Reviews that run while the automated checks (CI) run | done |
| M0.5f | A lighter start to each working session | done |
| M0.5g | The local checks that need the private reference data run on their own when physics code changes | done |
| M0.5h | The checks on the planning files rewritten to enforce the new rules | done |
| M0.5i | The first 20 working sessions after this milestone, measured against those before it | done |
| M0.6 | The FusionSpace product system: the docs site, the command line, its exports and its plot made to the design rules of FusionSpace, the family of tools hpr-sim belongs to, and the pages in US spelling (ADR-164) | done |
| M0.6a | The docs site | done |
| M0.6b | The CLI and exports | done |
| M0.6c | The plot | done |
| M0.6d | US spelling, no em dashes | done |
| M0.6d1 | The check, and the pages | done |
| M0.6d2 | The crates | done |
| M0.6d3 | The crates’ em dashes | done |
| M0.6e | US names | done |
| M0.7 | Rocketry explained: guides to high-power rocketry on the docs site, illustrated, then live (ADR-195) | not yet done |
| M0.7a | The format and four guides | not yet done |
| M0.7b | Recovery, wind and motors | not yet done |
| M0.7c | Live figures | not yet done |
| M0.7d | The rest of the hobby | not yet done |
| M0.8 | Product guides: a landing page and an illustrated tour for each product, every picture generated (ADR-196) | not yet done |
| M0.8a | The simulator’s guide | not yet done |
| M1.1 | Vectors and rotations, frames, the Earth’s shape and gravity | done |
| M1.2 | The atmosphere and wind | done |
| M1.3 | Solid motors: thrust curves, motor files, and mass through the burn | done |
| M1.4 | The rocket’s design and its mass properties | done |
| M1.4a | Part shapes and materials, and each part’s mass, center of gravity and inertia | done |
| M1.4b | The design tree: where parts sit, motor configurations and design checks | done |
| M1.5 | Aerodynamics below the speed of sound | done |
| M1.5a | Normal force and center of pressure | done |
| M1.5b | Drag, and tables that override it | done |
| M1.6 | The six-degree-of-freedom flight | done |
| M1.6a | The time integrator, and how events such as burnout and apogee are found | done |
| M1.6b | The rigid-body flight: the rail, the equations of motion and the phases of a flight | done |
| M1.7 | Recovery | done |
| M1.7a | Parachutes, and the descent under them | done |
| M1.7b | Streamers and tumble recovery | done |
| M1.7c | Separated bodies, each flown to its own landing | done |
| M1.8 | Transonic and supersonic aerodynamics, damping, and overriding the aerodynamics; closed with its drag target missed, which moves to M1.14 (ADR-143) | done |
| M1.8a | The normal force and center of pressure through Mach 1 | done |
| M1.8b | Drag through Mach 1: the transonic rise and supersonic wave drag | done |
| M1.8b1 | The drag of noses, shoulders and steps through Mach 1, against NASA’s Arcas Robin wind tunnel | done |
| M1.8b2 | Drag against RASAero II’s from Mach 0.1 to 2 | done |
| M1.8b3 | The drag of a boattail faster than sound, and the base behind it | done |
| M1.8c | Roll from canted fins, roll damping, and pitch and yaw damping (kept as each part’s local-flow damping) | done |
| M1.8d | Tables that override the normal force and center of pressure, read from RASAero II | done |
| M1.8e | The body’s normal force faster than sound, which slender-body theory underestimates past Mach 3; closed with its 15% target missed for the body alone (ADR-040, ADR-143) | done |
| M1.8e1 | The second-order shock-expansion method: the lift a body’s cylinder carries behind its nose faster than sound, checked against its report’s tables | done |
| M1.8e2 | The body’s supersonic normal force in a flight: the nose and its cylinder, joined to the subsonic model | done |
| M1.8e3 | Faster than sound: the blend into the shock-expansion method now starts at the exact Mach where the method starts to hold, not rounded to a 0.05 step | done |
| M1.8e4 | Faster than sound: a boattail, and a tube behind it, take their share of the body’s normal force from the shock-expansion method | done |
| M1.8e5 | Faster than sound: how much of the Arcas Robin’s remaining gap each missing effect (crossflow, the blunt tip, and others) explains, measured before modeling | done |
| M1.8e6 | The size of crossflow lift at every speed (Jorgensen) and a boattail’s measured share faster than sound (Washington and Pettis), the causes that measurement ranked first, in flight | done |
| M1.8e7 | Faster than sound: blunt and vertical nose tips (power-series, Haack and elliptical noses) by a Newtonian cap ahead of the shock-expansion method | done |
| M1.8e8 | Faster than sound: the lip behind a boattail, so that the committed Arcas Robin designs fly the shock-expansion method | done |
| M1.8e9 | Faster than sound: a bound on the boattail angle, footnote 8’s size pinned by hand, and the Arcas Robin wind tunnel’s 15% target judged | done |
| M1.8e10 | A lip’s shelter weighed as the drag buildup weighs it, instead of switching the whole body’s model at a threshold, and the size of every switch that remains | done |
| M1.8e11 | Cone slopes from 24° to 30°, from NASA SP-3007, where TN 3527’s own chart stops | done |
| M1.8e12 | What a blunt tip’s handover cap is worth once the cone slopes reach 30°, and what stops it moving there | done |
| M1.8e13 | What puts a marched answer at the mercy of the mesh: the surface pressure crossing its tangent cone’s, counted and told apart from a reduced element | done |
| M1.8e14 | Where the method stops marching a flare, bisected over Mach, and what the edge is made of | done |
| M1.8e15 | What a step in radius still switches, how big it is, and what a model of one would need | done |
| M1.8e16 | A blunt tip’s handover moved past 24°, once the march has a rule for the loading through a crossing (the rest of what M1.8e13 used to be, renumbered so the flare and the step keep their ids). Blocked, and deferred above Mach 4 with issue #108 (ADR-143); the vertical tip’s error goes to M1.14d below Mach 2.5 and M1.14h above | blocked |
| M1.8e17 | A flared body flown through the method where its shock is attached, with nothing jumping across that boundary as the model changes (the second of the three the old M1.8e14 splits into) | done |
| M1.8e18 | NASA TN D-4865 model 2’s readings committed, and what a marched flare is worth (the third of the three the old M1.8e14 splits into) | done |
| M1.8e19 | The band of near-flat flares the march used to refuse, which took the whole body off the method as a shape crossed it (found by M1.8e17); now read by the generalized method | done |
| M1.9 | Staging, clusters and air starts, for COTS motors | done |
| M1.9a | Motors lit at their own times, and a sustainer that flies on after a powered separation while the booster lands on its own, with tests for the ignition times, the mass step, the order of events and a trigger that never fires (ADR-074, Staging) | done |
| M1.9b | Several motors in one mount, their thrusts and masses summed, a motor out turning the rocket as a hand calculation predicts, and a .ork file’s clusters read with every tube where OpenRocket puts it (ADR-075, Clusters) | done |
| M1.9c | A two-stage and a cluster design from .ork files, each within the per-case tolerance of OpenRocket’s flight: every flight of each within 5% in apogee and largest speed (ADR-076, Staging) | done |
| M1.10 | Flight outputs: the stability margin over the flight, the best ejection delay, the peak dynamic pressure, fin flutter and the landing point | done |
| M1.10a | A flight’s peaks, its apogee with the height it counts from, its static and in-flight stability margins from the rail exit to apogee, each motor’s optimum ejection delay and each landing’s latitude and longitude, with None for what didn’t happen (ADR-077, Flight metrics) | done |
| M1.10b | Fin flutter speed and margin from a cited primary source, matching its worked example (ADR-078, Fin flutter) | done |
| M1.10c | Flights written as CSV, JSON, KML and GeoJSON files (Parquet optional), checked by schema and by parsing | done |
| M1.10c1 | A recording written as CSV or JSON, and the flight path with its landings as GeoJSON (checked against the published schema) or KML (checked by parsing) (ADR-079, Exporting a flight) | done |
| M1.10c2 | A recording written as Parquet, behind a cargo feature, and read back the same by Apache’s own Parquet library (ADR-080, Exporting a flight) | done |
| M1.11 | Ejected nose cones, body sections and payloads, each flown to its own landing | done |
| M1.11a | The airframe parting at any joint or around a payload, every piece landed under its own parachute (ADR-085, Recovery: ejected pieces) | done |
| M1.11b | The push of an ejection charge on the pieces, and a tumbling piece (ADR-086, Recovery: ejected pieces) | done |
| M1.12 | Payload mass that moves, or is released, during the flight | done |
| M1.12a | Ballast or a payload that slides along the airframe in flight, with the mass properties, the margin and the equations of motion following it (ADR-087, Moving mass) | done |
| M1.12b | Ballast or a payload released in flight, the rest flying on and the part falling on its own (ADR-088, Released mass) | done |
| M1.13 | Pods: bodies mounted beside the airframe, with or without motors | done |
| M1.13a | A pod’s mass: one pod repeated around the axis, each copy with its parallel-axis term, a motor in a pod one per pod (ADR-089, Pods) | done |
| M1.13b | Pods read from a .ork file | done |
| M1.13b1 | Pods of body components read from a .ork file, placed as OpenRocket 24.12 places them (ADR-090, .ork: Pods) | done |
| M1.13b2 | Pods of no length, which hang fins or a lug off the axis, and an empty pod set, read from a .ork file (ADR-091, .ork: Pods) | done |
| M1.13c | Pod aerodynamics from a cited source, and a pod design against OpenRocket | done |
| M1.13c1 | Pods fly: each pod’s parts with Barrowman’s normal force and their own drag, once per pod (ADR-092, aerodynamics: Pods) | done |
| M1.13c2 | A pod design with bodies and fins against OpenRocket, the limits of both codes’ pod models stated (ADR-093, aerodynamics: Pods) | done |
| M1.14 | Accuracy inside the operating envelope: the core band (Mach 0 to 2.5) first, then the extended band (Mach 2.5 to 3.5) in M1.14h, at angles of attack up to 15° (higher angles are M1.14e’s); real flights within the 5% apogee target, and at least as accurate as OpenRocket on the same flights (ADR-143) | not yet done |
| M1.14a | Four warning flags, each tested at its edge. Beyond the validated range: faster than the fastest public whole-flight reference, any committed comparison of a public flight against an independent reference (OpenRocket’s example at Mach 1.147 today; private flights never set it). At high angle of attack: above 15° more than 1 s after leaving the rail, at any Mach. Outside the core band: past Mach 2.5. Beyond the envelope: past Mach 3.5. And the aerodynamics page split by Mach band | done |
| M1.14a1 | Envelope flags | done |
| M1.14a2 | Drag issue warnings: issues #67, #68, #70, #72 and #222 warn by number when a flight meets their Mach and shape conditions (ADR-180) | done |
| M1.14a3 | Stability issue warnings: issues #87, #120, #121 and #172, where stability reads high, warn by number | done |
| M1.14b | New references from Mach 1.5 to 2.5: a public database of flights with simulator predictions, free-flight and measured supersonic coefficients, NASA’s six-degree-of-freedom check cases, and the validation uncertainty of each real flight | not yet done |
| M1.14c | The normal force and drag near Mach 1, from 0.8 to 1.2 | not yet done |
| M1.14d | Faster than sound, Mach 1.2 to 2.5. First the four shapes that fall back to slender-body theory and so read more stable than they are: a step in a body’s radius (issue #87), a flare behind a boattail too long for its wake (issue #120), a pointed tip steeper than 30° (issue #121) and a vertical tip steeper than its cap. Then drag, where hpr reads 5.1% to 14.9% below RASAero II on RocketPy’s Calisto rocket, and the body-alone misses M1.8e left from Mach 1.5 to 2.3 | not yet done |
| M1.14e | Large angles of attack: what the legal 20 mph wind costs, and a high-angle model if it costs more than 1%; how long the first moments off the rail stay steep, which tests the 1 s the high-angle flag allows; and the issues about high angles | not yet done |
| M1.14f | Missing physics, ranked: misalignments, airframe drag under a parachute, base drag with the motor burning, gusts, parachute opening loads and more | not yet done |
| M1.14g | Generated figures on every accuracy and aerodynamics page, each with its reference and the error shown | not yet done |
| M1.14h | The extended band, Mach 2.5 to 3.5, after the core band: each fixed or re-measured in a decision record. The four switches’ errors as measured at Mach 3, where the center of pressure moves aft and the rocket reads more stable; the near-flat flare’s step at Mach 2.90 to 2.95 (issue #108), which way it errs not yet measured; and M1.8e’s body-alone row at Mach 2.96, 16.9% high in its normal-force slope, which tends toward the conservative side on a finned rocket, whose center of pressure then reads forward | not yet done |
| M2.1 | The validation harness, and comparisons with RocketPy | done |
| M2.1a | The harness itself: cases, reference data, tolerances and reports | done |
| M2.1b | Whole flights against RocketPy, with both codes given the same drag | done |
| M2.1b1 | The script that flies RocketPy’s example rockets from pad to landing, as the reference | done |
| M2.1b2 | hpr’s whole flights compared with that reference | done |
| M2.1c | The same cases flown with each code’s own drag, a CI job, and regenerating references | done |
| M2.1c1 | A CI job that checks every case against its stored reference, and a workflow, run only by hand, that regenerates the references | done |
| M2.1c2 | The same cases flown with each code’s own drag | done |
| M2.1d | The time-series comparison, and where a rocket goes in wind (issue #50, why hpr turned into the wind less) | done |
| M2.1d1 | Each whole flight’s height and speed, compared over time with RocketPy’s | done |
| M2.1d2 | Juno III, Calisto and Bella Lui in still air, as committed cases to measure the wind against (issue #50, why hpr turned into the wind less) | done |
| M2.1d3 | Why hpr turned into the wind less than RocketPy (issue #50): RocketPy’s equations, corrected, and hpr’s body lift | done |
| M2.2 | OpenRocket as a reference program, and a corpus of designs to compare; closed with M2.2f, L19’s tube-fin bar missed and pinned | done |
| M2.2a | Each design’s structure (every stage, no motor): mass, center of mass and inertia against OpenRocket’s | done |
| M2.2b | OpenRocket’s mass conventions and roll inertia, split into M2.2b1 to M2.2b5 below; the stored results moved from the third to the fourth when ADR-062 split the fins off, and to the fifth when ADR-063 split the packed parts off; rolled up in ADR-101 | done |
| M2.2b1 | What a .ork leaves unsaid (a wall or shoulder of no thickness, no thickness written, no material) read as OpenRocket reads it, and which override wins | done |
| M2.2b2 | Fins and rail buttons against OpenRocket: where the roll inertia’s gap comes from, how each fin section is weighed, and where a rail button sits | done |
| M2.2b3 | Packed parts (parachutes, streamers, shock cords, mass components) against OpenRocket: the size one takes when its file writes none, and a mass override on one that weighs nothing | done |
| M2.2b4 | Motor clusters, fin fillets and the parts kept unread | done |
| M2.2b5 | Stored results in a .ork used as a reference only when they are current and plausible | done |
| M2.2c | The motors OpenRocket flies, for the configurations held back for want of a thrust curve, split into M2.2c1 and M2.2c2 below by ADR-066 | done |
| M2.2c1 | Every curve hpr flies integrated as OpenRocket 24.12 integrates it, to the milestone’s 0.1% in total impulse | done |
| M2.2c2 | The curves the reference library embeds, and the configurations held back for want of one, supplied from OpenRocket’s own motor database by ADR-067 | done |
| M2.2d | Flights to apogee on the public designs, against OpenRocket, split into M2.2d1 and M2.2d2 below by ADR-068 | done |
| M2.2d1 | OpenRocket 24.12 flies the public designs; what each of its summary words measures is written down for that version, and other versions’ are withheld; a metric for an event that never happened is never scored | done |
| M2.2d2 | hpr flies the configurations of that record it can fly, in a report against OpenRocket’s apogee, largest speed and stability margin (ADR-069, results) | done |
| M2.2e | The corpus, with a hypothesis for every apogee miss over 5%, split into M2.2e1 to M2.2e10 below by ADR-070, ADR-072, ADR-094, ADR-095, ADR-098 and ADR-100 | done |
| M2.2e1 | The flight report adds how far hpr’s mass and center of mass are from OpenRocket’s, at launch and as the rocket leaves the rod (ADR-070, results) | done |
| M2.2e2 | OpenRocket flies the private designs, kept out of the repository; only counts are published (ADR-071, results) | done |
| M2.2e3 | hpr flies the private designs, in a report of anonymised ids that publishes differences, never a design’s values: 17 flights of 4 of 12 designs, so 9 designs with the public report’s 5 (ADR-072, results) | done |
| M2.2e4 | A written cause for every apogee more than 5% from OpenRocket’s, sized by OpenRocket’s own flight without it: four of the five within 5% after, the fifth +7.80% with the no-drag part removed from both programs (ADR-073, results) | done |
| M2.2e5 | A tilted launch rod flown as OpenRocket records it: its angle from the vertical and the compass bearing it leans toward, checked on four public probe designs (bearing at apogee within 0.03 degrees, the tilt’s apogee loss within 0.27 percentage points) and adding one private design, 15 in all (ADR-094, results) | done |
| M2.2e6 | The single override flag older OpenRocket files use for a part and everything inside it, read as OpenRocket 24.12 reads it, measured on eleven probe designs and held by a test; one more private design flies, 16 in all. Not met for the second design the flag held: it also waits on a stage separation hpr can’t fly (#184) (ADR-095, results) | done |
| M2.2e7 | Fin fillets and an inner tube whose automatic radius has nothing to take, read as OpenRocket reads them, so that the two private designs they hold back fly (#174). Measured on 21 new probes: the fillets’ mass and center of mass to 1e-15, and every part inside a nose cone but one packed mass component (#186) at OpenRocket’s mass to 1e-14 and station to 1e-15. Both designs fly, 18 designs compared across both reports, of the 20 M2.2e10 needs. The one supersonic flight climbs 13.60% higher than OpenRocket’s; on OpenRocket’s own drag it is +1.11%, so its cause is in the drag (#222) (ADR-096, ADR-097, results) | done |
| M2.2e8 | Tube fins whose radius OpenRocket works out from the body, resolved as OpenRocket 24.12 does (#133). Measured on 19 new probes: the radius within 1e-15, the tube fins’ mass to 1e-14; OpenRocket’s tube fin example now reads, its mass within 5e-6 of OpenRocket’s. Its roll and pitch inertia are departures: OpenRocket’s roll is larger than any mass inside the ring could have, and its pitch leaves out how far the tubes sit from the axis. The example’s flight moved to M2.2e9 (ADR-098, results) | done |
| M2.2e9 | Tube fin aerodynamics: a cited method for the normal force and drag of tube fins, pinned by tests, so that OpenRocket’s tube fin example flies within M2.2e4’s bar: an apogee more than 5% off has a sized cause. Each tube flies as a ring wing below Mach 0.8. The example’s apogee is 6.95% above OpenRocket’s, sized as hpr’s drag by flying OpenRocket’s; 19 designs compared across both reports (ADR-099, Tube fins) | done |
| M2.2e10 | At least 20 designs across the two reports with all five spreads (apogee, largest speed, margin, mass and center of mass), the bar M2.2e3 had, unchanged. Met by flying a motor whose ignition never comes unlit and loaded, as OpenRocket does, measured on five probes of its two-stage example: one more private design flies, 0.88% above OpenRocket’s in apogee, 20 in all (ADR-100, the rules) | done |
| M2.2f | The two lessons that kept the comparison open. Cases let off a pass-or-fail bar still count in the error statistics, against both references where a rocket has two (L82): tested. A tube fin set’s center of pressure within a quarter calibre of OpenRocket’s (L19): not met, measured and pinned by a test instead, as L18’s is. hpr’s center is 1.07 calibres forward of OpenRocket’s on its Tube fin rocket, and no measurement says which is nearer (ADR-102) | done |
| M2.3 | Comparisons with real flights | not yet done |
| M2.3a | The weather over a launch site read from an ERA5 file, as RocketPy reads it (ADR-081, ERA5 weather files) | done |
| M2.3b | RocketPy’s logged flights flown in their ERA5 weather and compared with the logs (ADR-082, Accuracy: real flights) | done |
| M2.3c | The private designs that have a flight log, flown in their day’s weather, published as statistics. Blocked until 2026-10-04, when none of the private designs was the rocket of any logged flight (ADR-083); the private flight collection added that day has such pairs (ADR-151) | not yet done |
| M2.3c1 | Logged apogees: the private collection’s logged flights against hpr’s and OpenRocket’s predictions | done |
| M2.3c2 | Logged traces: the same flights’ altitude traces, once their logs are read | not yet done |
| M2.4 | A summary of accuracy for the README, and CI that fails on any regression (ADR-084, Accuracy: the census) | done |
| M3.1 | Reading OpenRocket .ork design files | done |
| M3.1a | The container a .ork arrives in, and its design document read whole | done |
| M3.1b | The component tree: parts, shapes, materials, finishes and overrides into a design | done |
| M3.1b1 | What a .ork value means: dimensions OpenRocket works out for itself, tags written under two names, and overrides | done |
| M3.1b2 | The spine: the stages and the body components stacked in them, with their automatic radii marked for the layout to resolve | done |
| M3.1b3 | The parts on and inside the body, with their positions and the dimensions they take from their parents | done |
| M3.1b4 | The three designs of the 76 whose rocket still did not lay out: a radius with nothing to take, and a document with no design | done |
| M3.1c | Motors, recovery, stages, and what OpenRocket last simulated | done |
| M3.1c1 | A design’s motor configurations, the motors in them, and their thrust curves | done |
| M3.1c2 | When each parachute and streamer opens, and when each stage separates | done |
| M3.1c3 | The launch conditions and results of the simulations OpenRocket stored | done |
| M3.1c4 | Pods, parallel stages, and every part, section, tag and attribute hpr does not read, kept for writing the file back | done |
| M3.1d | The corpus and the cross-check against RocketSerializer | done |
| M3.1d1 | Snapshots of what hpr reads from public .ork designs | done |
| M3.1d2 | Every .ork imports without an error, and the cross-check against RocketSerializer | done |
| M3.2 | Writing OpenRocket .ork files | done |
| M3.2a | The writer: a design written back out as a .ork, reading back as the same design (ADR-109, Writing a .ork) | done |
| M3.2b | OpenRocket 24.12 loading and flying the written files, within 0.5% of the original’s apogee (ADR-110, Checked in OpenRocket) | done |
| M3.3 | hpr’s own open design file format | done |
| M3.3a | The document: a design as canonical JSON with its schema, every corpus design through it and back to .ork flying to the same apogee (ADR-111, The hpr design format) | done |
| M3.3b | The zip container (.hprz), the first migration (0.1 to 0.2), the comparison with other formats, and hpr convert and hpr sim taking .hpr and .hprz (ADR-112, The hpr design format) | done |
| M3.3c | TypeScript and Python types generated from the schema, each with a reader that checks a document (ADR-113, TypeScript and Python) | done |
| M4.1 | A simpler interface, with a builder for environments, motors, rockets and flights | done |
| M4.1a | The builder: environments, motors, rockets part by part, and flights, over the crates’ own types (ADR-103, The builder) | done |
| M4.1b | Models of your own: a drag model the flight calls in place of hpr’s, through a trait, with a guide in the API reference (ADR-104, Models of your own) | done |
| M4.2 | A command-line tool | done |
| M4.2a | The command line’s commands, its JSON output and exit codes, shell completions, and looking up motors (ADR-105, The command line) | done |
| M4.2b | Flying a design from the command line (hpr sim), with its recording exported (ADR-106, The command line) | done |
| M4.2c | Checking the validation cases (hpr validate) and converting motor files (hpr convert) from the command line (ADR-107, hpr convert; hpr validate has since left the published hpr for cargo xtask validate --check, ADR-187, what it checks) | done |
| M4.2d | Reading a flight log from the command line (hpr analyze), with no design file: PerfectFlite’s .pf2 first, and liftoff, apogee, the top speed and landing (ADR-108, Reading a flight log) | done |
| M4.3 | Python bindings | done |
| M4.3a | The hpr Python package: the builder’s environment, motor, rocket and flight, designs read from files, recordings as NumPy arrays, and wheels built and tested on three operating systems (ADR-114, Python) | done |
| M4.3b | A drag table on a flight, and RocketPy’s example rocket, Calisto, flown from Python within 3% of RocketPy (ADR-115, Python) | done |
| M4.3c | Drag and wind models written as Python functions, their exceptions raised in Python (ADR-116, Python) | done |
| M4.5 | Fly my .ork: OpenRocket’s example designs fly as saved in hpr sim, with their recovery, offline after one motor download (ADR-144); Base drag hack’s E12-4 not met (M4.5o) | done |
| M4.5a | Parachutes and streamers from a .ork flown, with their triggers (issue #240) | done |
| M4.5b | A missing motor fetched from ThrustCurve and kept, and the exact command to fetch it printed when offline | done |
| M4.5c | Design checks that warn, with a cited tolerance, on fits builders make every day, and refuse only impossible ones | done |
| M4.5d | Output a person reads: configurations by name, results in sentences, the summary led by margin, apogee and rail exit speed | done |
| M4.5e | hpr sim --plot: a flight’s altitude, speed and acceleration drawn as an SVG figure | done |
| M4.5f | How-to guides: fly your .ork, pick a motor, check stability for a certification flight | done |
| M4.5g | Then unpowered separations, freeform fins and several separations, in order of how many designs each holds back | done |
| M4.5g1 | A powered separation in hpr sim | done |
| M4.5g2 | Several separations | done |
| M4.5g3 | An unpowered separation before apogee | done |
| M4.5g4 | Freeform fins | done |
| M4.5h | A part’s drag override | done |
| M4.5i | A powered pods example | done |
| M4.5j | The CLI’s corpus count | done |
| M4.5k | A ring around its tube | done |
| M4.5l | A packed part wider than its bore | done |
| M4.5m | Parallel booster staging | done |
| M4.5n | Pods–powered’s first configuration | done |
| M4.5o | Base drag hack’s E12-4: an elliptical nose’s subsonic drag taken from Hoerner’s measurement and pinned by a test; the E12-4 stays 7.80% above OpenRocket’s apogee, so the 5% bar is not met (ADR-173) | done |
| M4.6 | Monte Carlo from the CLI and Python: apogee and landing spreads without writing Rust | done |
| M4.6a | hpr mc | done |
| M4.6b | Monte Carlo in Python | done |
| M5.1 | The online layer, with an on-disk cache for working offline | done |
| M5.1a | The cache, its freshness rule and an offline mode that never fetches, tested with a hand-written sample response (ADR-117, Online data and the cache) | done |
| M5.1b | The HTTP transport, with rustls, behind a cargo feature, and the platform’s cache folder, tested against a server on the loopback address (ADR-118, Online data and the cache) | done |
| M5.2 | Weather forecasts, turned into atmosphere and wind profiles | done |
| M5.2a | A launch site’s weather from Open-Meteo, forecast or archived, as a sounding: the ground and the pressure levels above it (ADR-119, Launch-day weather) | done |
| M5.2b | Weather-balloon soundings from the University of Wyoming’s archive, as a sounding: the ground and every level above it (ADR-120, Weather-balloon soundings) | done |
| M5.2c | NOAA’s GFS and RAP forecasts from NOMADS, as a sounding: a small GRIB2 cut around the site, read by hpr’s own decoder and checked value for value against ecCodes (ADR-121, NOAA forecasts: GFS and RAP) | done |
| M5.2d | Weather files you download, and the hpr weather command: the command done in M5.2d1; NOAA’s whole files in M5.2d2, complex packing and M5.2d3, JPEG 2000 | done |
| M5.2d1 | hpr weather: a launch site’s profile from Open-Meteo, a Wyoming sounding, GFS, RAP or an ERA5 file, fetched, from the cache, or from a saved answer (ADR-122, The command line) | done |
| M5.2d2 | NOAA’s whole GRIB2 files: complex packing, checked against ecCodes on every value of a whole GFS file (ADR-123, A whole GFS file) | done |
| M5.2d3 | NOAA’s whole GRIB2 files: JPEG 2000, checked against ecCodes on four public RAP fields (ADR-124, Files in JPEG 2000) | done |
| M5.3 | Launch-site data: magnetic declination in M5.3a, ground elevation in M5.3b, distances between places and a user’s elevation file in M5.3c | done |
| M5.3a | Magnetic declination from the World Magnetic Model, WMM2025, checked against NOAA’s test values (ADR-125, The magnetic field) | done |
| M5.3b | A launch site’s ground elevation from Open-Meteo, cached so it works offline after the first lookup (ADR-126, A launch site’s elevation) | done |
| M5.3c | Distance and bearing between two places on the WGS 84 ellipsoid, and a site’s elevation from a GeoTIFF file the user gives; split in two (ADR-127) | done |
| M5.3c1 | Distance and bearing between two places on WGS 84, checked against Karney’s published set of 500,000 geodesics (ADR-127, Geodesy) | done |
| M5.3c2 | A launch site’s elevation from a GeoTIFF file the user gives, checked against GDAL’s reading through rasterio on seven files and a whole USGS tile (ADR-128, A launch site’s elevation) | done |
| M5.4 | Motor stock and prices from motor.fusionspace.co, joined with ThrustCurve.org’s motors; split in three (ADR-129) | done |
| M5.4a | The motor finder’s files (its build, every motor, those in stock, the vendors, one motor’s page) read through the cache, so they work offline, each carrying the credit the site asks for (ADR-129; its CC BY 4.0 credit, ADR-145; Motor stock and prices) | done |
| M5.4b | ThrustCurve.org’s search and a motor’s thrust curve through the cache, and the motors in stock matched to ThrustCurve.org’s by name, with a report of the misses: 282 of 282 matched (ADR-130; the tests’ stand-in searches, ADR-145; Motor stock and prices) | done |
| M5.4c | hpr motors search: motors in stock by class and price, from the network, a saved list or offline, with both sources’ credit on every list (ADR-131, Motors you can buy) | done |
| M5.5 | A catalog of parts: OpenRocket’s parts files, looked up by maker and part number, and parts from them in a design; split in two (ADR-132) | done |
| M5.5a | The 16 .orc parts files OpenRocket ships, bundled and read, every part held to OpenRocket’s own reading: 3,449 parts, 17,911 values to the bit, the rest counted with their causes (ADR-132, OpenRocket .orc parts catalogs) | done |
| M5.5b | Catalog parts in the builder, and a rocket of them flown: all 3,449 parts built and held to what OpenRocket builds, the departures counted with their causes (ADR-133, parts from a catalog) | done |
| M5.6 | A catalog of hpr’s own | not yet done |
| M5.6a | Format, search and a parts list | not yet done |
| M5.6b | Parachutes and recovery hardware | not yet done |
| M5.6c | Motor hardware and rail buttons | not yet done |
| M5.6d | More makers and electronics | not yet done |
| M6.1 | Monte Carlo runs and sensitivity; split in four (ADR-134) | done |
| M6.1a | Seeded dispersion of mass, center of mass, drag, motor, wind, rail and recovery delays; each flight the same whatever the run’s size or thread count; failed flights counted; the apogee’s spread (ADR-134, Monte Carlo dispersion) | done |
| M6.1b | Landing ellipses holding a chosen share of the landings, checked against normal spreads with known answers; the next flight’s ellipse; the landings each holds counted (ADR-135, Landing ellipses) | done |
| M6.1c | Sensitivity analysis, Morris screening and Sobol’ indices, checked against functions with known answers within their own standard errors (ADR-136, Sensitivity analysis) | done |
| M6.1d | 10,000 flights of a Level 2 rocket (one on a J, K or L motor) in 10 s or less, timed and recorded: 3.0 s for Valetudo, 9.4 s for a rocket past Mach 1.6, a run’s flights sharing one layout and one supersonic table (ADR-137, How long a run takes) | done |
| M6.2 | Design optimization; split in five (ADR-138) | not yet done |
| M6.2a | CMA-ES over continuous design variables, held to four test functions’ known minima and to pycma, its author’s implementation; a rocket’s ballast and body length found for a 3,048 m apogee and a 2.2-calibre margin, and checked by flying it again (ADR-138, Optimization) | done |
| M6.2b | Discrete choices (a motor, a catalog part) and limits such as a minimum stability margin; split in two (ADR-139) | done |
| M6.2b1 | Limits on a design, such as a minimum stability margin: candidates that break one rank below those that don’t (Deb’s rules); held to three test problems whose limited minima are known | done |
| M6.2b2 | Discrete choices (a motor, a catalog part) as whole-number variables, by CMA-ES with margin; held to three mixed test functions’ known minima and to an outside implementation; a motor and a Madcow nose cone chosen for a 3,048 m apogee under margin and rail-exit limits, and checked by flying the winner again (ADR-140, Optimization) | done |
| M6.2c | Several goals at once: NSGA-II finds a Pareto front; held to the known fronts of three standard test problems (ZDT1 to ZDT3) and to an outside implementation (pymoo), and a rocket’s trade-off between apogee and static margin, flown again and checked against CMA-ES (ADR-141, Optimization) | done |
| M6.2d | Bayesian optimization (EGO) for costly flights, split d1, d2 (ADR-142) | done |
| M6.2d1 | EGO: a surrogate (kriging) fitted to the designs tried, and the next design where it expects the most improvement; Branin’s and Hartmann 3’s minima within 1% in 50 evaluations from 20 seeds (ADR-142, Optimization) | done |
| M6.2d2 | EGO on Hartmann 6, a six-variable test function whose local minimum traps M6.2d1’s EGO in 7 runs of 10; one attempt (ADR-142, ADR-144, Optimization) | done |
| M6.2e | Robust designs: a Monte Carlo run inside the optimizer | not yet done |
| M6.3 | Competition rules as files, with scoring, limits and presets | not yet done |
| M6.4 | Airbrakes, with a controller that aims for a target apogee | not yet done |
| M6.5 | Roll control, roll only: tail-fin tabs first, then canards | not yet done |
| M6.6 | Submission packs: the numbers Student Launch and IREC ask for, from one design | not yet done |
| M6.7 | Ejection charges: black-powder size for a bay, always “ground test first” | not yet done |
| M6.8 | Field kit: checklists, the settings check and the ground-test log | not yet done |
| M3.4 | RockSim .rkt files in and out | not yet done |
| M3.5 | RASAero .CDX1 files in and out | not yet done |
| M3.6 | RocketPy scripts and files in and out | not yet done |
| M4.4 | Use from C, and in the browser through WebAssembly | not yet done |
| M7.1 | Reading flight logs from altimeters and trackers, with no design file and no simulation | not yet done |
| M7.2 | The readings a flight gives, each with where it came from, and reconstructing the flight from its log | not yet done |
| M7.3 | A flight against its simulation: residuals, and fitting drag, mass, impulse and wind to the log | not yet done |
| M7.4 | Diagnosing what went wrong in a flight | not yet done |
| M8.1 | A design assistant | not yet done |
| M8.2 | An editing model for apps: commands, undo and stable ids | not yet done |
| M8.3 | CAD interop: parts and designs out to meshes, drawings, FreeCAD and STEP, and meshes or STEP solids in as custom parts, through files only (ADR-144) | not yet done |
| M8.3a | Any part or the whole design written as a watertight mesh in millimeters: STL, 3MF or OBJ | not yet done |
| M8.3b | Dimensioned drawings (SVG, DXF, PDF): fins with bevels, rings, nose profiles and tube cut lists | not yet done |
| M8.3c | A generated FreeCAD script that rebuilds the design as a parametric feature tree, driven by a spreadsheet of its dimensions | not yet done |
| M8.3d | STEP export as solids, through a permissively licensed geometry kernel | not yet done |
| M8.3e | A mesh read in as a custom part: its mass properties computed exactly from the closed mesh and a material, its aerodynamics recognised as a body profile, a fin or a protuberance, or else marked as not modeled | not yet done |
| M8.3f | STEP solids read in as custom parts, once a reader with a suitable license is found | not yet done |
| M8.3g | Warnings for parts printed on a 3D printer: heat limits, layer direction, unvalidated flutter | not yet done |
| M9.0 | Choosing how the app is built, with trial builds | not yet done |
| M9.1 | A desktop app | not yet done |
| M9.2 | 3D flight replay, the real flight beside the simulated one | not yet done |
| M9.3 | A web app that works offline | not yet done |
| M9.4 | Mobile apps | not yet done |
| M9.5 | Optional accounts that save designs and flights and sync them across devices | not yet done |
| M9.6 | Neer’s four web tools (Motor Finder, Charge, Window, Muster) rebuilt as library code and app screens | not yet done |
| M9.7 | Field equipment and frequencies | not yet done |
| M10.1 | Release 0.1: the simulator | not yet done |
| M10.1a | The flight and design fixes | done |
| M10.1b | The data, network and Python fixes | done |
| M10.1c | The release workflow | done |
| M10.1d1 | The release notes and the install pages | done |
| M10.1d2 | The missing warnings and the checklist | done |
| M10.1d3 | The friction and freeform fin warnings | done |
| M10.1d4 | The checklist | not yet done |
| M10.1d5 | The separated parts’ warnings | not yet done |
| M10.1d6 | The unknown signs | not yet done |
| M10.1d7 | The designation and the design pin | not yet done |
| M10.1d8 | The new name’s URLs | not yet done |
| M10.1d9 | FusionSpace HPR | not yet done |
| M10.2 | Release 0.2: the flight analyzer | not yet done |
| M10.3 | Release 0.3: accuracy and diagnosis | not yet done |
| M10.4 | Release 0.4: the competition kit | not yet done |
| M10.5 | Release 0.5: the app preview | not yet done |
| M10.6 | Release 1.0: the app | not yet done |
| M11.1 | A motor of your own | not yet done |
| M11.2 | Experimental solids | not yet done |
| M11.3 | Certified hybrids | not yet done |
| M11.4 | Nitrous blowdown | not yet done |
| M11.5 | Hybrid and liquid design | not yet done |
| M12.1 | Gores | not yet done |
| M12.2 | Opening loads | not yet done |
| M13.1 | Ground station | not yet done |
| M13.2 | GPS tracker logic | not yet done |
| M13.3 | Flight computer logic | not yet done |
| M13.4 | Hardware | not yet done |
| M13.5 | More tracker and flight-computer boards on one firmware | not yet done |
| M13.6 | Control hardware: drag-only airbrakes and roll-only tabs, held for a ruling | not yet done |
| M13.7 | Ground-test bench | not yet done |
Lessons from Loft
Loft was the project that came before hpr-sim. Its mistakes are listed as numbered lessons, such as Loft lesson L18, its made-up transonic drag curve, each with the test that guards against it here, or the milestone that will add one. The list of lessons says what went wrong, where in Loft, and how hpr avoids it.
The lessons these pages name
Each lesson that a page of this site names has a row here. Its label opens its section of the list of lessons, which gives Loft’s evidence and the name of the test that guards it; the last column is the milestone that added or will add that test.
| lesson | what went wrong in Loft, or what the lesson records | guarded by |
|---|---|---|
| L1 | Loft used one constant gravity on a flat Earth, so it read low against RocketPy | M1.1 |
| L2 | Loft treated geometric altitude as geopotential, so its temperature and pressure were off at 11 km | M1.2 |
| L3 | Loft’s atmosphere had four layers, and its last temperature gradient ran on forever: 335 K at 70 km, against 219.6 K | M1.2 |
| L4 | Loft’s air viscosity constants weren’t the 1976 standard’s, 1.3% high at sea level | M1.2 |
| L5 | Loft’s “today’s conditions” kept the standard temperature gradient above the field, with dry air and no sounding temperatures | M1.2 |
| L6 | Loft flew one wind vector; forecast profiles stepped at the lowest level; no gusts | M1.2 |
| L7 | Loft’s fin lift had no compressibility factor, so its slope and center of pressure never changed with Mach | M1.8a |
| L8 | Loft’s fin lift grew in proportion to the fin count, with no correction for 5 to 8 fins | M1.5a |
| L9 | Loft used the conical transition’s center-of-pressure formula for every transition shape | M1.5a |
| L10 | Loft took elliptical fins’ lift from an equal-area trapezoid with the wrong sweep | M1.5a |
| L11 | Loft merged fin sets into one for drag, so the result depended on their order | M1.5b |
| L12 | Loft’s drag used uncited constants, such as a body form factor of 1.95 where Niskanen gives 1.13 | M1.5b |
| L13 | Loft had no power-on base drag relief, which Niskanen’s drag method includes | M1.5b |
| L14 | Loft’s launch-lug drag was uncited, and rail buttons dragged as lugs | M1.5b |
| L15 | Loft gave a bare step in diameter no drag, and shoulder drag jumped to zero as a transition shrank | M1.5b |
| L16 | Loft silently capped the drag coefficient at 10, which hid malformed designs | M1.5b |
| L17 | Loft froze the fins’ leading-edge drag at its Mach 1 value, and gave nose and shoulder pressure drag no Mach term | M1.8 |
| L18 | Loft’s transonic wave drag was an invented curve, never checked against RASAero | M1.8 |
| L19 | Loft put a tube fin set’s center of pressure about 0.9 calibres forward of OpenRocket’s, and left out ring tails (a ring joining the fins’ tips). hpr’s is 1.07 calibres forward, measured and pinned, not within the lesson’s quarter calibre (ADR-102) | M2.2f |
| L20 | Loft flew in 3-DOF: no angle of attack, body lift, damping or roll, and no weathercocking | M1.6b |
| L21 | Loft stepped with RK4 without error control, and never tested that the apogee converges | M1.6a |
| L22 | Loft didn’t locate events exactly: apogee fell on a step, altitude deployments overshot, landings were below ground | M1.6a |
| L23 | Loft let discontinuities such as burnout fall inside steps, and checked its vacuum case to only ±2% | M1.6a |
| L24 | Loft’s simulate() changed its inputs, so a second run of the same flight differed from the first | M1.6b |
| L25 | Loft labelled any early stop “step budget”, even a rocket that never lifted off | M1.6b |
| L26 | Loft’s launch rail had no friction and no button geometry | M1.6b |
| L30 | Loft fixed the staging before the flight, so an apogee or height separation fell back to the burnout, and it never flew the booster | M1.9a |
| L31 | Loft’s clusters sat on the axis only, so a motor out turned nothing, and it sent a mixed cluster to its oracle as copies of the first motor | M1.9b |
| L32 | Loft’s flutter constant was half of NACA TN 4197’s, so its flutter speeds were √2 too high, on the unsafe side, and 7 of its shear moduli had no source | M1.10b |
| L33 | Loft published static margins of ±12 to 15 calibres where the normal-force slope had all but cancelled and the margin meant nothing | M1.10a |
| L34 | Loft counted the opening shock as the peak acceleration, and read thrust spikes low from a finite difference of the speed | M1.10a |
| L35 | Loft used zeros for “never happened”, and never said which height apogee was measured from | M1.10a |
| L36 | Loft’s .eng reader read only the first header, and appended a second motor’s points to the first curve | M1.3 |
| L37 | Loft’s delay parsing lost P (plugged) and lists of delays, and read marker values as seconds | M1.3 |
| L38 | Loft’s impulse class letter was off by one at the top of each band | M1.3 |
| L39 | Loft didn’t check that a curve’s times increase, and took the last point as burnout instead of NFPA 1125’s rule | M1.3 |
| L40 | Loft fixed the motor’s center of gravity at the casing’s middle, with no inertia of its own | M1.3 |
| L41 | Loft bundled thrust curves under mixed or unknown licenses | M1.3 |
| L42 | Loft’s impulse checks were loose (±8%); a mis-sourced curve flew about 26% high until caught | M1.3 |
| L43 | ThrustCurve’s data must override a .eng header’s size: one said 75 mm for a 54 mm motor | M1.3 |
| L56 | Loft told a design file’s container apart by its first bytes, and a malformed one had to give an error rather than crash | M3.1a |
| L57 | Loft threw away the thrust curves stored inside a .ork archive | M3.1a, M3.1c1 |
| L59 | Loft resolved an automatic radius within a stage only, so a booster’s first component took a stale number | M3.1b2 |
| L60 | Loft resolved automatic dimensions as it walked the tree, so a ring’s bore depended on sibling order and a bulkhead inside a coupler stayed NaN | M3.1b3 |
| L61 | Loft weighed a ring with an automatic bore at 0 g, and dropped a stated wall when the outer radius was automatic | M3.1b2, M3.1b3 |
| L58 | Loft kept an automatic dimension’s number but lost the flag, so saving turned it into a hand-typed one | M3.1b1 |
| L62 | Loft met a tag written under two names, and read a stated 0 as a missing value | M3.1b1 |
| L63 | Loft read neither the drag override nor the subcomponent flags, so a part set to no drag was still charged drag | M3.1b1 |
| L64 | Loft read the wind’s direction from the launch rod’s, and dropped it from the stored conditions | M3.1c3 |
| L65 | Loft read a configuration from only one of the two places a .ork keeps it, and fired a motor whose mount it could not find from the top stage | M3.1c1 |
| L66 | Loft dropped pods, parallel stages and booster sets, and its export then lost the note that the rocket was reduced | M3.1c4 |
| L67 | Loft exported a plugged delay as 0 s, ignition only for the whole mount, no launch conditions, and masses it had worked out as overrides | M3.2a |
| L68 | Loft exported a freeform fin as a trapezoid of the same area (42% too big), lost a cluster’s scale and rotation, and rounded every number to six decimals | M3.2a |
| L44 | Loft’s inertia was pitch only, with simplified formulas, and zero for rings and masses | M1.4a |
| L45 | Loft put a hollow transition’s center of gravity at the solid’s centroid | M1.4a |
| L46 | Loft never read fin tabs (100 to 120 g lost on two designs), and rail buttons weighed nothing | M1.4a |
| L47 | Loft’s reference diameter was the widest part, even an internal one | M1.4b |
| L48 | Loft had tangent ogives only, a silent default nose shape, and swapped Haack names | M1.4a |
| L49 | Loft’s transitions used a kinked profile, never checked against what OpenRocket means | M1.4a, M3.1 |
| L50 | Loft let a motor wider than its mount fly (+69% apogee), and fins could sit off the airframe | M1.4b |
| L51 | Loft’s rule for which center-of-gravity override wins was unsettled (up to 133 mm) and came from OpenRocket’s source | M2.2b1 |
| L75 | Loft’s RocketPy check wasn’t like for like: a different atmosphere, unstated latitude and gravity, and Loft’s own drag and mass fed to RocketPy | M2.1b, M2.1b2 |
| L76 | Loft’s advice to regenerate a reference when a check failed let the reference follow Loft’s own drag | M2.1a |
| L77 | Loft shipped hand-written “stored” results, one set inconsistent with itself | M2.1a |
| L78 | Loft’s test suites skipped themselves when their data was missing, and still reported a pass | M2.1a |
| L79 | Only 2 of Loft’s 12 metrics had a tolerance per case; a deployment speed 204% off passed as “ungated” | M2.1a |
| L80 | Same word, different quantity: Loft found the deployment and ground-hit speeds and the optimum delay differ by tool and OpenRocket version; hpr has measured OpenRocket 24.12 only | M2.2d1 |
| L81 | Metrics for events that never happened, such as a deployment speed with no deployment, were scored as 0 | M2.2d1 |
| L82 | References 60% apart were excused as “no single target”, and known issues excused the two largest misses. Tested: every compared case counts, whatever explains a miss, against both references where a rocket has two | M2.2f |
| L84 | Loft wrote its counts by hand, for populations it didn’t name, and counted one disagreement 15 times | M2.4 |
| L85 | Loft’s check that a known gap had closed used half the tolerance, so it missed gaps that closed in between | M2.1b2, M2.4 |
| L86 | Loft published a headline accuracy figure without saying what it was compared with, over which rockets, or at what speeds | M2.4 |
| L88 | Loft’s only independent check held drag equal, so its own aerodynamics were never held to another code | M2.4 |
| L89 | Barrowman’s hand-worked values for a cone, a conical transition and an elliptical fin, which hpr’s tests check | M1.5a |
| L90 | Properties any drag model must keep, such as split fin sets dragging like one set, which hpr’s tests check | M1.5b |
| L91 | Exact volumes of nose cones (cone, tangent ogive, Haack), which hpr’s tests check | M1.4a |
| L93 | Staging: the sustainer lights at the booster’s burnout plus its delay, the mass steps at the separation, and a trigger never reached lights nothing | M1.9a |
| L94 | The optimum ejection delay must come out the same whether the delay flown opens the parachute early or late | M1.10a |
| L95 | A degenerate design, with a zero radius, a NaN, no fins or a negative mass, must be refused or fly to finite numbers, never to a NaN | M4.1a |