CUJ2 inference E2E in the UAT runner + nightly both-intent (#1276)#1597
Conversation
📝 WalkthroughWalkthroughThis PR adds inference serve execution to the AWS and GCP UAT runners, including new Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/uat-aws.yaml:
- Around line 182-201: The main-cell build step in the workflow currently only
prints `./aicr --version`, so a broken ldflags stamp could still pass with
default metadata. Update the `run` block that builds `./aicr` and calls `./aicr
--version` to assert the output contains both `main` and `${COMMIT_SHA}`, so the
step fails if `github.com/NVIDIA/aicr/pkg/cli.version` or
`github.com/NVIDIA/aicr/pkg/cli.commit` are not stamped correctly.
In @.github/workflows/uat-gcp.yaml:
- Around line 180-199: The workflow step that builds and runs ./aicr --version
currently does not verify that the ldflags stamping worked, so a broken
github.com/NVIDIA/aicr/pkg/cli.version, commit, or date target could still pass
unnoticed. After the build in the main-only version stamping step, assert that
the version output includes the expected main value, the COMMIT_SHA env value,
and the BUILD_DATE used in the go build command, so the step fails if the binary
still reports the default metadata.
In `@tests/uat/aws/run`:
- Around line 555-560: The current fast-fail check only detects pods with
phase=Failed, so it does not catch crash loops or image-pull failures that
remain in Running or Pending. Update the guard in the workload-pod polling logic
to also inspect container waiting states such as CrashLoopBackOff,
ImagePullBackOff, and ErrImagePull (using the same pods_json/jq flow), and
adjust the surrounding comment so it only claims behavior the check actually
enforces.
In `@tests/uat/gcp/run`:
- Around line 555-560: The fast-fail check only looks at pod phase in the run
script, so it misses crash-loop and image-pull failures. Update the pod health
guard in the workload polling logic to also inspect container waiting states
(for example in the same jq-based check used for pods_json) and treat reasons
like CrashLoopBackOff, ImagePullBackOff, and ErrImagePull as terminal-bad; if
you choose not to broaden the check, then soften the comment so it only
describes phase=Failed detection. Use the existing pod polling block and the
related logic mirrored in tests/uat/aws/run to keep behavior consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 3021cd14-fac2-439b-a318-c8a0032fda0a
📒 Files selected for processing (14)
.github/workflows/uat-aws.yaml.github/workflows/uat-gcp.yaml.github/workflows/uat-nightly-batch.yamldocs/contributor/uat.mdinfra/uat/reservations.yamlpkg/uatbroker/model.gopkg/uatbroker/registry.gopkg/uatbroker/registry_test.gotests/uat/aws/runtests/uat/aws/tests/cuj2-inference/chainsaw-test.yamltests/uat/gcp/runtools/uat-broker/README.mdtools/uat-broker/main.gotools/uat-broker/main_test.go
…VIDIA#1276) Bring real-cluster inference to CUJ1 parity (DC3). phase_serve (tests/uat/{aws,gcp}/run): deploy a Dynamo DynamoGraphDeployment (KAI queue + DRA claim + Frontend/decode-Worker graph), wait for readiness, port-forward the frontend, issue an OpenAI-compatible /v1/chat/completions request, and assert a non-empty completion. Fails closed with captured pod logs/events on a non-ready deployment or invalid completion, mirroring phase_train. run all selects train vs serve by the config's recipe intent. phase_conformance cross-checks the declared platform against the deployed workload CRD (dynamo vs kubeflow), since the TestGrid coordinate is otherwise cluster-unverifiable. Workflows (uat-{aws,gcp}.yaml): add an intent-gated 'UAT - serve' step mirroring train; summary row and serve-logs artifact. Nightly cadence: both training and inference run nightly on both clouds, folded into the version matrix as serialized cells (version outer / intent inner loop) through the shared per-reservation lease -- no second cron, no contention, and main lands both intents before any release cell. Driven by a new data-driven nightly-intents list in infra/uat/reservations.yaml (pkg/uatbroker + uat-nightly-batch.yaml). Stamp the main-cell binary via ldflags (version=main, commit, date) so the emitted recipe/evidence report 'main' instead of the un-stamped 'dev'; pin main-cell validator images to the run's own :uat-<run_id> build (mirroring the agent pin) so the version label change does not redirect image resolution. Docs: document the inference UAT path, phase_serve, and the nightly cadence in docs/contributor/uat.md; fix the chainsaw test's demos/cuj2-inference.md ref. Signed-off-by: Nathan Hensley <[email protected]>
c3274ea to
59f6f5a
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/uat-nightly-batch.yaml (1)
147-147: 🩺 Stability & Availability | 🔵 TrivialNightly cell count doubles per reservation; time-box budget unchanged.
With
nightly-intents: [training, inference]now set on both reservations (infra/uat/reservations.yaml), each version now dispatches two full cells instead of one, butDEADLINE_OFFSET_HOURSstill defaults to'5'here. The graceful drop-oldest-first logic (break 2) will mask this, but confirm that 5h is still sufficient to runmain× 2 intents +previous_n× 2 intents before older release cells start getting silently dropped every night.Also applies to: 203-215
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/uat-nightly-batch.yaml at line 147, The nightly batch deadline budget may now be too tight because both reservations dispatch two intents per version, doubling the number of cells while DEADLINE_OFFSET_HOURS in the uat-nightly-batch workflow still defaults to 5 hours. Review the scheduling and drop-oldest-first behavior around the nightly batch flow, especially the inputs handling in the workflow and the reservation intent fanout, and either पुष्टि that 5 hours remains sufficient for main and previous_n across both intents or increase the default/override accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/contributor/uat.md`:
- Line 53: Update the CUJ reference in the `intent=inference` → `phase_serve`
description so it matches the served-inference flow described by
`demos/cuj2-inference.md`. Replace the incorrect “CUJ1 parity” wording with the
correct CUJ2 reference in that same sentence, keeping the rest of the
`phase_serve` explanation unchanged.
---
Outside diff comments:
In @.github/workflows/uat-nightly-batch.yaml:
- Line 147: The nightly batch deadline budget may now be too tight because both
reservations dispatch two intents per version, doubling the number of cells
while DEADLINE_OFFSET_HOURS in the uat-nightly-batch workflow still defaults to
5 hours. Review the scheduling and drop-oldest-first behavior around the nightly
batch flow, especially the inputs handling in the workflow and the reservation
intent fanout, and either पुष्टि that 5 hours remains sufficient for main and
previous_n across both intents or increase the default/override accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: e139afb1-f3a4-4f5e-8bf6-9b8c400bfaa4
📒 Files selected for processing (14)
.github/workflows/uat-aws.yaml.github/workflows/uat-gcp.yaml.github/workflows/uat-nightly-batch.yamldocs/contributor/uat.mdinfra/uat/reservations.yamlpkg/uatbroker/model.gopkg/uatbroker/registry.gopkg/uatbroker/registry_test.gotests/uat/aws/runtests/uat/aws/tests/cuj2-inference/chainsaw-test.yamltests/uat/gcp/runtools/uat-broker/README.mdtools/uat-broker/main.gotools/uat-broker/main_test.go
Summary
Bring real-cluster inference to CUJ1 parity (DC3): a
phase_servestep deploys a DynamoDynamoGraphDeployment, hits its OpenAI-compatible endpoint, and asserts a completion; and the nightly batch now runs both training and inference on both clouds, serialized through the shared reservation lease.Motivation / Context
Inference was only a
--no-clusterdry-run that no workflow invoked — no inference column existed on any cloud. This makes inference a real cluster phase, the counterpart ofphase_train, and wires it end-to-end so nightly runs exercise a served endpoint and emit a signed bundle whose criteria map toinference-dynamo.Fixes: #1276
Related: #1596 (follow-up: surface the build commit on the corroboration dashboard)
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)cmd/aicrd,pkg/server)pkg/recipe)pkg/bundler,pkg/component/*)pkg/collector,pkg/snapshotter)pkg/validator)pkg/errors,pkg/k8s)docs/,examples/)tests/uat/**,.github/workflows/uat-*), reservation broker (pkg/uatbroker,tools/uat-broker)Implementation Notes
phase_serve(tests/uat/{aws,gcp}/run): deploys the KAI queue + DRAResourceClaim+ Frontend/decode-WorkerDynamoGraphDeployment(inlined fromdemos/workloads/inference/vllm-agg.yaml), waits for pod readiness, port-forwards the frontend,POST /v1/chat/completions, asserts a non-empty completion. Fails closed (captured pod logs/events underserve-logs/) on a non-ready deployment or invalid completion, mirroringphase_train. Node scheduling/model areSERVE_*-overridable; tolerations are a portable superset across both clouds.run allpicks train vs serve from the config's recipe intent; the workflows add an intent-gatedUAT - servestep mirroringtrain.phase_conformance: the declaredplatformmust match the deployed workload CRD (dynamographdeployments.nvidia.com/trainjobs.trainer.kubeflow.org), since the TestGrid coordinate is author-declared and otherwise cluster-unverifiable.mainlands both intents before any release cell. Data-driven via a newnightly-intentslist ininfra/uat/reservations.yaml(pkg/uatbroker). Trade-off: this ~doubles a reservation's cell count; the batch time-box drops oldest cells first (tuneprevious_n/deadline_offset_hours), documented indocs/contributor/uat.md.version=main+ commit + date via ldflags so evidence/results readmaininstead of the un-stampeddev. Because a realcommitwould otherwise redirect validator images:latest→:sha-<commit>(which may not exist for a feature-branch ref), main-cell validator images are pinned to the run's own:uat-<run_id>build — mirroring the existing agent pin. Release cells are unaffected (empty override → released:vX.Y.Z).Testing
Full
make qualify(e2e/grype) was not run — its e2e leg provisions real infrastructure. Per the issue's test plan, the real-hardware inference run is a manualworkflow_dispatch intent=inferenceduring bring-up; the--no-clusterchainsaw dry-run continues to validate the inference AICRConfig resolves.Risk Assessment
Rollout notes: No breaking changes. One behavior change to flag: main-cell validator images now resolve to the run's
:uat-<run_id>build instead of:latest(consistent with the agent pin; removes known:lateststaleness).nightly-intentsdefaults to[training]when absent, so the change is backward-compatible. The nightly cell count roughly doubles — see the time-box tuning note indocs/contributor/uat.md.Checklist
make testwith-race) — ran-raceon the changed Go packages (pkg/uatbroker,tools/uat-broker)make lint) —golangci-lint(affected pkgs, 0 issues) +yamllint+shellcheckgit commit -S)