Skip to content

Framework boundary: what is mission-neutral in branes::racing

Date: 2026-10-28 Purpose: The audit behind ADR 0008. For every header, source and build file of the composition framework, it records whether it is mission-neutral, racing-only, or mixed, and what a mixed file needs before its neutral part can move to anatomy.

The split is done (plan). The list of neutral files is now cmake/framework_boundary.cmake, which a ctest validates: each listed file exists and includes no racing-only header. (Adding a newly neutral file to the list is still a manual step.) This audit is the record of the starting point.

The audit was made at commit 6c6a712 by reading each file’s includes and the racing types it uses. The racing types are Gate, CourseMap, GateObservation(s), the oracle gate projector, the scorer, and the gate_detector slot.

  • Neutral, moves as is: the utilities, result, time and TimeBase, geometry, sensors, truth, the state estimate, control, flight-controller status, DAA conflicts, the controller and safety slots, the FC and IMU models, the log container, and the build helpers.
  • Racing-only, stays: the course, the gate detector and waypoint planner, the gate projector, the scorer, the course config, and the racing baselines.
  • Mixed, needs a split first: the rest. Racing enters them through four seams:
    1. The task. Three slot concepts (Estimator, GateDetector, Planner) and SlotContext take the course or gate observations.
    2. The composition. Stack wires the racing slot set, and the harness builds it from a CourseMap.
    3. The record format. One log channel (oracle_gates) and its codec are racing data, inside the framework’s channel enum.
    4. The simulator. Its loop owns the course and calls the gate projector, and the batch runner calls the racing scorer.

sdk/include/branes/racing/ is abbreviated sdk/; sim/include/branes/racing/sim/ is sim/.

FileClassRacing contentBefore it moves
sdk/result.hppNeutral——
sdk/util/bytes.hpp, sha256.hpp, splitmix64.hpp, sdk/src/util/sha256.cppNeutral——
sdk/msg/geometry.hppNeutral——
sdk/msg/time.hpp (Timestamp, TimeBase)Neutral——
sdk/msg/sensors.hpp (IMU, camera frame)Neutral——
sdk/msg/truth.hppNeutral——
sdk/msg/estimate.hppNeutral——
sdk/msg/fc.hppNeutral——
sdk/msg/daa.hppNeutral——
sdk/msg/control.hppNeutralReferenceSample::progress is documented as “along the course”Reword it as the path parameter of the reference; it is generic
sdk/msg/course.hppMixedGate, CourseMapGeofence and StartPose move to a neutral header; the rest stays
sdk/msg/perception.hppMixedGateObservation(s)IntruderDetection(s) moves; gate observations stay
sdk/msg/codec.hppMixedThe GateObservations codecThe gate codec moves to a racing header
sdk/log/log.hpp, sdk/src/log/log.cppMixedChannel::oracle_gates in a closed enum; is_sim/is_known hard-code itFramework channel ids become a fixed set and missions register their own. Id 5 stays oracle_gates, so existing logs read unchanged
sdk/config/config.hpp, sdk/src/config/config.cppMixedCourseConfig; ScenarioConfig::course_ref; kSlotNames lists the racing slots; SimParams::oracle_corner_sigma_pxVehicle, baseline and scenario loaders move. The course loader, the scenario’s world reference, the slot list and the oracle parameters become mission-supplied
sdk/slots/slots.hppMixedEstimator takes gate observations; GateDetector; Planner takes a CourseMapController, SafetyFilter, DaaTracker and FcBridge move; the three task-facing concepts stay
sdk/slots/context.hppMixedSlotContext::courseSlotContext becomes generic over the mission’s world type
sdk/slots/null.hppMixedNullGateDetector, NullPlanner, and NullEstimator’s gate argumentThe nulls of the neutral slots move
sdk/slots/ground_truth.hppMixedSatisfies the racing Estimator (gate argument ignored)Its truth pass-through moves; a thin racing adapter stays
sdk/slots/scripted.hppNeutral——
sdk/compose/stack.hppMixedThe racing slot set; the frame path detects gates and fuses themThe Stack stays a mission type. The framework defines what a stack must provide to the harness (a concept)
sdk/harness/harness.hppMixedmake_stack takes a CourseMap; the replay switch decodes oracle_gatesRunner becomes generic over that stack concept; building the stack and the mission channels are supplied by the mission
sdk/slots/waypoint.hppRacingPlans through the gatesStays
sim/fc.hpp, sim/imu.hppNeutral——
sim/vehicle.hppNeutral once StartPose movesIncludes course.hpp for StartPoseFollows course.hpp’s split
sim/simulator.hppMixedOwns the course; calls the gate projector; emits oracle_gatesThe loop (dynamics, FC, IMU, faults, camera timing, truth) moves; the mission supplies its world and its oracle sensors
sim/batch.hppMixedTakes a CourseMap; calls the racing scorerBecomes generic over the mission’s world and scorer
sim/sweep_types.hppMixedin_plane_ulp(gate)The type list moves; the gate helper stays
sim/gates.hpp (oracle projector)Racing—Stays
sim/score.hppRacingLaps, gatesStays
baselines/glue/ (cascaded_pid.hpp, reflex_params.hpp)Neutral—Moves with the controller it adapts
cmake/warnings.cmake, deps.cmake, compile_all.cmakeNeutral——
cmake/baselines.cmake, slot_registry.cmake, racing_baseline.hpp.inMixedThe slot list (RACING_SLOTS) and the racing_ namesThe generator moves; the slot list and the names become mission-supplied
apps/sitl, replay, sitl_batch, flight_stack, log_dumpMixedThrough Stack, CourseMap and the scorerThe harness logic moves as library functions; each mission keeps thin mains
apps/score, apps/precision_sweepRacingThe scoreboard; gate error by gateStay
baselines/*.yaml, courses/, scenarios/, vehicles/Racing data—Stay; vehicles/rp1.yaml is copied by any mission that flies RP-1
  • The mechanism was built neutral. No neutral file reaches into a racing header except through the four seams. That makes the move a split along existing lines rather than a redesign.
  • The task is the real seam. In each of the four places where racing enters, it enters as the mission’s task: what the vehicle is asked to do and what it perceives of it. For racing that is a course of gates. For scout-drone it would be a goal and depth observations. A framework generic over the task removes all four seams.
  • The simulator core depends on reflex (the dynamics model). The contracts, log and harness do not. Splitting the framework into two build targets keeps that dependency off consumers that need only the contracts.