Skip to content

Baton: producer-side route keying for handler-framework Go (huma route-registration ↔ output struct) #319

Description

@montfort

Context: Baton Phase 1 (#304). Sibling to #313 (per-type → endpoint keying for generated consumer type files), discovered while dogfooding the #313 fix against Sentinel (AILOG-2026-06-26-001).

#313 fixed the consumer side: a generated types.gen.ts whose interfaces carry no endpoint anchor now key to their route via the call site (api.get<HealthSnapshot>(/services/${id}/health)). But the coherence engine still keyed the producer (Go struct) by nearest /api/... anchor — and that has the symmetric failure.

The gap. Sentinel's Go backend uses the huma framework, which registers every route in one block:

huma.Get(api, "/api/v1/services/{service_id}/health", h.getServiceHealth)   // line 37
...
type getServiceHealthOutput struct { ... }                                   // line 113

The response struct getServiceHealthOutput is defined ~75 lines below the route registration. Nearest-anchor ("the /api/... reference at or above the declaration") binds it to whatever route was registered last before line 113 — not services.health. Net effect on the Sentinel dogfood: the services.health contract shows producer=None, so even with the #313 consumer keying fixed, C2/C3 cannot fire (they require a keyed producer).

Why it doesn't show today. Sentinel's types.gen.ts was remediated to match the backend, so the run is correctly 0 blocking regardless. This gap only bites on an un-remediated huma-style repo — but that is exactly the #304 scenario the engine is meant to catch.

Proposal. Mirror the #313 call-site binding on the producer side: bind the route literal in a registration call (huma.Get(api, "/path", h.handlerMethod)) to the handler symbol, then key the handler's output struct to that route via the framework's naming convention (<handler>Output for huma; the (*ctx, *Input) (*Output, error) return for the general case). Keep it conservative (R6): only bind when the convention resolves unambiguously; fall back to nearest-anchor otherwise. Optionally generalize beyond huma (gin/echo/chi r.GET("/path", handler)).

Done when: on a huma-style Go repo, the response struct keys to the route from its registration call rather than nearest-anchor, so a producer↔consumer field/enum mismatch (C2/C3) fires end-to-end.

Relation: #313 (consumer-side, done), #304 (the umbrella — this is part of its close condition for the field/enum half), #314 (component→path mapping for C1 — different lever).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions