Skip to content

Generate the routing gRPC field mapping from a single source of truth #1730

Description

@ramakrishnap-nv

Follow-up to review feedback from @rg20 on #1597 (mapper, to_device, round-trip test).

Problem

Adding one field to cpu_routing_problem_t today means editing five places by hand:

  1. the struct — cpp/include/cuopt/routing/cpu_routing_problem.hpp
  2. the wire format — cpp/src/grpc/routing/cuopt_routing.proto
  3. host → proto — map_routing_problem_to_proto
  4. proto → host — map_proto_to_routing_problem
  5. host → device — cpu_routing_problem_t::to_device

Nothing enforces that all five stay in sync. Not the compiler, not a test.

The failure mode is worse than the usual boilerplate complaint. A forgotten field
does not crash — the value silently never crosses the wire, and the remote solve
returns a plausible answer for a different problem than the one submitted.
That is expensive to detect and easy to miss in review.

Scale: cpu_routing_problem_t currently has 41 std::vector members, 6
std::map members, and 5 nested struct types. Roughly 80% of that is one
regular pattern repeated 41 times.

Suggested direction

Both review threads share a single root cause — the field list is written out
five times — so it is worth fixing once rather than twice.

Single source of truth for the routing field list, expanded into the proto,
both mapper directions, to_device, and a round-trip test. Either:

  • a routing section in cpp/src/grpc/codegen/field_registry.yaml, reusing
    generate_conversions.py (which already emits 27 .inc files and supports
    repeated_messages), or
  • an X-macro field-list header, which is less machinery and also covers
    to_device, which is outside the gRPC codegen's remit.

Caveat worth designing around: routing is less regular than LP. The 6 maps carry
real semantics — order_service_times is keyed by vehicle id with -1 meaning
"all vehicles", vehicle_breaks maps to a vector of structs. Expect ~80%
generated plus a tail of hand-written special cases, not a pure win.

Cheaper first step

A round-trip property test — populate every field with distinct values, go
host → proto → host, compare — catches the same class of bug for a fraction of
the effort and does not restructure anything. Worth doing first, and worth
keeping even after codegen lands.

Prior art in-tree: python/cuopt/cuopt/tests/routing/test_routing_grpc_serialization.py
already fails loudly when a new cuopt.routing._deferred._SETTERS entry is
unmapped. That guards the Python DataModelcpu_routing_problem_t direction;
this issue is about the remaining C++ hops.

Not blocking #1597

#1597 is approved with these threads open, so this is design follow-up rather
than a merge blocker.

Metadata

Metadata

Labels

awaiting responseThis expects a response from maintainer or contributor depending on who requested in last comment.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions