Skip to content

[Epic]: Single-path CNCF AI conformance validation and submission evidence #3601

Open
16 of 16 issues completed
Open

Description

@yuanchen8911

Outcome

aicr validate --phase conformance is the only runner for CNCF AI conformance. A flag decides whether evidence is written and in what layout; for the same selected checks it never changes what a check does. One run on a cluster produces a submission directory that passes the upstream validator with no hand-run checks, no hand-written PRODUCT.yaml, and no hand redaction. The requirement set tracks the CNCF version being submitted; a requirement is Implemented only when every expected check is present and passed, an incomplete applicable MUST fails the run, and an unclaimed SHOULD renders Not Implemented without failing it.

Where things stand

AICR has two unrelated implementations of every CNCF requirement.

  • Path A: Go validators in validators/conformance/, run by aicr validate --phase conformance. Their stdout artifacts become evidence/*.md through pkg/evidence/cncf/renderer.go when --evidence-dir is set. This is what nightly UAT runs.
  • Path B: the 3,548-line bash script pkg/evidence/cncf/scripts/collect-evidence.sh, embedded in the binary and run by --cncf-submission. That flag short-circuits validation (pkg/cli/validate.go, the "Short-circuit" block): under it the Go checks never run.

Both deploy workloads and keep separate verdict logic; docs/conformance/cncf/index.md documents them as "Two Modes". The script is deeper for gang scheduling (two-phase GPU barrier on a pinned node vs CPU-only PodGroup in Go), HPA (CUDA stress vs metrics-API probe), and metrics (DCGM and Prometheus query capture vs an 80-line Go check). Go is deeper for secure access (1,687 lines, sibling-container isolation), cluster autoscaling (AKS branch, fail-closed list errors), and the gateway (data-plane readiness, exposure policy).

The NVKE v1.36 submission still needed four hand-run checks on top of the script (gateway traffic, RuntimeClass bypass probe, TrainJob reconciliation, autoscaling N/A text), plus hand-written PRODUCT.yaml, README, platform-configuration.md and hand redaction. review of #3455 caught a PRODUCT.yaml note (SR-IOV resources) whose cited evidence did not show the claim. #3155 sets the bar: incomplete results cannot masquerade as passing, and evidence must describe what was actually checked. The v1.2 release update names the next NVKE items: explicit secondary-network attachment checks and durable Multus token rotation.

Upstream requirement drift (checked 2026-11-03)

Version Change AICR today Gap
v1.36 dra_support removed as a requirement; advanced_inference_ingress, high_performance_networking, disaggregated_inference added (SHOULD) requirements.go still maps dra-support to dra_support; no mapping for the three SHOULDs Renderer presents a retired requirement; SHOULD rows are hand-typed
v1.37 workload_sandboxing added (SHOULD). Hybrid verification: junit.xml and e2e.log recommended from the kubernetes-sigs/ai-conformance suite; file://...#TestName links; scripts/validate.go parses the artifacts No junit or e2e.log emitter; evidence is Markdown only Submissions at v1.37 fall back to manual attestation for everything
v1.38 (announced in the KARs) driver_runtime_management and workload_sandboxing graduate to MUST No check for either. The deployment phase proves the GPU Operator is healthy but not the upstream contract (vanilla ubuntu:22.04 pod gets nvidia-smi injected, driver version matches the GFD label or ResourceSlice driverVersion). No sandboxed RuntimeClass (gVisor or Kata) exists in any AICR recipe Two new MUSTs, one of which is a product gap for NVKE, not only a validator gap
Upstream test suite semantics TestGatewayAPIInference: OpenAI-Project: ai-conformance-canary header to model-v2, 70/30 split within 5% over 500 requests. TestHPAAutoscaling: custom per-pod metric, 2 accelerators. TestAIServiceMetrics: collected count increases by exactly the requests sent. TestSecureAcceleratorAccess, TestGangScheduling, TestRobustCRDControllerOperation AICR's checks test similar things with different thresholds and no shared names Upstream validate.go (PR #168 maps ai_inference to TestGatewayAPIInference) credits junit testcases by upstream name, so AICR-named testcases would not be credited
Vendor names Requirement titles in requirements.go say "agentgateway" and "Dynamo Platform" Hard-coded Conflicts with #3588's gateway-neutral direction

Validation gaps

Requirement Gap Where Tracker
ai_inference No traffic test (header route, weighted split) Both paths check only Accepted and Programmed #3428
ai_inference agentgateway hard-coded in check, perf validator, script, catalog Go and script #3588, PR #3589 (open)
ai_inference HTTPRoute count matches parent name only inference_gateway_check.go:513 #3597
secure_accelerator_access No unprivileged RuntimeClass: nvidia + NVIDIA_VISIBLE_DEVICES=all probe; stock check passed before and after the toolkit hardening Go sibling test relies on the CUDA image baking the envvar #3428
robust_controller Webhook rejection only; no CR reconciled to completion; NIM and Dynamo probes never run live Both #3428, #2137
gang_scheduling No all-or-nothing negative case (upstream TestGangScheduling: a non-fitting Job keeps zero pods bound) Go check proves co-scheduling only #3603
pod_autoscaling, accelerator_metrics, ai_service_metrics HPA not driven on GPU-requesting pods with a custom metric; no DCGM or Prometheus capture; collected-count assertion missing Go #3604
cluster_autoscaling EKS and AKS fallback paths pass on node-group membership with no observed scale event; unrecognized providerID skips with "not EKS, GKE, or AKS" (a missing probe, not product nonapplicability) cluster_autoscaling_check.go:543-620 #3428
driver_runtime_management, workload_sandboxing No check; MUST at v1.38 none #3615
dra_support Still a requirement in the renderer; SHOULD rows typed by hand requirements.go:37 #3606
recipe coverage The NVKE kubeflow leaf declares no gang, HPA, secure-access or gateway check, so a submission run on it cannot evidence those MUSTs; refusing --skip-check does not cover this recipes/overlays/nvke.yaml, gb200-nvke-ubuntu-training*.yaml #3612 (expected-check table), #3605 (wiring)
status aggregation Renderer drops skipped checks and marks a requirement passed unless a test is exactly failed; other, pending, missing or crashed checks read as passed renderer.go:143-200 #3612
evidence header Cluster name blank on bare metal script #3428
provenance Node image and bootstrap version, validator image digests, trust class not recorded snapshot, attestation #3509, #2882, #2877
integrity PRODUCT.yaml notes can cite evidence that does not show the claim manual authoring #3455 review
recipe qualification (not a CNCF MUST) Secondary networks pass with no attachment exercised; Multus thin token expiry after 1h deployment phase #3474, #3482

Design: one path

Principle: aicr validate --phase conformance is the only runner. The recipe defines which conformance checks run; every run executes all of them at the depth the CNCF bar requires (#3619). Flags never change what a check does or how it decides. Nightly UAT and a CNCF submission run the identical check set; the submission run additionally writes the submission directory. The bash collector and its --feature section interface are deleted.

Commands:

  • aicr validate -r recipe.yaml -s snapshot.yaml --phase conformance: every check the recipe lists. CTRF report and recipe-evidence attestation as today. No evidence files. This is the nightly run.
  • aicr validate -r recipe.yaml -s snapshot.yaml --phase conformance --cncf-submission --evidence-dir <dir>: the same run, plus PRODUCT.yaml, README.md (with the platform facts PRODUCT.yaml notes cite), junit.xml, e2e.log and the existing evidence/<requirement>.md pages, redacted in one pass, then the pinned upstream validator as the last step. --cncf-submission and --evidence-dir require each other; --recipe is required; --skip-check and --no-cluster are refused. Vendor fields and the conditional cluster_autoscaling N/A justification come from the validate config. Statuses come from the run (evidence: fail-closed requirement status aggregation scoped by level #3612): an incomplete applicable MUST fails the run; a SHOULD with incomplete or absent checks renders Not Implemented without failing.

Not in the design (removed 2026-11-04 after the CNCF-bar audit, #3619): depth tiers or sibling checks, a nightly --skip-check list, a weekly full-depth lane, typed artifacts in the signed bundle, platform-configuration.md, the collector's GPU gang barrier, CUDA stress and nvidia-smi/DCGM captures. --skip-check remains only for lanes that cannot host a check at all (Kind, KWOK).

Nightly UAT budget

Nightly UAT already runs --phase all on cells with two GPU nodes. The parity ports to the CNCF bar add one CPU-only gang Job, one HPA cycle on 2 GPUs, one TrainJob and gateway traffic on CPU backends, estimated at 5 to 8 minutes with the HPA scale-down as the long pole; recipes that gain checks through #3605's wiring (EKS, AKS and NVKE training bases) see the largest delta. #3609 measures the cost and raises the step budget. Checks run serially on a cell.

Options considered on 2026-11-03 (one depth always-on; two tiers as sibling checks; a depth flag; delegating deep MUSTs to the upstream suite) are recorded in the ADR-007 amendment (#3614). The two-tier option was chosen that day and superseded on 2026-11-04 once the audit showed the expensive tests exceeded the CNCF bar; AICR's junit carries AICR check names referenced by file://...#<check> fragments, and the upstream suite remains optional independent verification.

Plan (sub-issues, in merge order)

  1. docs(adr): amend ADR-007 for single-path CNCF conformance evidence #3611 docs(adr): amend ADR-007. Lands first.
  2. evidence: key the CNCF requirement map by Kubernetes version and drop vendor names from titles #3606 evidence: complete upstream checklist per Kubernetes version with expected checks per requirement; vendor names out of titles; pinned schemas; unsupported versions refused.
  3. conformance: align checks and submission output to the CNCF requirement bar #3619 conformance: the CNCF-bar audit (decision record for the scope cuts below). evidence: fail-closed requirement status aggregation scoped by level #3612 evidence: fail-closed status aggregation scoped by level. Gate: lands before any parity port.
  4. Parity ports to the CNCF bar, in place (no sibling checks, no tiers), each deleting its script section: conformance: add the all-or-nothing negative case to gang-scheduling (CNCF bar) #3603 all-or-nothing negative case in gang-scheduling (CPU-only); conformance: bring pod-autoscaling and the two metrics checks to the CNCF bar #3604 HPA on GPU-requesting pods with a custom metric, plus metrics capture; conformance: own the checks hand-run for NVKE AI conformance (gateway traffic, CR reconciliation, RuntimeClass extra, autoscaling claim) #3428 gateway traffic (on feat(validator): gateway-neutral inference-gateway check #3589), CR reconciliation to completion, the RuntimeClass probe as an AICR extra, cluster-autoscaling constrained claim; inference-gateway check counts HTTPRoutes attached by parent name only, ignoring namespace #3597 and [Feature]: Gateway selection for inference recipes and a gateway-neutral inference-gateway check #3588 gateway fixes.
  5. validate: run CNCF submission evidence from the conformance phase and retire collect-evidence.sh #3602 validate: --cncf-submission --evidence-dir renders from the conformance run (each requires the other; evidence only for submissions); delete the collector and remaining script; --feature removed; facade migration semantics specified. Gate: a requirement-by-requirement comparison of a Go run against a script run attached before deletion, scoped to the CNCF bar.
  6. evidence: generate the CNCF submission directory (PRODUCT.yaml, README, junit.xml, e2e.log, redaction) #3605 evidence: submission packaging (PRODUCT.yaml, README with the platform facts, junit.xml, e2e.log with #<check> references, one redaction pass, pinned upstream validator gate; vendor fields from config) and the NVKE proof run.
  7. NVKE proof (in evidence: generate the CNCF submission directory (PRODUCT.yaml, README, junit.xml, e2e.log, redaction) #3605): wire NVKE recipes to the expected checks, regenerate v1.36 through the single path, explain every status difference by evidence, dry-run the v1.37 shape.

In parallel at any point: #3615 v1.38 readiness (driver-runtime-management; workload sandboxing, where a CPU-pool runtime suffices and a missing runtime is Not Implemented, never N/A); #3509 node image and bootstrap in evidence; #3474 secondary-network attachment probe (v1.2 "Next" item).

Related, owned elsewhere (not sub-issues): #3588 gateway selection for inference recipes (iracic82), #3474 secondary-network attachment exercise (atif1996), #3509 node image and bootstrap version in evidence; follow-ups and gaps after this epic are tracked under #3710 (sub-issues #3704, #3705, #3709); #3155 (parent outcome), #1044, #2137 and #2877 (children of #3155), #2882, #3482.

NVKE v1.36 validation run, for provenance (closed): #3439 RDMA fabric gate stability window, #3452 KWOK NVKE cleanup on the SR-IOV pre-delete hook, #3361 check-nvidia-smi skipped every GPU node when one was busy, #3384 sensitive information removed from docs and issue text. #3389 (the NVKE conformance tracker) is attached as a sub-issue.

Upstream validator assumptions (checked 2026-11-04)

The submission generator targets the upstream validator at cncf/k8s-ai-conformance commit c64e5bc (scripts/validate.go, instructions.md) and the kubernetes-sigs/ai-conformance tests at fd9ba2d. The pinned revision is recorded in the submission README. These are the behaviors the design relies on; a bump of the pin re-checks each one.

  • Fragments on every artifact reference. A reference to junit.xml or e2e.log without #<check> is resolved through the validator's upstream-test-name map and fails "not found" for an AICR-named testcase. The generator writes file://...#<check> on every reference, e2e.log included.
  • e2e.log shape. The validator parses go test -v output: one --- PASS|FAIL|SKIP: <check> line per check. The log is emitted from the same CTRF report as junit.xml with those lines, so both artifacts agree by construction.
  • Whole-artifact failure. Any failing testcase anywhere in a referenced artifact fails that artifact before fragments are resolved. This is why the export rule is mandatory: non-passing testcases behind a Not Implemented SHOULD or an N/A-overridden MUST export as skipped with a reason; an applicable MUST failure fails the run and nothing is written.
  • Required vendor metadata. k8sConformanceUrl and productLogoUrl must be present and well-formed; they come from spec.validate.evidence.cncf.vendor and are refused up front when missing.
  • Scheduler neutrality. The requirement is scheduler-neutral and KAI satisfies it. The upstream suite's gang adapter supports only kueue and volcano, so on KAI the AICR-named junit testcase is the sole machine-checked evidence for gang_scheduling, and the optional upstream-suite add-on is partial by design. Our check must therefore meet the upstream assertion on its own (conformance: add the all-or-nothing negative case to gang-scheduling (CNCF bar) #3603).
  • ai_inference map gap. ai_inference is not in the validator's auto-tested map at the pinned revision. Its testcase is still referenced with a fragment so a later map change does not break an existing submission.

Risks and open decisions

Activity

  1. added theissue type on Nov 3, 2026
  2. 54 remaining items

  3. yuanchen8911 commented on Nov 7, 2026

    @yuanchen8911
    ContributorAuthor

    Status 2026-11-06 (end of day)

    Merged today (10 PRs): #3666 single runner and --cncf-submission from the conformance run (collector script retired); #3667 CR reconciliation, RuntimeClass hardening extra, autoscaling observations; #3672 metrics baseline race; #3682 inference-gateway traffic phase; #3683 driver-runtime-management (#3615 Part A); #3689 observation-only marking; #3693 N/A wording; #3697 workload-sandboxing (#3615 Part B); #3699 UAT validate budget; #3701 CNCF submission directory generator. Earlier: #3614/#3616 ADR amendment and version-keyed map, #3627 fail-closed aggregation, #3637 gang negative case, #3647 pod-autoscaling and metrics checks, #3665 namespace cleanup.

    Closed: #3602, #3603, #3604, #3606, #3611, #3612, #3428, #3597, #3671, #3681, #3615, #3609, #3619.

    Live validation of the final code (all phases, from the #3701 head):

    • AKS H100 aicr-29937818785 (v1.35.5, h100-aks-ubuntu-inference-dynamo): conformance 12/12 passed, inference-perf passed, submission directory written and accepted by the pinned upstream validator, attestation emitted and verified. Deployment phase failed on expected-resources because the cluster's nodewright-customizations release predates the toolkit-hardening Nodewright (feat(recipes): harden AKS toolkit via nvidia-setup aks-any #3617); upgraded from the current recipe, re-validation in progress. Deployment drift, not a defect.
    • EKS GB300 aws-us-east-2-nhensley-gb300 (v1.35.6, arm64): deployment 4/4, conformance 10/10 after upgrading the prometheus-adapter release to the recipe values that carry the feat(conformance): bring autoscaling and metrics checks to the CNCF bar #3647 HPA rule (the deployed adapter predated it: drift, not a defect); NCCL all-reduce fails by design (no in-rack RDMA) and the full run exits 8 with nothing promoted, as intended; attestation run in progress.
    • Both clusters confirmed clean after every run.

    Reviews: an epic-wide independent review and a docs-consistency review on 2026-11-06 found no blocking defect; their findings are filed as #3703 (P1, sub-issue), #3704 and #3705, or were fixed in #3701 before merge.

    Remaining:

  4. yuanchen8911 commented on Nov 7, 2026

    @yuanchen8911
    ContributorAuthor

    Live validation update, 2026-11-06 17:35 PT (CLI built from the #3701 head, validator images at main's immutable sha- tag, nothing skipped):

    Cluster Deployment Conformance Performance Submission / attestation
    AKS H100 aicr-29937818785 (v1.35.5, h100-aks-ubuntu-inference-dynamo) 4/4 after upgrading nodewright-customizations to the current recipe (toolkit-hardening Nodewright added by #3617; the 11-02 deployment predated it) 12/12 inference-perf passed directory written and accepted by the pinned upstream validator; attestation emitted and verified (the earlier run's attestation correctly recorded the failed deployment check); final all-phases run in progress
    EKS GB300 aws-us-east-2-nhensley-gb300 (v1.35.6, arm64, gb300-eks-ubuntu-training) 4/4 10/10 after upgrading prometheus-adapter to the recipe values carrying the #3647 HPA rule (the deployed adapter predated it) NCCL all-reduce fails by design (no in-rack RDMA); the run exits 8 and nothing is promoted attestation run in progress

    Both drift findings are deployment/upgrade matters on standing clusters, not validator defects: a cluster deployed from an older recipe must be upgraded from the current one before validating against main. Every per-run namespace, Job and probe was cleaned up automatically after each run, including the failed ones. Detailed per-check results will be posted as a comment on #3701.

  5. yuanchen8911 commented on Nov 7, 2026

    @yuanchen8911
    ContributorAuthor

    NVKE regeneration (the last live step of #3605) is done: aicr validate --phase conformance --cncf-submission on nvke022 (Kubernetes v1.36.3, GB200) exited 0 in 16m40s with 11 checks passed and cluster-autoscaling exported N/A; the pinned upstream validator accepted the directory on the first run. Every requirement keeps the status of the committed v1.36 NVKE submission, with driver_runtime_management now backed by a generated check page and every hand-run artifact replaced by a generated counterpart. Details, the drift handled (prometheus-adapter values only) and the pre-upstream caveats (stamped build, installed versions, cluster-name redaction) are on #3605, which is now closed.

    Remaining open sub-issue: #3703 (draft PR #3708, in review). Follow-ups and gaps after this epic are tracked under #3710.

  6. yuanchen8911 commented on Nov 7, 2026

    @yuanchen8911
    ContributorAuthor

    First nightly UAT after the merge set (2026-11-07 04:01 UTC, main efbc5d8)

    Batch run 42336608248. Every cell that got a cluster passed the conformance phase with the full check set the epic added; the failures were all infrastructure.

    Cell (main lane) Deployment Conformance Performance
    gcp-h100 inference (42340256240) 4/4 12/12 passed, 13m58s inference-perf passed, 7m36s
    kind-h100 training (42336681062) 4/4 9 passed, cluster-autoscaling skipped none declared
    kind-h100 inference (42339686896) 4/4 10 passed, cluster-autoscaling skipped none declared

    The GCP inference cell exercised every check: gang-scheduling, pod-autoscaling, accelerator-metrics, ai-service-metrics, inference-gateway with the traffic phase, secure-accelerator-access, driver-runtime-management, robust-controller, dra-support, cluster-autoscaling (passed on GKE) and the two health checks. The v1.2.0 comparison lane passed the same cells.

    Failed cells, none in validation:

    • aws-h100 training and inference, both lanes: Bringup Infra, no p5.48xlarge capacity in the zone.
    • azure-h100 training and inference, both lanes: Bringup Infra, AKS GPU agent-pool creation timed out.
    • gcp-h100 training, main lane (42336674494): install step. The GKE API server became unreachable during helmfile apply; the retries then failed in helm-diff's render of kubeflow-trainer on a ServiceMonitor capability check while the control plane was unavailable, with prometheus-operator-crds already deployed. The same cell passed twice on 2026-11-06 on the previous main, and no bundler or helmfile code changed in between.
    • gcp-h100 training, v1.2.0 lane: reached validation (deployment 6/6, conformance 10/10) and failed only NCCL all-reduce with the nodes reporting CNI NetworkNotReady.

    The fullest cell used about 23 minutes of the 50-minute validate budget from #3699. The two consecutive green nights that #3705 asks for are still pending on the cloud cells getting clusters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/validatortheme/validationConstraint evaluation, health checks, and conformance evidence

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions