feat(responses): register operations for request-head classification - #788
feat(responses): register operations for request-head classification#788cdoern wants to merge 1 commit into
Conversation
praxis-bot
left a comment
There was a problem hiding this comment.
PR Review
Summary: Registers eight Responses operations in a family-owned registry, moving identity from body heuristics to request-head classification (method, path, transport). Introduces shared infrastructure (RouteParams, match_operation, OperationEntry) and migrates Conversations to use it. Adds a pinned-spec drift check wired into make lint.
Overall: Clean implementation. The shared matcher correctly handles precedence (static segments outrank parameters via max_by_key), transport separation, path normalization, and bounded parameter capture. The Conversations migration preserves the public API while switching to generic name-based parameter lookup. Test coverage is comprehensive: uniqueness, round-trip resolution, precedence, transport separation, capacity limits, and drift detection. No issues found at Critical, Large, or Medium severity.
| Severity | Count |
|---|---|
| Critical | 0 |
| Large | 0 |
| Medium | 0 |
e09e42d to
fd47caf
Compare
|
Unsigned commits: 7760b51, fd47caf. Please sign your commits. |
fd47caf to
94b4e25
Compare
Responses operation identity came from path string matching in the request classifier, with hand-written prefix and suffix checks per endpoint. Declare the supported operations in a family-owned registry instead, so identity comes from method, path, and protocol headers before any payload is read. Register the eight supported operations against the shared operation registry: create, retrieve, delete, cancel, list input items, count input tokens, compact, and the WebSocket handshake. Operation IDs are the official ones from the pinned specification, reproduced verbatim including upstream's casing for `Getinputtokencounts` and `Compactconversation`. Praxis proxies the Responses contract rather than owning it, so every operation declares its runtime request-body shape without an owned OpenAPI contract. This is the first registry to rely on request-body shape being independent of contract ownership. The WebSocket handshake shares its method and path with no HTTP operation the pinned specification represents, so it is declared as an explicit Praxis protocol extension and separated from `POST /v1/responses` by transport. Drift checks skip declared extensions and fail if one later appears in the specification. Add `cargo xtask check-responses-registry`, wired into `make lint`, comparing registered method, path, and operation ID against the pinned specification. The check projects the specification through the existing semantic YAML reader, because the pinned document contains an integer that serde_yaml cannot parse. The registry lives in a subdirectory because non-anchor files in a filter category root are parsed as shared types by the filter doc generator, which would otherwise leak registry type documentation into unrelated filter docs. Closes praxis-proxy#743 Signed-off-by: Charlie Doern <cdoern@redhat.com>
94b4e25 to
e209fa8
Compare
Closes #743
Stacked on #772
The first commit on this branch,
edee244, is the #746 work under review in #772.It is included because this registry is the first consumer of it. Merge #772
first; this branch will then contain only its own commit. Review just
e09e42dhere.Summary
Responses operation identity came from path string matching in the request
classifier — hand-written prefix and suffix checks per endpoint. This declares
the supported operations in a family-owned registry instead, so identity comes
from method, path, and protocol headers before any payload is read.
Eight operations are registered against the shared registry:
createResponse/responsespraxis_createResponseWebSocket/responsesgetResponse/responses/{response_id}deleteResponse/responses/{response_id}cancelResponse/responses/{response_id}/cancellistInputItems/responses/{response_id}/input_itemsGetinputtokencounts/responses/input_tokensCompactconversation/responses/compactOperation IDs are the official ones from the pinned specification, reproduced
verbatim — including upstream's casing for the last two.
Contract ownership
Praxis proxies the Responses contract rather than owning it, so every operation
declares its runtime request-body shape without an owned OpenAPI contract. This
is the first registry to depend on body shape being independent of contract
ownership, which is the change #746 makes.
WebSocket as a protocol extension
The pinned specification does not represent the Responses WebSocket handshake as
an HTTP operation, so it is declared an explicit Praxis protocol extension and
separated from
POST /v1/responsesby transport rather than by inspecting abody. Drift checks skip declared extensions, and fail if one later turns up in
the specification.
Drift check
cargo xtask check-responses-registry, wired intomake lint, comparesregistered method, path, and operation ID against the pinned specification.
It projects the specification through the existing semantic YAML reader rather
than parsing it directly, because the pinned document contains an integer
(
components.schemas.CreateChatCompletionRequest.allOf[1].properties.seed.minimum,line 32725) that
serde_yamlrejects.Verified to fail correctly: renaming
cancelResponsein the registry producesand exit code 1.
File placement
The registry lives in
responses/routes/mod.rsrather thanresponses/routes.rsbecause the filter doc generator parses non-anchor files in a category root as
shared types. As a plain file it leaked registry type documentation into four
unrelated filter docs, replacing their descriptions with
"Static metadata for one Responses operation".
Testing
cargo test --workspace— all suites pass, including 2556 inpraxis-ai-apismake lint— passes end to end, including the new drift checkmake doc— cleanNew coverage: every registered operation resolving from its own template, static
endpoints not consumed as response IDs, identifier paths still capturing the
response ID, create and WebSocket separated without reading a body, unsupported
methods and unknown subresources not matching, body-bearing versus bodyless
shapes, registry key and operation ID uniqueness, and the WebSocket operation
being the only declared protocol extension.
Not in scope
Switching the classifier and Responses filters over to consume this registry
depends on the
openai_operationclassifier in #744.