Skip to content

fix(request): send filter syntax the UAR API accepts - #73

Merged
aaearon merged 2 commits into
mainfrom
fix/request-list-filter-syntax
Aug 23, 2026
Merged

aaearon merged 2 commits into
mainfrom
fix/request-list-filter-syntax

Conversation

@aaearon

@aaearon aaearon commented Aug 23, 2026

Copy link
Copy Markdown
Owner

The bug

grant request list --state, --result and --priority all failed with HTTP 400 BAD_REQUEST against the live UAR API. Every filtered invocation of the command was broken; unfiltered grant request list worked.

Measured against the live API

filter sent result
(requestState eq PENDING) OK
((requestState eq PENDING)) 400
(requestState eq 'PENDING') 400
((requestState eq 'PENDING')) 400
(priority eq High) OK
(priority eq 'High') 400
(requestResult eq APPROVED) OK
((requestState eq FINISHED) and (priority eq High)) OK

So the API requires unquoted operand values, and single parentheses around a lone condition. The outer wrap is correct only when combining two or more conditions.

The API spec (Access Requests API.json, GET /workflows/requests filter) agrees on the shape — "filter expressions must be complete within parentheses" — but its own example quotes string operands, which the live API rejects for these enum fields. The measured table wins.

The two defects, both in cmd/request_list.go

  1. params.Filter = "(" + strings.Join(filters, " and ") + ")" wrapped unconditionally. With one filter, filters[0] is already parenthesised, so it emitted ((requestState eq PENDING)) → 400.
  2. --priority was built as fmt.Sprintf("(priority eq '%s')", v) → 400. --state and --result were already unquoted.

The fix

A combineFilters helper: zero conditions → empty, one → emitted bare, two or more → wrapped once. Priority loses its quotes.

Filter strings now produced:

flags filter
none `` (empty)
--state PENDING (requestState eq PENDING)
--result APPROVED (requestResult eq APPROVED)
--priority High (priority eq High)
--state FINISHED --priority High ((requestState eq FINISHED) and (priority eq High))
--state FINISHED --result APPROVED --priority Low ((requestState eq FINISHED) and (requestResult eq APPROVED) and (priority eq Low))

An existing test had pinned the broken format

cmd/request_args_test.go asserted wantFilt: "((requestState eq PENDING))" — the exact string the API rejects. The suite was green on a command that could not work: a test passing for the wrong reason. That expectation is corrected, not preserved.

New TestRequestList_FilterSyntaxMatchesLiveAPI pins the exact filter string for every flag combination, with the measured table reproduced in a doc comment so the next person does not have to rediscover it.

Other builders of this syntax (checked, not churned)

  • cmd/request_picker.go — passes scope.filter through; correct.
  • cmd/request_finalize.go(requestState eq PENDING); single, bare, unquoted. Correct.
  • cmd/request_cancel.go((requestState eq STARTING) or (requestState eq RUNNING) or (requestState eq PENDING)); three conditions under one wrap, unquoted. Correct and consistent with the fixed rule.

request_list.go was the only wrong one. Left the three literals alone rather than routing them through the helper — they are already in the right shape and the churn would not be paid for.

One extrapolation worth flagging

The live table verifies the flat join for two conditions. Three conditions (((a) and (b) and (c))) is an extrapolation from that; the spec's own example nests binary pairs instead ((((a) and (b)) and (c))). Left-associative and parsing makes the flat form near-certain, and cmd/request_cancel.go already ships a working three-condition flat or, but it has not been directly measured with and.

Verification

gofmt -s -l . empty; go build ./..., go test -race -count=1 ./..., go test -shuffle=on -count=1 ./..., go test -tags=integration -count=1 ./cmd, golangci-lint run — all exit 0.

`grant request list --state`, `--result` and `--priority` all returned
HTTP 400 BAD_REQUEST. Two defects in the filter builder:

- a lone condition was wrapped a second time, emitting
  `((requestState eq PENDING))`; the API only accepts `(requestState eq PENDING)`
- the priority operand was quoted, emitting `(priority eq 'High')`;
  the API only accepts `(priority eq High)`

Both confirmed against the live API. Two or more conditions still get the
single outer wrap, `((a) and (b))`, which the API accepts.

`TestRequestList_ParamsFromFlags` had pinned the broken double-wrapped
string, so the suite passed for the wrong reason; that expectation is
corrected and `TestRequestList_FilterSyntaxMatchesLiveAPI` now pins the
exact string for every flag combination.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is narrowly scoped to filter-string construction, matches the documented live API behavior, and is covered by updated and newly added tests.

Pull request overview

This PR fixes grant request list filtered queries by aligning the generated UAR OData filter string with what the live API actually accepts, restoring functionality for --state, --result, and --priority.

Changes:

  • Add combineFilters to avoid emitting an invalid double-wrapped filter when only one condition is present.
  • Remove single-quote wrapping from the --priority operand so enum values are sent unquoted.
  • Update and add tests to pin the live-API-accepted filter syntax, and record the fix in the changelog.
File summaries
File Description
docs/mutation-ledger.md Updates mutation ledger line references to match the shifted code after the fix.
cmd/request_list.go Fixes filter construction (no redundant outer parens for single conditions; unquoted priority).
cmd/request_args_test.go Corrects the previously wrong expectation and adds a dedicated filter-syntax regression test suite.
CHANGELOG.md Documents the user-visible fix for filtered grant request list invocations.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@aaearon
aaearon merged commit 812660b into main Aug 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants