Legacy command vocabulary — mined at C6, the last look before the C7 deletion of legacy/¶
What this is: the complete record of every command id the team ever declared or authored routines with in the legacy tree, what each did (or was meant to do), and where each maps in shulib v2 today. This is a requirements input for F3 (the concrete mechanism/scoring primitives — an earlier revision said "F2 (mechanism primitives)", which is two mistakes: chunk F2 is the sequence engine, and the mechanism seam was F1) and G2 (the canonical command-id registry), and the two data specimens characterized here are the real inputs G4's
.shupathsimporter must be able to read.Method: extracted mechanically (scripts in §6), from all four places commands existed in
legacy/; the hand-reading only interprets what the scripts found. Nothing below is from memory.C7 executed the deletion on 2026-08-10. Every
legacy/path in this document is now historical: the files live in git history, not the working tree. Retrieve any of them withgit show 691c656:<path>(the last commit containing the tree,shulib-v2branch) — e.g.git show 691c656:src/legacy/autonomous_commands.csvfor G4's importer specimen.
1. The four sources, and the headline finding¶
Every path in the table below was deleted at the cutover and none of them exists in the tree today. They are named because this document exists to record what was there before it went, and the audit that normally flags a dead path is told so explicitly at the top of this section rather than being quietly weakened for everyone.
To read any of them, ask git for the commit before the deletion:
git log --diff-filter=D -- '*/legacy/*'finds it, andgit show <commit>^:<path>prints the file.
| Source | Kind | Rows | Distinct ids used |
|---|---|---|---|
include/legacy/shulib/RobotCommands/autonomous_commands.h |
C enum (declaration) | — | 6 declared |
include/legacy/shulib/RobotCommands/CommandType.hpp |
C++ enum (duplicate declaration) | — | same 6 |
src/legacy/shulib/Pathing/autonomous_commands.c |
generated routine data | 635 | 1 (CMD_MOVE_WITH_HEADING) |
src/legacy/autonomous_commands.csv |
exported routine data | 844 (+header) | 2 (MOVE_WITH_HEADING ×826, NONE ×18) |
src/legacy/main.cpp:448 |
hard-coded CommandData vector |
11 | 2 (MOVE_WITH_HEADING ×10, NONE ×1) |
The headline finding — no executor ever existed. Verified by grep: main.cpp's
autonomousCommands vector is defined at line 448 and never read; the .c array is
extern-declared in two headers (autonomous_commands.h, CommandArray.hpp) and no code
consumes it; Chassis::commands (chassis.hpp:85) is declared and never populated; the one
OO command (MoveWithHeadingCommand::execute()) calls a private moveTo() whose body is
empty. The team built three parallel data representations of a routine — C array, CSV,
C++ vector — plus two enum declarations and an OO command class, and none of it ever drove the
robot. Every auton that actually ran was hand-written blocking calls in main.cpp (see §4).
That is the strongest possible evidence for G2's design: this team wanted data-driven autons badly enough to attempt it three ways, and what was missing every time was the runner. G2 builds the runner first-class; VexBuilder supplies the data.
2. The declared vocabulary — every distinct id, mapped¶
Seven distinct ids exist across all sources (6 declared + 1 that appears only in data):
| Legacy id | Authored in data? | What it did / meant | v2 home today | Status |
|---|---|---|---|---|
MOVE_WITH_HEADING |
yes — 826 CSV + 635 .c + 10 main.cpp rows |
Move to (x, y) holding a commanded heading, at speed. The only motion verb the planner emitted; in practice never executed from data (no runner) |
C1 MoveToPose (decoupled x/y/θ — exactly "move with heading") via C2 MotionScheduler, surfaced as C4 Chassis::moveTo; per-segment speed = motion-config speed budget / G2 segment constraints |
Covered — v2's core motion verb is a strict superset (profiled, watchdog-bounded, exit-reasoned) |
NONE |
yes — 18 CSV rows + 1 main.cpp row, absent from both enums |
Path-segment boundary marker: every one has speed=0; the 18 markers (file start, file end, 16 internal) delimit 17 move segments of 12–115 waypoints |
G2 needs an explicit no-op/waypoint-only marker in the canonical vocabulary (or the importer folds boundaries into paths[] segment structure, which .vexbot already has) |
GAP (named): G2 must decide boundary-marker representation; G4 must consume NONE rows (see §5) |
PICK_UP |
no — enum only | Intended: acquire a game piece (floor pickup) | Phase F′ intakeUntilCapture (master plan §14, bottleneck #1) |
Covered by plan, not yet built — F-phase |
PLACE |
no — enum only | Intended: place/score a held piece | Phase F′ buildStack / liftToLevel+place sequence (§14) |
Covered by plan, not yet built — F-phase |
SCOOP |
no — enum only | Intended: scoop-style floor acquisition (mechanism variant of pick-up) | Phase F′ intake family; whether "scoop" is a distinct verb is a build-team mechanism decision, not a software one | Covered by plan; flag: don't mint two ids for one mechanism until the mechanism exists |
RELEASE |
no — enum only | Intended: release a held piece (their robot had a releaser motor group — main.cpp:62) |
Phase F′ clampActuate(open) / outtake |
Covered by plan, not yet built |
CLASP |
no — enum only | Intended: clamp/grab (their robot had pneumatic arm/lever — main.cpp:57-58) |
Phase F′ clampActuate+clampConfirm (§14) |
Covered by plan, not yet built |
Reading for G2: the five mechanism ids were declared intent that data authoring never
reached — the planner could only emit MOVE_WITH_HEADING (+ NONE). So the honest legacy-derived
requirement is not "support these five ids"; it is: (a) the motion verb + boundary marker are
the proven minimum a planner emits, and (b) mechanism ids must be registerable by the team
(runner.on(...)) precisely because the mechanism set churns season to season — legacy hard-coding
the season's verbs into an enum is the anti-pattern G2's registry replaces.
Duplicate-declaration hazard (why porting any of this was rejected)¶
The 6-id enum is declared twice (autonomous_commands.h as a C typedef enum,
CommandType.hpp as a C++ enum), the payload struct twice (Command in the C header,
CommandStruct in the C++ one), and Command.hpp declares an unrelated abstract Command class
that name-collides with the extern "C" Command struct — an ODR trap wired into the
design. None of it is salvageable as code; the vocabulary above is the salvage.
3. The de-facto vocabulary — what hand-written autons actually used¶
Because the data path never ran, the real command vocabulary is in main.cpp's hand-written
routine (the active one and the large commented-out competition routine, lines 836–1045). This is
equally a G2/F′ requirements input — it is what the team reached for when authoring for real:
| Hand-written verb | What it did | v2 home |
|---|---|---|
rotate_to(deg) |
Blocking turn-to-heading, coarse PID, min/max power floors | C1 TurnTo (profiled, settled-exit) |
move_vertical(inches) |
Blocking straight drive by displacement, PID on remaining distance | C1 MoveToPose (relative move); the displacement-not-accumulation lesson is designed in (pose-space error) |
move_to_pose(pose) |
Turn-to-face then drive (tank strategy) | C1 MoveToPose / C3 H-drive fallback does turn-then-drive structurally |
chassis.setPose(0,0,θ) after every turn |
Manual odometry re-anchor — they trusted heading so little they re-zeroed constantly | Superseded by IMU-owned heading (M2) + M3 correctors; a routine should never need mid-run setPose |
lever.extend() / lever.retract(), arm pneumatics |
Mechanism actuation | F′ deployActuator / clampActuate → G2 ids |
intake/conveyor/releaser .move(±127) + timed limitedCombo/limitedComboFull |
Timed open-loop mechanism combos | F′ intakeUntilCapture etc. — sensor-confirmed, not timed; G2 typed-args markers |
oscillation(n) |
Wiggle forward/back ×n to seat a piece | Not in any v2 plan by name — a candidate F′ micro-primitive (seat/settle wiggle); noted as a gap-adjacent observation for F3/F′ (recorded at C6 as "F2", the pre-split chunk name) |
timer(ms) / pros::delay between steps |
Sequencing by wall-clock delay | C2 waitUntilSettled / D1 recipe chaining / the run guard's whole-run deadline |
test_min_output(), rotation_calibration() |
Calibration routines (see hardware-assumptions addendum) | M3 "calibration routines + persistence" — specimens captured at C6 |
Gap summary for the sequencing/primitives chunks (recorded at C6 under the pre-split name "F2"): everything maps onto planned §14 primitives except the seat/settle wiggle
(oscillation), which is worth a line in the scoring-primitives brief (Phase F′) as a candidate
micro-primitive (cheap, and
they used it twice in one routine, under a dedicated task, mid-drive).
4. The two data specimens — what G4's importer must actually survive¶
Both files carry the same 5-column shape — command, x, y, heading, speed — and they disagree
about everything else. G4 must treat these as two dialects of one format:
| Property | autonomous_commands.csv (844 rows) |
Pathing/autonomous_commands.c (635 rows) |
|---|---|---|
| Container | CSV with header row, string command ids | Generated C array, enum command ids |
| Coordinates | x ∈ [3.69, 123.28], y ∈ [14.27, 118.85] — fits the 144″ field in inches | x ∈ [13, 151], y ∈ [23, 343] — does NOT fit a 144″ field; unit/space unrecorded (cm? planner canvas px?) |
| Heading | signed degrees, [−177.03, 172.77] (−180..180 convention) | signed degrees, includes values > 90 and < −90; same convention |
| Speed | constant 50 on every move row; 0 on every NONE |
per-waypoint ramp, 41.8 → 100 within each heading-group (the planner emitted speed profiles) |
| Segmentation | 18 NONE marker rows (speed 0; file start + file end + 16 internal) delimit 17 move segments, 12–115 waypoints each |
segmentation implicit in heading/speed-ramp resets; no marker rows at all |
| Waypoint density | ~1″ spacing (dense interpolation, not sparse waypoints) | ~3″ spacing, also dense |
| Vocabulary | MOVE_WITH_HEADING, NONE |
CMD_MOVE_WITH_HEADING only |
Importer requirements extracted (G4):
- Never assume inches. One shipped specimen is in-field-range inches; the sibling specimen is
not. The importer needs a unit/coordinate-space decision per file — explicit metadata if the
planner recorded any, else a documented heuristic (e.g. bounds-fit against the field) that
flags rather than silently guesses. This is the same "explicit fields are the contract"
posture as
inferDrivetrain()(§16.1). NONEmust parse. It is absent from the legacy enum (the legacy C importer could not even have represented its own sibling file — an enum round-trip bug they shipped). Map it to segment boundaries inpaths[], not to a motion.- Commands arrive as rows interleaved in the waypoint stream, not as markers attached to segments. The importer must convert row-commands → G2 marker model (id on a waypoint).
- Speed is per-waypoint and dialect-dependent (constant vs ramp). Map to G2 segment constraints; do not preserve 1:1 (v2 profiles motion itself — imported speeds are constraints, not commands).
- Dense ~1″ waypoints are the input shape. 826 waypoints for one routine.
PathRunnerconsumes sparse waypoints + profiles; the importer should decimate/fit, and say it did. - Expect unconsumed vocabulary. The five mechanism ids exist in the enum with zero data
ever authored; a
code_template-era file may equally carry ids no registry knows. G4 already specifies WARN+skip for unknown ids (§16.3) — these specimens confirm it will fire in practice. - The 845-row CSV is committed in-tree until C7. G4 should lift a copy into its own test fixtures before/at C7 (flagged in C6's completion record, in the development log). That window has closed: C7 ran on 2026-08-10 and the CSV is no longer in the tree, and no fixture copy was lifted. It is recoverable from git history, which is why this was recorded as a flagged risk rather than a blocker — but recovering it is now G4's job, not a matter of copying a file that is sitting there.
For G2's manifest: nothing in the legacy vocabulary demands a new canonical id beyond what
§14/§16.3 already plan. The legacy-derived additions to G2's requirements are exactly two:
an explicit waypoint-only/boundary marker semantics decision (NONE's successor), and the
registry-not-enum principle §2 documents (which G2 already embodies).
5. Command-id gaps, stated precisely¶
NONE(boundary marker): no v2 representation decision yet. Not a missing feature —.vexbotpaths[]segments can absorb it structurally — but G2 must make the call and G4 must implement the mapping. Owner: G2 (decision), G4 (mapping).- Seat/settle wiggle (
oscillation): used in real routines, in no plan by name. Owner: the scoring-primitives brief (Phase F′), as a candidate micro-primitive. (Recorded at C6 under the pre-split name "F2"; chunk F2 became the sequence engine and never carried this item.) Low stakes, cheap to add or reject. - Everything else declared or authored in
legacy/has a named v2 home in the tables above — built (C1–C4) or planned with an owner (F′ §14, G2/G4, M3/M4).
6. Mechanical cross-check (re-runnable against git history)¶
Every count above came from these commands, run at C6 (2026-08-10), from the repo root — at a
tree that still contained legacy/. To re-run them today, check out 691c656 (or pipe
git show 691c656:<path> into the same commands):
# Distinct ids + counts, CSV (844 data rows: 826 MOVE_WITH_HEADING + 18 NONE; all rows 5 fields):
awk -F, 'NR>1 {print $1}' src/legacy/autonomous_commands.csv | sort | uniq -c
awk -F, '{print NF}' src/legacy/autonomous_commands.csv | sort | uniq -c # → "845 5"
# Distinct ids + counts, generated C array (636 = 1 enum decl + 635 rows; others 1 = decl only):
grep -o 'CMD_[A-Z_]*' src/legacy/shulib/Pathing/autonomous_commands.c | sort | uniq -c
# The two enum declarations (identical 6 ids ×2):
grep -h 'CMD_' include/legacy/shulib/RobotCommands/autonomous_commands.h \
include/legacy/shulib/RobotCommands/CommandType.hpp | tr -d ' ,' | sort | uniq -c
# main.cpp's hard-coded vector (10 MOVE_WITH_HEADING + 1 NONE among the string literals):
grep -o '"[A-Z_]*"' src/legacy/main.cpp | sort | uniq -c
# NONE rows are all speed-0 boundary markers (18 hits, lines 2..845):
grep -n '^NONE' src/legacy/autonomous_commands.csv
# The no-executor proof (each returns declarations/definitions only, zero consumers):
grep -rn "autonomousCommands" src/legacy/main.cpp # def line 448 only
grep -rn "autonomous_commands\[" src/legacy include/legacy # extern decls + the .c def only
grep -n "commands" include/legacy/shulib/chassis/chassis.hpp # member decl only, never touched
Coordinate/speed ranges were computed with awk min/max over the data columns (§4 table); segment
lengths with an awk pass over NONE positions. The live log of each extraction as it was run is
preserved in the development log on the shulib-v2 branch.
Produced by chunk C6 (2026-08-10), the final audit of the pre-rebuild tree before its deletion
at C7 — the full 34-file classification and the safe-to-delete verdict are in the development log
on the shulib-v2 branch. Companion documents: hardware-assumptions.md
(the legacy-measured reference constants, added at C6), shulib-v2-master-plan.md
§16.3 (the registry design this feeds; G2 owns the id registry, G4 the importer).
Last updated 2026-08-14 — published from the main release branch, commit 6d5dd35. This site tracks releases, so between them it can lag the repository — that lag is deliberate, and it is what keeps the development log off the public site. For the current state of the code, see the repository.