feat(eval): ab-test config-bundle run (create) - #2113
Conversation
Adds `agentcore eval ab-test config-bundle run` — the first create in the ab-test family. Runs an A/B test between two config-bundle versions on one gateway. --control / --treatment / --gateway-filter each accept inline JSON, file://<path>, or - (stdin) via SourceResolver (same shape as online-eval create's --filters). Core provisions an IAM execution role when --role-arn is omitted (mirrors online-eval create + retryWhileRolePropagates), and rolls the role back if CreateABTest fails. Validation is server-side (gateway READY, bundles, online-eval enabled iff enableOnCreate) — the CLI resolves ids to ARNs and surfaces the service's 4xx cleanly. Note: --runtime dropped (not a CreateABTest field) and deviates from doc.
- Reject control/treatment only when the (config-bundle, bundle-version) pair is identical, not on version-string collision across different bundles. - Retry CreateABTest on data-plane AccessDenied (403), not just the control-plane role-not-propagated phrasing, so a freshly provisioned role that is mid-propagation is retried. - Extract accountId via a throwing helper instead of a silent '*' fallback. - --treatment-weight must be an integer. - Add unit tests for the execution-role module (name cap, trust + inline policy, create vs reuse).
|
Claude Security Review: no high-confidence findings. (run) |
There was a problem hiding this comment.
AgentCore Harness Review
Verdict: Looks good
Nice, tightly-scoped PR. A few observations, none of which I think need to block merging:
retryWhileRoleUnassumableinsrc/core/eval.tsxretries on anyAccessDeniedException/ HTTP 403. Because callers using their own--role-arnbypass this path (the ternary increateConfigBundleABTest), this is only reached for auto-provisioned roles — where the retry is well justified. It does mean a genuinely misconfigured auto-provisioned role (or a caller missingbedrock-agentcore:CreateABTest— though that would be surprising to reach this call at all) will add up to ~15s before surfacing the real error. Fine as-is, worth revisiting if the retry ever gets reused elsewhere.provisionAbTestRoleunconditionally callsPutRolePolicyeven when the role already existed, which overwrites any prior inline policy underABTestExecutionPolicy. Since we own the role name (deterministic,AgentCoreABTest-…), this is intentional and correct — just noting so the invariant is explicit.- On failure cleanup,
deleteAbTestRoleonly removes the single inline policy we attached and then deletes the role, and only runs whenprovisioned.createdis true. That is the safe subset. If a future change ever attaches managed policies here, the cleanup will need to grow to match. abTestExecutionRoleNameuses the rawtestNamein the base. IAM role names are constrained to[\w+=,.@-]; if AgentCore ever accepts A/B test names outside that set,CreateRolewill fail with an IAM-shaped error rather than something the user can act on. Probably a non-issue given the service's own name validation, but worth keeping in mind.
Tests correctly mock only at the AWS SDK client boundary (IAMClient.send) and at the Core interface, which matches the guidance. No handler-level telemetry is needed here — telemetry is centralized in this repo.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## refactor #2113 +/- ##
============================================
- Coverage 97.38% 97.08% -0.30%
============================================
Files 440 443 +3
Lines 26626 26955 +329
============================================
+ Hits 25929 26170 +241
- Misses 697 785 +88 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Match online-eval create's flag ergonomics: replace the boolean opt-out --disable-on-create with a value flag --enable-on-create <true|false> (default true). Input carries enableOnCreate?: boolean; core sends enableOnCreate ?? true.
|
Claude Security Review: no high-confidence findings. (run) |
Drop the duplicate retryWhileRoleUnassumable I added; broaden the existing retryWhileRolePropagates to also retry on data-plane AccessDenied/403 (how a freshly-provisioned role surfaces on CreateABTest) and reuse it. Removes the cross-file name collision with harness's helper.
258461d to
60e8758
Compare
|
Claude Security Review: no high-confidence findings. (run) |
Command structure
Starts an A/B test that splits gateway traffic between two config-bundle versions on one runtime. First create command in the
ab-testfamily (get/list/pause/resume/stop/delete already merged in #2102).Actual input → output
Input (run against the exploratory account, us-west-2):
Actual output — the CLI resolves + validates the gateway before any create, so an unreachable gateway fails fast and creates nothing:
Output on success (shape returned by
CreateABTest— a real create was intentionally not run: it provisions IAM + routes live traffic on a shared account):{ "abTestId": "orders-prompt-v2-rollout-abc123", "abTestArn": "arn:aws:bedrock-agentcore:us-west-2:…:ab-test/orders-prompt-v2-rollout-abc123", "name": "orders-prompt-v2-rollout", "status": "CREATING", "executionStatus": "RUNNING", "createdAt": "2026-08-26T15:00:00.000Z" }With
--enable-on-create false,executionStatusisNOT_STARTED(created PAUSED, no traffic).How it works
CreateABTestCommandon the data-plane client. BuildsC/T1variants (weights100 - w/w),evaluationConfig = { onlineEvaluationConfigArn }, and passes--gateway-filterstraight through as the SDKGatewayFilter.--control/--treatment/--gateway-filtereach accept inline JSON,file://<path>, or-(stdin) viaSourceResolver— same pattern asonline-eval create's--filters.--role-arnis omitted, Core provisions one (abTestExecutionRole.ts: confused-deputy-scoped trust + gateway-rule/get inline policy), retriesCreateABTestwhile IAM propagates (data-plane 403 too), and rolls the role back if create fails.CreateABTestvalidates gateway READY, bundle versions, and the online-eval (enabled iff starting) by assuming the role. The CLI resolves ids → ARNs and surfaces the service's 4xx; no duplicated client-side state machine.--runtimedropped — not aCreateABTestfield (deviates from the doc on purpose).Tests
ab-test.create.test.tsx— flag→request mapping,--gateway-filterpassthrough,--enable-on-create/--role-arn, identical-variant rejection, weight bounds, required-flag matrix, malformed/mis-shaped JSON.abTestExecutionRole.test.ts— 64-char name cap, trust + inline policy bodies, create-vs-reuse.Bug bash — 4 agents + live exploratory (us-west-2)
(bundle, version)pair (was version-only);CreateABTestretries on data-planeAccessDenied;accountIdextraction throws instead of a silent"*";--treatment-weightmust be an integer; added the role-module unit tests.bun test→ 723 pass / 0 fail ·typecheck→ 0 errors ·oxlint→ clean.Follow-ups (separate PRs)
--jsonerror output (errors print plain text to stderr — cross-cutting, all commands).config-bundle run.stop's gateway-rule promotion suggestion (still a TODO).