AIR CLI Migration: resolve usage_policy_name to a policy id - #6152
Merged
Conversation
Collaborator
Integration test reportCommit: b458f66
8 interesting tests: 4 RECOVERED, 4 SKIP
Top 6 slowest tests (at least 2 minutes):
|
riddhibhagwat-db
force-pushed
the
air-usage-policy-resolution
branch
from
August 4, 2026 00:47
d1b0449 to
6a3b428
Compare
Ports the usage policy name->id resolution from the Python CLI (cli/serverless_policy_client.py), which `air run` previously rejected with "usage_policy_name is not yet supported". usage_policy_id was also validated and then silently dropped: nothing wired it into the runs/submit payload. Both paths now populate budget_policy_id, the field the AI Runtime backend reads (matching the Python CLI). The resolver pages GET /api/2.0/serverless-policies with the partial, case-insensitive filter_by.policy_name filter, then re-applies an exact case-insensitive match locally. Not-found errors list candidate names; an ambiguous match refuses to guess rather than pick the wrong policy. Resolution happens before any artifact upload so a bad name fails fast. Also ports the UUID-shape check on usage_policy_id, so a policy name pasted into the id field gets an error pointing at usage_policy_name. Co-authored-by: Isaac
- Dedupe policies by policy_id across pages and track seen page tokens, matching the pager in aitraining.go. A repeated page previously appended the same policy twice, so an unambiguous name failed as "multiple usage policies match". The token guard now also catches an A->B->A cycle, not just a self-repeat. - Run the local idempotency-token check before the policy lookup, so a bad --idempotency-key fails without spending an API round trip. - Assert the "resolve before any artifact upload" ordering instead of only claiming it in a comment. - Require a non-empty filter in listUsagePolicies; the unfiltered list mode had no production caller. - Soften the budget_policy_id comment to cite the Python CLI and ssh connect rather than assert unverified backend behavior. Co-authored-by: Isaac
Two gaps found reviewing my own change after the agent pass: - The --override path re-decodes and re-validates, so mutual exclusion and the UUID check apply to overridden values too. That was untested; both hold. - A 403/5xx from the policy list call must surface rather than fall through to an empty (= no policy) id. It does, via the %w wrap. Co-authored-by: Isaac
riddhibhagwat-db
force-pushed
the
air-usage-policy-resolution
branch
from
August 4, 2026 18:06
6a3b428 to
be6a637
Compare
ben-hansen-db
approved these changes
Aug 4, 2026
ben-hansen-db
left a comment
Contributor
There was a problem hiding this comment.
Looks good, thanks for adding
|
|
||
| // suggestionHint renders a deduplicated, sorted "did you mean" clause for the | ||
| // candidates the partial filter returned, or "" when there are none. | ||
| func suggestionHint(candidates []usagePolicy) string { |
Contributor
There was a problem hiding this comment.
one UX to consider. Display name and policy name are different. policy_name is unique display_name. If users post display_name instead probably policy_name will come up.
Maybe add a comment about this
Contributor
Author
There was a problem hiding this comment.
Added in a comment!
…name The serverless-policy API returns both policy_name and display_name, and filter_by can only match policy_name. Per serverless-policy/api/proto/ message.proto, display_name equals policy_name for user-created policies and is fixed to "Default Policy" for the system defaults, so a user who supplies a UI display name lands on the not-found error, which lists real policy_names as candidates. Record why display_name is deliberately not read. Co-authored-by: Isaac
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.
Changes & Why
usage_policy_id was also validated and then silently dropped: nothing wired it into the runs/submit payload. Both paths now populate budget_policy_id, the field the AI Runtime backend reads (matching the Python CLI).
The resolver pages GET /api/2.0/serverless-policies with the partial, case-insensitive filter_by.policy_name filter, then re-applies an exact case-insensitive match locally. Not-found errors list candidate names; an ambiguous match refuses to guess rather than pick the wrong policy. Resolution happens before any artifact upload so a bad name fails fast.
Also ports the UUID-shape check on usage_policy_id, so a policy name pasted into the id field gets an error pointing at usage_policy_name.
Tests
Unit tests: usagepolicy_test.go (new)
Unit tests: runsubmit_test.go / runconfig_test.go (modified)
Acceptance tests