Repository navigation
Description
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 byaicr validate --phase conformance. Their stdout artifacts becomeevidence/*.mdthroughpkg/evidence/cncf/renderer.gowhen--evidence-diris 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, plusPRODUCT.yaml,README.md(with the platform facts PRODUCT.yaml notes cite),junit.xml,e2e.logand the existingevidence/<requirement>.mdpages, redacted in one pass, then the pinned upstream validator as the last step.--cncf-submissionand--evidence-dirrequire each other;--recipeis required;--skip-checkand--no-clusterare refused. Vendor fields and the conditionalcluster_autoscalingN/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)
- docs(adr): amend ADR-007 for single-path CNCF conformance evidence #3611 docs(adr): amend ADR-007. Lands first.
- 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.
- 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.
- 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. - validate: run CNCF submission evidence from the conformance phase and retire collect-evidence.sh #3602 validate:
--cncf-submission --evidence-dirrenders from the conformance run (each requires the other; evidence only for submissions); delete the collector and remaining script;--featureremoved; 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. - 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. - 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.xmlore2e.logwithout#<check>is resolved through the validator's upstream-test-name map and fails "not found" for an AICR-named testcase. The generator writesfile://...#<check>on every reference,e2e.logincluded. e2e.logshape. The validator parsesgo test -voutput: one--- PASS|FAIL|SKIP: <check>line per check. The log is emitted from the same CTRF report asjunit.xmlwith 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
skippedwith a reason; an applicable MUST failure fails the run and nothing is written. - Required vendor metadata.
k8sConformanceUrlandproductLogoUrlmust be present and well-formed; they come fromspec.validate.evidence.cncf.vendorand 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_inferencemap gap.ai_inferenceis 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
- GPU hardware is needed to verify every parity port; the NVKE GB200 cluster must stay available with free GPUs.
- The conformance validator ships as its own image; each parity-port PR must rebuild it and run live, not only
make test. - The 83% coverage floor applies to new
pkg/code; validators are excluded. - Whether to run the upstream sigs suite as optional independent verification (decided in evidence: generate the CNCF submission directory (PRODUCT.yaml, README, junit.xml, e2e.log, redaction) #3605); AICR's junit is the default artifact.
workload_sandboxingat v1.38 needs a product answer from NVKE; a CPU-pool sandbox runtime satisfies the upstream test.- Regenerate nim-eks conformance evidence in place with the strengthened behavioral tests #2137 (regenerate v1.35 nim-eks): close as superseded once the single path exists, or regenerate at the next NIM submission.
Activity
54 remaining items
feat(conformance): add workload-sandboxing check (NVIDIA#3615 Part B)
feat(conformance): add workload-sandboxing check (NVIDIA#3615 Part B)
feat(conformance): add workload-sandboxing check (NVIDIA#3615 Part B)
yuanchen8911 commentedon Nov 7, 2026
Status 2026-11-06 (end of day)
Merged today (10 PRs): #3666 single runner and
--cncf-submissionfrom 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):
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 onexpected-resourcesbecause the cluster'snodewright-customizationsrelease 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.aws-us-east-2-nhensley-gb300(v1.35.6, arm64): deployment 4/4, conformance 10/10 after upgrading theprometheus-adapterrelease 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.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:
yuanchen8911 commentedon Nov 7, 2026
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):aicr-29937818785(v1.35.5, h100-aks-ubuntu-inference-dynamo)nodewright-customizationsto the current recipe (toolkit-hardening Nodewright added by #3617; the 11-02 deployment predated it)aws-us-east-2-nhensley-gb300(v1.35.6, arm64, gb300-eks-ubuntu-training)prometheus-adapterto the recipe values carrying the #3647 HPA rule (the deployed adapter predated it)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.
fix(validator): fail closed on unreadable results, harden probes
yuanchen8911 commentedon Nov 7, 2026
NVKE regeneration (the last live step of #3605) is done:
aicr validate --phase conformance --cncf-submissiononnvke022(Kubernetes v1.36.3, GB200) exited 0 in 16m40s with 11 checks passed andcluster-autoscalingexported 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, withdriver_runtime_managementnow 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.
fix(validator): fail closed on unreadable results, harden probes
fix(validator): fail closed on unreadable results, harden probes
yuanchen8911 commentedon Nov 7, 2026
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.
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:
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.
fix(validator): fail closed on unreadable results, harden probes