feat(agent-bff): validate filters, sorts, and projections from capabilities#1755
Open
Conversation
…lities Add a reusable, pure validator that checks a request's filter, sort, and projection fields against a collection's capabilities before any agent call, plus an operator normalizer mapping agent snake_case operators to the canonical PascalCase set from datasource-toolkit `allOperators`. - unknown_field (422) for a filter/sort/projection field absent from capabilities - field_not_filterable (422) for a filter field present with no operators - invalid_filter_operator (400) with validOperators for an unsupported operator - sort/projection check existence only; capabilities is the only source of truth - unmapped capabilities operator throws 500 mapping_error (version skew) `CapabilitiesResult.operators` made optional to match runtime (relations omit it). Fixes PRD-675 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A condition-tree leaf always carries an operator; one without a valid operator is malformed and must not reach the agent. Previously such a leaf bypassed operator validation and was forwarded untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a reusable, pure validator in
agent-bffthat checks a list/count request'sfilter,sort, andprojectionfields against the target collection's capabilities before any agent call, plus an operator normalizer. Capabilities are the only source of truth — no hardcoded type table is consulted, which fixes the drift between the frontend operator tables and what the agent actually supports.This is the reusable validator only. Wiring it into the endpoints is out of scope (PRD-676/677).
How
operator-normalizer.ts— maps agent snake_case capabilities operators to the canonical PascalCase set. The snake→Pascal map is derived from datasource-toolkitallOperatorsusing the same transform the agent uses to serialize them, so it round-trips every operator and cannot drift.validation-errors.ts— three error factories owned by this slice, reusing the existing error-envelope shape ({ error: { type, status, message, details } }) without touching the shared registry.capabilities-validator.ts—validateAgainstCapabilities()returns every offending field as aBffHttpError[](empty = valid);assertValidAgainstCapabilities()throws the first. Walks every filter leaf (including underAnd/Orgroups).Validation rules
422 unknown_field422 field_not_filterable400 invalid_filter_operator(+validOperators)422 unknown_field422 unknown_fieldSort/projection check existence only; operator checks apply to filters. Each error carries the offending
details.field.Notable decisions
allOperatorsset, not justuniqueOperatorsas the ticket wording suggests — real capabilities includein,contains,blank, etc.operatorskey (notoperators: []); treated asfield_not_filterableviaoperators ?? [].CapabilitiesResult.operatorsmade optional to match runtime. See the ticket comment for the invariant discrepancy.500 mapping_error(loud) rather than dropping or passing it through — this only happens on an agent/BFF version skew.Tests
22 new focused unit tests: normalizer round-trip over all operators + edge cases; every error case; a fully-valid request; a mapping_error case; and an assertion that a field absent from capabilities is rejected with no type table consulted. Full suite: 660/660 green.
Fixes PRD-675
🤖 Generated with Claude Code
Note
Validate filters, sorts, and projections against collection capabilities in agent-bff
validateAgainstCapabilitiesincapabilities-validator.tsto check request filter fields/operators, sort fields, and projection fields against collection capabilities, returning structuredBffHttpErrorarrays.operator-normalizer.tsto convert between PascalCase and snake_case operator formats, bridging the agent's serialization format and the canonical@forestadmin/datasource-toolkitoperator names.unknownField,fieldNotFilterable,invalidFilterOperator) invalidation-errors.tswith standardized HTTP status codes (400/422).mapping_errorif a capabilities operator cannot be normalized to a canonical name.Macroscope summarized dc02e94.