Move from string-based links and joints to id-based logic (using hashes)#734
Move from string-based links and joints to id-based logic (using hashes)#734rjoomen wants to merge 71 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates motion-planning and command-language code from string-based link/joint identification to id-based logic (e.g., LinkId, JointId), enabling hash/id-driven lookups across kinematics, collision checking, planners, and examples.
Changes:
- Replace link/joint name strings with
LinkId/JointIdin manipulator info, collision configuration, FK transform maps, and waypoint seeds. - Update command-language waypoint models + utilities to store/operate on joint IDs and adjust cereal serialization accordingly.
- Update planners/tests/examples to the new id-based APIs, including active collision object configuration and FK transform handling.
Reviewed changes
Copilot reviewed 85 out of 85 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| time_parameterization/totg/test/time_optimal_trajectory_generation_tests.cpp | Update ManipulatorInfo frames to LinkId. |
| time_parameterization/ruckig/test/ruckig_trajectory_smoothing_tests.cpp | Update ManipulatorInfo frames to LinkId. |
| time_parameterization/kdl/test/constant_tcp_speed_parameterization_tests.cpp | Update ManipulatorInfo frames to LinkId. |
| time_parameterization/kdl/src/constant_tcp_speed_parameterization.cpp | Switch KDL FK transform map + scene graph parsing to id/name accessors. |
| time_parameterization/isp/test/iterative_spline_tests.cpp | Update ManipulatorInfo frames to LinkId. |
| task_composer/test/tesseract_task_composer_planning_unit.cpp | Use LinkId frames and seed JointState via joint IDs. |
| task_composer/test/fix_state_bounds_task_unit.cpp | Construct ManipulatorInfo using LinkId frames. |
| task_composer/planning/src/nodes/format_as_result_task.cpp | Populate StateWaypoint using joint IDs. |
| task_composer/planning/src/nodes/format_as_input_task.cpp | Seed/format joint waypoints using joint IDs. |
| task_composer/planning/src/nodes/fix_state_collision_task.cpp | Convert collision checking to active link IDs + id-based FK state. |
| task_composer/planning/src/nodes/discrete_contact_check_task.cpp | Use active link IDs for discrete contact checks. |
| task_composer/planning/src/nodes/continuous_contact_check_task.cpp | Use active link IDs for continuous contact checks. |
| task_composer/core/include/tesseract/task_composer/test_suite/test_programs.hpp | Construct ManipulatorInfo using LinkId frames in test programs. |
| motion_planners/trajopt_ifopt/src/profile/trajopt_ifopt_default_move_profile.cpp | Build joint waypoints from state waypoints via joint IDs. |
| motion_planners/trajopt/test/trajopt_planner_tests.cpp | Update tests to use LinkId working/tcp frames. |
| motion_planners/trajopt/src/trajopt_utils.cpp | Update TrajOpt term-info utilities to accept LinkId parameters. |
| motion_planners/trajopt/src/profile/trajopt_default_move_profile.cpp | Update active-link checks + fixed joint waypoint creation to joint IDs. |
| motion_planners/trajopt/include/tesseract/motion_planners/trajopt/trajopt_utils.h | Update TrajOpt utility APIs to use LinkId. |
| motion_planners/simple/test/simple_planner_test_utils.hpp | Update ManipulatorInfo frames to LinkId. |
| motion_planners/simple/test/simple_planner_lvs_move_unit.cpp | Build explicit JointState seeds using JointId. |
| motion_planners/simple/test/simple_planner_lvs_assign_no_ik_move_unit.cpp | Build explicit JointState seeds using JointId. |
| motion_planners/simple/test/simple_planner_lvs_assign_move_unit.cpp | Build explicit JointState seeds using JointId. |
| motion_planners/simple/test/simple_planner_fixed_size_move_unit.cpp | Build explicit JointState seeds using JointId. |
| motion_planners/simple/test/simple_planner_fixed_size_assign_move_unit.cpp | Build explicit JointState seeds using JointId. |
| motion_planners/simple/src/simple_motion_planner.cpp | Format results as input using joint IDs; validate joint order via joint IDs. |
| motion_planners/simple/src/profile/simple_planner_lvs_assign_no_ik_move_profile.cpp | Query current joint values via joint IDs. |
| motion_planners/simple/src/profile/simple_planner_lvs_assign_move_profile.cpp | Query current joint values via joint IDs. |
| motion_planners/simple/src/profile/simple_planner_fixed_size_assign_no_ik_move_profile.cpp | Query current joint values via joint IDs. |
| motion_planners/simple/src/profile/simple_planner_fixed_size_assign_move_profile.cpp | Query current joint values via joint IDs. |
| motion_planners/simple/src/interpolation.cpp | Replace string frame checks and FK caches with LinkId/LinkIdTransformMap. |
| motion_planners/simple/include/tesseract/motion_planners/simple/interpolation.h | Change instruction-info structs to store LinkId frames. |
| motion_planners/ompl/test/ompl_planner_tests.cpp | Use LinkId link/joint fields and manipulator frames in tests. |
| motion_planners/ompl/src/utils.cpp | Set collision transforms in bulk using id-based FK result map. |
| motion_planners/ompl/src/state_collision_validator.cpp | Use active link IDs + id-based FK transform map for validity checks. |
| motion_planners/ompl/src/profile/ompl_real_vector_move_profile.cpp | Use joint IDs for joint-format checking and active link IDs for collision. |
| motion_planners/ompl/src/continuous_motion_validator.cpp | Use active link IDs + id-based FK transform maps for motion validation. |
| motion_planners/ompl/src/collision_cost_objective.cpp | Use active link IDs + id-based FK transform map for cost evaluation. |
| motion_planners/ompl/include/tesseract/motion_planners/ompl/state_collision_validator.h | Store active link IDs instead of names. |
| motion_planners/ompl/include/tesseract/motion_planners/ompl/continuous_motion_validator.h | Store active link IDs instead of names. |
| motion_planners/ompl/include/tesseract/motion_planners/ompl/collision_cost_objective.h | Store active link IDs instead of names. |
| motion_planners/examples/raster_example.cpp | Update ManipulatorInfo frames to LinkId. |
| motion_planners/examples/freespace_example.cpp | Update ManipulatorInfo frames to LinkId. |
| motion_planners/examples/chain_example.cpp | Update ManipulatorInfo frames to LinkId. |
| motion_planners/descartes/test/descartes_planner_tests.cpp | Update ManipulatorInfo frames to LinkId. |
| motion_planners/descartes/src/descartes_collision.cpp | Use LinkIdTransformMap and id-based FK results for collision checks. |
| motion_planners/descartes/include/tesseract/motion_planners/descartes/impl/profile/descartes_default_move_profile.hpp | Validate joint format via joint IDs; pass frame names from LinkId. |
| motion_planners/descartes/include/tesseract/motion_planners/descartes/impl/descartes_robot_sampler.hpp | Construct IK inputs via LinkId; use joint IDs + id-based FK cache. |
| motion_planners/descartes/include/tesseract/motion_planners/descartes/impl/descartes_collision_edge_evaluator.hpp | Use active link IDs and id-based collision margin access. |
| motion_planners/descartes/include/tesseract/motion_planners/descartes/descartes_collision_edge_evaluator.h | Store active link IDs (comment needs update). |
| motion_planners/descartes/include/tesseract/motion_planners/descartes/descartes_collision.h | Switch FK cache type and active link storage to id-based types. |
| motion_planners/core/src/utils.cpp | Switch toolpath pose computation + contact-check program plumbing to joint/link IDs. |
| motion_planners/core/include/tesseract/motion_planners/robot_config.h | Use LinkIdTransformMap and LinkId lookups for FK-derived poses. |
| examples/src/scene_graph_example.cpp | Update joint parent/child fields to use LinkId. |
| examples/src/puzzle_piece_example.cpp | Update ManipulatorInfo frames to LinkId. |
| examples/src/puzzle_piece_auxillary_axes_example.cpp | Update ManipulatorInfo frames to LinkId. |
| examples/src/pick_and_place_example.cpp | Use LinkId for joint parent/child and for ManipulatorInfo frames. |
| examples/src/online_planning_example.cpp | Use LinkId FK lookup for tool pose; set environment state via joint-name accessor. |
| examples/src/glass_upright_ompl_example.cpp | Update FK usage to id-based map (currently extracts pose incorrectly). |
| examples/src/glass_upright_example.cpp | Use LinkId for joint parent/child and ManipulatorInfo frames. |
| examples/src/freespace_ompl_example.cpp | Use LinkId for joint parent/child and ManipulatorInfo frames. |
| examples/src/freespace_hybrid_example.cpp | Use LinkId for joint parent/child and ManipulatorInfo frames. |
| examples/src/car_seat_example.cpp | Use LinkId for joint parent/child, transforms, and ManipulatorInfo frames. |
| examples/src/basic_cartesian_example.cpp | Use LinkId for joint parent/child and ManipulatorInfo frames. |
| command_language/test/type_erasure_benchmark.cpp | Construct ManipulatorInfo using LinkId. |
| command_language/test/command_language_utils_unit.cpp | Update tests to use LinkId and build seed joint IDs. |
| command_language/test/command_language_unit.cpp | Construct ManipulatorInfo using LinkId. |
| command_language/test/command_language_test_program.hpp | Build seed joint IDs in test program generation. |
| command_language/src/utils.cpp | Add joint-ID utilities and migrate waypoint joint extraction/formatting. |
| command_language/src/state_waypoint.cpp | Store joint IDs internally; derive names on demand; add joint-id accessors. |
| command_language/src/poly/state_waypoint_poly.cpp | Expose joint-id accessors; return names by value. |
| command_language/src/poly/joint_waypoint_poly.cpp | Expose joint-id accessors; return names by value. |
| command_language/src/poly/cartesian_waypoint_poly.cpp | Treat cartesian seed validity as joint-id based. |
| command_language/src/joint_waypoint.cpp | Store joint IDs internally; derive names on demand; add joint-id accessors. |
| command_language/include/tesseract/command_language/utils.h | Change joint-name extraction to return by value; add joint-id APIs. |
| command_language/include/tesseract/command_language/test_suite/state_waypoint_poly_unit.hpp | Update tests to use setters instead of mutating name refs. |
| command_language/include/tesseract/command_language/test_suite/move_instruction_poly_unit.hpp | Construct ManipulatorInfo using LinkId. |
| command_language/include/tesseract/command_language/test_suite/joint_waypoint_poly_unit.hpp | Update tests to use setters instead of mutating name refs. |
| command_language/include/tesseract/command_language/test_suite/cartesian_waypoint_poly_unit.hpp | Build cartesian seed state using joint IDs. |
| command_language/include/tesseract/command_language/state_waypoint.h | Add joint-id storage/accessors + cereal load/save friend declarations. |
| command_language/include/tesseract/command_language/poly/state_waypoint_poly.h | Extend interface to include joint IDs; return names by value. |
| command_language/include/tesseract/command_language/poly/joint_waypoint_poly.h | Extend interface to include joint IDs; return names by value. |
| command_language/include/tesseract/command_language/joint_waypoint.h | Add joint-id storage/accessors + cereal load/save friend declarations. |
| command_language/include/tesseract/command_language/cereal_serialization.h | Switch Joint/State waypoint serialization to non-member load/save for id-backed storage. |
| command_language/POLY_TYPE_DESIGN.md | New documentation describing the poly/type-erasure architecture. |
| CLAUDE.md | New repository guidance file (architecture + patterns overview). |
Comments suppressed due to low confidence (1)
examples/src/glass_upright_ompl_example.cpp:199
- Same issue here:
transforms.begin()->secondis not guaranteed to be the TCP (or any specific) link transform, so the constraint may compute an angle for the wrong frame. Select the intended link explicitly from the FK results (e.g., by keying on the tool link id/name) instead of taking the first element.
auto transforms = fwd_kin_->calcFwdKin(x);
const Eigen::Isometry3d& pose = transforms.begin()->second;
Eigen::Vector3d z_axis = pose.matrix().col(2).template head<3>().normalized();
out[0] = std::atan2(z_axis.cross(normal_).norm(), z_axis.dot(normal_));
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 87 out of 87 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Reason: flagged by Copilot PR review on tesseract-robotics#734; prevents -Wunused-using-declaration noise when warnings are treated as errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The JointId-based getJointPosition / formatJointPosition overloads still threw "Joint name ..." on mismatch, making failures misleading when the caller passed IDs. String-name overloads keep their original wording. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The id-migration switched from a reused thread-local LinkIdTransformMap and calcFwdKin(out_map, joints) to "auto state = calcFwdKin(start_pos)", which allocates a new map on every call. stateInCollision can run on a hot path during collision fixing, so restore the previous pattern. Also add <cstdint> in motion_planners/robot_config.h: the enum now uses std::uint8_t and was relying on transitive includes. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 83 out of 83 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (2)
examples/src/glass_upright_ompl_example.cpp:205
- This collision constraint constructs a LinkId from tcp_link_ on every evaluation. Since LinkId creation likely hashes the string, consider storing a tesseract::common::LinkId member (initialized once in the ctor) and using it directly in transforms.at(...) to reduce per-call overhead in OMPL constraints.
GlassUprightConstraint(const Eigen::Vector3d& normal,
tesseract::kinematics::ForwardKinematics::Ptr fwd_kin,
std::string tcp_link)
: ompl::base::Constraint(fwd_kin->numJoints(), 1)
, normal_(normal.normalized())
, fwd_kin_(std::move(fwd_kin))
, tcp_link_(std::move(tcp_link))
{
}
~GlassUprightConstraint() override = default;
void function(const Eigen::Ref<const Eigen::VectorXd>& x, Eigen::Ref<Eigen::VectorXd> out) const override
{
auto transforms = fwd_kin_->calcFwdKin(x);
const Eigen::Isometry3d& pose = transforms.at(tesseract::common::LinkId(tcp_link_));
Eigen::Vector3d z_axis = pose.matrix().col(2).template head<3>().normalized();
out[0] = std::atan2(z_axis.cross(normal_).norm(), z_axis.dot(normal_));
}
motion_planners/core/include/tesseract/motion_planners/robot_config.h:35
- This header now uses tesseract::common::LinkId and tesseract::common::LinkIdTransformMap, but it doesn't include the header that defines them. Please add a direct include (e.g., <tesseract/common/types.h>) so robot_config.h is self-contained and doesn't rely on transitive includes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
validate() and distance() receive transforms_cache as a reusable buffer (the sampler holds a thread_local LinkIdTransformMap that loops over every IK solution). Assigning transforms_cache = manip_->calcFwdKin(pos) builds a fresh map inside calcFwdKin on every call and move-assigns it in, throwing away the thread_local's reserved buckets. Use the calcFwdKin(out_map, joints) overload so the existing storage is reused. Reason: flagged by Copilot PR review on tesseract-robotics#734 (descartes_collision.cpp:66). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Store tcp_link_ as a LinkId member so its hash is computed once in the constructor rather than rebuilt on every constraint evaluation inside the OMPL sampler loop. Note: this file isn't wired into examples/CMakeLists.txt, so the change is compile-untested; it is syntactically consistent with the rest of the id migration. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The surrounding logic already queries manip->getJointIds() for format checking and for start_state.getJointValues(); building the JointState seed from getJointNames() was the odd one out and forced a redundant name->id lookup inside the JointState constructor. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…_utils getJointNames' @param said "extract the joint position from", which was a copy-paste from getJointPosition — corrected to "joint names". planner_utils.h exposes common::LinkId in isValidState's signature but was relying on a transitive include for the definition; include <tesseract/common/types.h> directly. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 83 out of 83 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (4)
task_composer/planning/src/nodes/fix_state_collision_task.cpp:1
stateisthread_localand is no longer cleared between calls. IfcalcFwdKindoesn’t overwrite all entries every time (or if the active links set changes), stale transforms can persist and be consumed by collision checking, potentially producing incorrect results without throwing. Clear the map beforecalcFwdKin(...)(or switch to an API that returns a fresh transform map per call) to avoid reusing stale data.
task_composer/planning/src/nodes/fix_state_collision_task.cpp:1calcFwdKin(start_pos)returning a transform map by value may allocate and re-hash on each invocation. Since this codepath can run in iterative collision-fixing loops, consider reusing an outputLinkIdTransformMap(e.g., thread-local or stack-allocated and cleared) and calling thecalcFwdKin(out, ...)overload if available to reduce per-iteration allocations.
motion_planners/simple/test/simple_planner_lvs_move_unit.cpp:1- This manual loop for converting joint names to
JointIds is repeated across multiple simple planner tests in this PR. Consider using a shared helper (e.g.,tesseract::common::toIds<tesseract::common::JointId>(joint_names_)) to reduce duplication and keep the tests consistent.
motion_planners/core/src/utils.cpp:1 StateWaypointPoly::getNames()now returns by value, so this assert creates an unnecessary allocation/copy just to get a size. Prefer checkingswp.getJointIds().size()(or the stored position size invariants) to avoid extra work in a hot utility function.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 74 out of 74 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Reason: flagged by Copilot PR review on tesseract-robotics#734; prevents -Wunused-using-declaration noise when warnings are treated as errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The JointId-based getJointPosition / formatJointPosition overloads still threw "Joint name ..." on mismatch, making failures misleading when the caller passed IDs. String-name overloads keep their original wording. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The id-migration switched from a reused thread-local LinkIdTransformMap and calcFwdKin(out_map, joints) to "auto state = calcFwdKin(start_pos)", which allocates a new map on every call. stateInCollision can run on a hot path during collision fixing, so restore the previous pattern. Also add <cstdint> in motion_planners/robot_config.h: the enum now uses std::uint8_t and was relying on transitive includes. Reason: flagged by Copilot PR review on tesseract-robotics#734. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The split save/load pair added when these waypoints moved to JointId storage left them with two candidate cereal serializers: the pair plus the serialize inherited from their interface base. Cereal binds a type only when exactly one candidate exists, and silently skips CEREAL_REGISTER_TYPE otherwise, so saving either waypoint threw "unregistered polymorphic type" at runtime. JointId already serializes as its name via save_minimal, so the id vector can be written directly and the pair is unnecessary. NVP keys and the archive format are unchanged. Fixes 5 failing tests; tesseract_planning is now 291/291. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115dXrv5yUqynisbKY9HjGe
getJointIds already covered every caller; the string form only existed to convert ids back to names and, for Cartesian seeds, reached through JointState::getJointNames.
Leaves three genuine string sinks converting at the point of use: OMPL dimension labels, the car_seat name-keyed pose map, and ifopt Var labels. Also renames command_language_utils_unit.cpp's getJointNamesTests to getJointIdsTests, left stale after the prior task deleted getJointNames.
Four locals in the command language utils tests were typed std::vector<JointId> but still named joint_names. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115dXrv5yUqynisbKY9HjGe
Both profiles fetched the group joint names only to hand them to APIs that have id spellings, hashing them straight back into ids per waypoint. They now use getGroupJointIds() with the id overloads of checkJointPositionFormat() and getCurrentJointValues(). Names are produced once per scope for trajopt_ifopt::Node::addVar, which labels generic optimization variables and deliberately has no id overload. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
assignSolution, assignTrajectory and both getInterpolatedInstructions carried a vector<std::string> overload that was a one-line toIds shim over the JointId form. Nothing called them, and nothing could: JointGroup::getJointNames() is gone, so a caller can only reach them by first calling toNames() — the ids->names->ids round trip the migration exists to remove. Passing names is now a compile error instead of a silent per-joint re-hash. 121 lines deleted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The joint name member was initialized from literals and fed to a JointState constructor once per trajectory row, hashing all 10 joints on every row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The waypoints hold ids; setJointIds and getJointIds are the accessors, and they had already taken over every production call site. The only name reader left was the Qt tree display, which now resolves names at its own boundary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agent guidance, not part of the library; it was swept into an unrelated commit. The file stays on disk and is now ignored locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getJointPosition, formatJointPosition and checkJointPositionFormat each kept a one-line toIds string delegate with zero non-test callers; every production caller already passes ids. Their delegation-only unit test goes with them, leaving 288 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The private declaration had no definition anywhere and would have failed to link; the id-spelled helper in tesseract/collision/common.h is the real one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JointState no longer takes joint names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The surviving overloads take ids; their doxygen still named the parameter joint_names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Their SFINAE-guarded vector<string> constructors duplicated the vector<JointId> constructors already in place, so a name-typed call site still silently compiled and hashed instead of failing to build, unlike every other class touched by the identity migration. The initializer_list<string> constructors have no id twin (they exist only to brace-init both lists in one expression) so those got retyped to initializer_list<JointId> instead of deleted. Every remaining vector<string> caller is now a hard compile error, fixed by retyping local declarations (tests/examples never define TESSERACT_NAMEID_NO_IMPLICIT, so string literals keep converting implicitly). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Only the position lists need to be initializer_lists; Eigen cannot take a flat braced list as an argument, but a vector of ids can. Callers may now pass an id vector alongside brace-initialized values, and the convenience constructors gain the coverage they never had. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The variables were retyped to JointId during the migration but kept their string-era spelling, which now describes the wrong thing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the wording used in the other cereal headers: the "names"/"joint_names" archive keys are kept over the joint_ids_ field because a JointId serializes as its name string, keeping the on-disk key stable and portable across builds. Comment-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Retype car_seat_example's saved-position store, puzzle_piece's joint list, and online_planning_example's updateState boundary to the id twins of Environment::setState/getState, matching the pattern already applied elsewhere on this branch.
Drop 8 explicit JointId(...) wrappers where the target type is already fixed by context; test TUs enable implicit string->id conversion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XnQ84NASLsf6oQ2kGqXdnk
Dropping state.clear() on the thread-local scratch map let an out-of-group base_link/tcp_frame read a stale pose instead of failing. Guard membership and throw; keep the no-clear map. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Note the safe-iff-every-key-belongs contract where descartes and fix_state_collision reuse a scratch transform map without clearing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gather the active set into thread-local buffers and call the id-typed parallel-array setter, restoring active-only and fail-loud semantics while keeping the Coal/FCL batching. Replaces the whole-map call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
orig_names/post_names hold vector<JointId>; rename to orig_ids/post_ids. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getJointIds only forwards references into stored waypoint data, so return const& like the sibling getJointPosition and drop copies at forwarding call sites. Add the matching deleted template overload to block a dangling reference into an implicitly-converted temporary WaypointPoly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This type-erasure design doc is unrelated to the string-to-id migration; it rode in on an unrelated commit. Untrack it here so the migration stays focused; it will be upstreamed on its own. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Requires tesseract-robotics/tesseract#1274