Skip to content

feat: [generator] Add FPM deployment target with reusable Pod and run script (phase 1)#1328

Open
Ethan-ES wants to merge 4 commits into
mainfrom
etshen/fpm-generator-v1
Open

feat: [generator] Add FPM deployment target with reusable Pod and run script (phase 1)#1328
Ethan-ES wants to merge 4 commits into
mainfrom
etshen/fpm-generator-v1

Conversation

@Ethan-ES

@Ethan-ES Ethan-ES commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Overview:

This PR adds a new fpm deployment target to generator.

The target reuses the existing Generator rule, mapping, hardware-facts, and versioned-template pipeline, then emits a reusable Kubernetes resource Pod and a separate vLLM launch script for FPM data collection. The resource Pod can be created once and reused across multiple collection attempts. Each generated run.sh starts and stops its own Engine, so reusing the Pod avoids repeated scheduling and image setup, but does not keep the Engine or model resident in GPU memory. FPM V1 intentionally supports only vLLM aggregated deployments with one worker, one replica, and one node. Existing deployment targets are unchanged.

Details:

Usage

Add FPM-specific vLLM arguments as individual tokens under Workers.agg.extra_cli_args, and add concrete environment variables under K8sConfig.extra_env:

ServiceConfig:
  model_path: /workspace/model_cache/my-model
  served_model_name: my-model

DynConfig:
  mode: agg

WorkerConfig:
  agg_workers: 1
  agg_gpus_per_worker: 4

Workers:
  agg:
    tensor_parallel_size: 4
    pipeline_parallel_size: 1
    gpus_per_worker: 4
    extra_cli_args:
      - --scheduler-cls
      - explicit_case_scheduler.InstrumentedScheduler
      - --benchmark-mode
      - agg
      - --benchmark-output-path
      - /results/run-1/benchmark.json

K8sConfig:
  name_prefix: fpm-example
  k8s_namespace: default
  k8s_image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.1
  extra_env:
    - name: DYN_FPM_BENCHMARK_OUTPUT_PATH
      value: /results/run-1/benchmark.json
    - name: FPM_RUN_ID
      value: run-1

Generate the artifacts with:

python -m aiconfigurator.generator.main render-artifacts \
  --backend vllm \
  --version 0.20.1 \
  --deployment-target fpm \
  --config fpm-request.yaml \
  --output ./artifacts

The runtime image can also be overridden directly from the command line:

python -m aiconfigurator.generator.main render-artifacts \
  --backend vllm \
  --version 0.20.1 \
  --deployment-target fpm \
  --config fpm-request.yaml \
  --set K8sConfig.k8s_image=nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.1 \
  --output ./artifacts

extra_cli_args must be a list[str]. The Generator preserves token boundaries and shell-quotes the final command. extra_env accepts concrete {name, value} entries only.

--benchmark-mode agg is required. The benchmark output path may be supplied through the CLI argument, the environment variable, or neither; the Generator fills in the missing side and defaults to /results/benchmark.json. If both are supplied, they must match.

Generated artifacts

The FPM target emits exactly two artifacts:

artifacts/
├── k8s_deploy.yaml
└── run.sh
  • k8s_deploy.yaml is a standard keepalive Pod. It contains the resolved runtime image, GPU count, volumes, /results, /dev/shm, node selectors, tolerations, and other infrastructure settings. It does not contain the vLLM command, Engine arguments, or FPM environment variables.
  • run.sh contains concrete environment exports and the complete resolved python3 -m dynamo.vllm ... command. The base command still comes from the existing rules, mappings, hardware facts, and versioned templates; FPM-specific extra_cli_args are appended afterward. The script starts the Engine, waits for valid benchmark JSON, stops the Engine, and refuses to overwrite an existing output file.

A typical Agent workflow is:

kubectl apply -f artifacts/k8s_deploy.yaml

POD_NAME=$(kubectl get -f artifacts/k8s_deploy.yaml \
  -o jsonpath='{.metadata.name}')

kubectl wait \
  --for=condition=Ready \
  "pod/${POD_NAME}" \
  --timeout=10m

kubectl exec -i "${POD_NAME}" -- \
  bash -s < artifacts/run.sh

The Pod may be reused, but every run.sh execution starts a new Engine and reloads the model. Each collection attempt must therefore use a unique benchmark output path.

The referenced scheduler module and FPM input files, such as case, capacity, and run-spec files, must already exist in the selected runtime image or be provided through mounted storage. The Generator passes their paths through but does not create those files.

valueFrom, envFrom, router/planner configurations, disaggregated mode, multiple workers, and multinode workers fail fast in FPM V1.

Summary by CodeRabbit

  • New Features
    • Added an fpm deployment target that generates a reusable Kubernetes workload and a runnable run.sh.
    • Expanded --deployment-target options across the CLI and artifact rendering (dynamo-j2, dynamo-python, llm-d-helm, llm-d-kustomize, fpm).
  • Bug Fixes
    • Made fpm run script output naming consistent with the selected target behavior.
    • Improved model-cache PVC mount resolution based on Kubernetes configuration (with a safe default).
  • Documentation
    • Updated README and CLI/deployment guides with revised target semantics and detailed fpm constraints/output behavior.
  • Tests
    • Added/expanded unit and contract tests for fpm artifact generation and CLI validation.

@Ethan-ES
Ethan-ES requested review from a team as code owners July 8, 2026 16:51
@copy-pr-bot

copy-pr-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds an fpm deployment target that generates a keepalive Kubernetes workload and run.sh for aggregated vLLM benchmarking, with CLI wiring, artifact routing, builder logic, documentation, and tests.

Changes

FPM V1 Deployment Target

Layer / File(s) Summary
CLI and artifact routing
src/aiconfigurator/cli/main.py, src/aiconfigurator/generator/{main.py,api.py,artifacts.py,aggregators.py}, src/aiconfigurator/generator/rendering/engine.py, src/aiconfigurator/generator/config/deployment_config.yaml, src/aiconfigurator/generator/builders/k8s_builder.py
Adds fpm target selection, routes it through artifact generation, preserves run.sh naming, forwards extra_cli_args, adds FPM-only config inputs, and supports configurable model-cache mounts.
FPM validation and artifact construction
src/aiconfigurator/generator/builders/fpm_builder.py
Validates aggregated vLLM inputs, benchmark arguments, environment values, topology, and resource overrides; generates run.sh; and lowers workloads into Pod or LeaderWorkerSet YAML.
FPM CLI task validation
src/aiconfigurator/cli/main.py, tests/unit/cli/test_cli_workflow.py
Rejects incompatible task mixes and Spica thorough sweeps before execution, with coverage for valid aggregated vLLM tasks and fail-closed behavior.
Documentation and contract tests
README.md, docs/*.md, tests/unit/generator/test_fpm_artifacts.py
Documents FPM artifacts and constraints, and tests workload rendering, script execution, multinode behavior, overlays, and validation failures.

Estimated code review effort: 4 (Complex) | ~60 minutes

Poem

A Pod stayed still in sleepy grace,
While run.sh raced the benchmark space.
No secrets slipped, no helper strays,
Just GPU paths and rank-filled ways. 🐇📦

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the new FPM deployment target and its reusable Pod/run.sh output.
Description check ✅ Passed It includes a solid overview and implementation details, but omits the reviewer-start and related-issues sections from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the feat label Jul 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@src/aiconfigurator/cli/main.py`:
- Around line 137-145: The shared CLI parser in main.py allows
--deployment-target fpm too broadly, so invalid FPM combinations are only
rejected later inside build_fpm_artifacts(). Add an upfront validation path in
the parser/CLI setup around common_parser.add_argument and the deployment-target
handling so unsupported default/exp cases are rejected before entering expensive
sweep/render work. Keep the existing FPM V1 constraint checks in
build_fpm_artifacts(), but also gate the fpm target earlier using the
deployment-target selection logic and the FPM-specific config symbols.

In `@src/aiconfigurator/generator/builders/fpm_builder.py`:
- Around line 185-203: The `_ensure_benchmark_output_path` logic in
`fpm_builder.py` mishandles an explicit empty `--benchmark-output-path`, because
`value = cli_value or env_value` treats an empty CLI string as missing and the
later `cli_value is None` guard lets `args` and `env` get out of sync. Update
`_ensure_benchmark_output_path` to validate emptiness before resolving/filling
defaults, and treat `cli_value` as present whenever the flag was provided even
if empty; then only append the default to `args` and `env` after confirming the
resolved path is non-empty, so the path used by `run.sh` always matches the
stored benchmark output path.
- Around line 246-296: The engine shutdown path is unbounded in both cleanup()
and the final happy-path termination, so a stuck process can block the reusable
Pod forever. Update the logic around engine_pid in cleanup() and the final
kill/wait sequence to use a bounded termination flow with the same
wait_timeout_seconds behavior as the benchmark-output loop, e.g. send SIGTERM,
wait only up to the timeout, then force cleanup with SIGKILL or exit with a
timeout status if the engine does not stop. Keep the timeout handling
centralized in a helper so both paths share the same bounded shutdown behavior.
- Around line 130-152: The _collect_concrete_env helper only validates
worker.envs and main_container.env, but FPM V1 also needs to reject
envFromSecret on DGDService because those secret-backed variables are not
propagated into the generated Pod or run.sh. Update the FPM builder path that
assembles environment handling to detect envFromSecret on the worker service and
fail fast with a clear error, alongside the existing valueFrom checks, so the
validation is enforced in the same code path as _collect_concrete_env.
🪄 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: CHILL

Plan: Enterprise

Run ID: 29667ac7-a857-43ff-aee1-537f4cf54300

📥 Commits

Reviewing files that changed from the base of the PR and between 0828d6b and e65a757.

📒 Files selected for processing (13)
  • README.md
  • docs/cli_user_guide.md
  • docs/dynamo_deployment_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/cli/main.py
  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/rendering/engine.py
  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: AIC Accuracy Regression Testing
  • GitHub Check: Cargo Deny
  • GitHub Check: Rust/Python engine-step parity
  • GitHub Check: Build and Test (e2e)
  • GitHub Check: Build and Test (unit)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/guard_rails.md)

**/*.py: Catch unsupported system/backend/version combinations early with fast validation to prevent wasting user time on late failures after profiling.
MoE model detection must use config.json, not model name patterns, to correctly identify MoE models with non-standard naming.
Use model_family not model_name for model compatibility checks; model_name includes size/quantization info that changes across variants.
safe_model_name must be generated BEFORE saving results to avoid race condition with raw model_path containing slashes.
Quantization type must be inferred from model config, not name patterns, to handle inconsistent naming conventions.

Files:

  • tests/unit/cli/test_cli_workflow.py
  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/cli/main.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/rendering/engine.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/generator/test_fpm_artifacts.py
**/*

⚙️ CodeRabbit configuration file

**/*: - Prefer applicable inline comments. When the correct fix is clear, small, and limited to the commented diff hunk, include it as a GitHub Suggested Change so the author can apply it with one click.

  • Do not use a suggested change when the fix requires broader design choices, multiple files, generated artifacts, unavailable context, or validation that cannot be inferred from the diff.
  • If a comment is not directly applicable, state the smallest concrete next step and why a one-click suggestion is not safe.

Files:

  • tests/unit/cli/test_cli_workflow.py
  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/cli/main.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/main.py
  • docs/dynamo_deployment_guide.md
  • src/aiconfigurator/generator/api.py
  • README.md
  • src/aiconfigurator/generator/rendering/engine.py
  • docs/cli_user_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/generator/test_fpm_artifacts.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - Check that tests cover the changed behavior rather than only the happy path.

  • Watch for fixtures or golden outputs that mask backend drift, support-matrix ordering changes, or CLI output regressions.

Files:

  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
src/aiconfigurator/generator/**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/debugging.md)

When debugging generator output issues, verify template variable names match the rendering context in src/aiconfigurator/generator/rendering/engine.py:make_worker_context()

Files:

  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/rendering/engine.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
src/aiconfigurator/generator/**/?(naive|aggregators).py

📄 CodeRabbit inference engine (.claude/rules/generator/debugging.md)

Verify RFC-1123 compliance by checking naive.py or aggregators.py when debugging RFC-1123 violation bugs in generator output

Files:

  • src/aiconfigurator/generator/aggregators.py
src/aiconfigurator/generator/**

📄 CodeRabbit inference engine (AGENTS.md)

Before making any change under src/aiconfigurator/generator/**, you must read .claude/rules/generator-development.md first.

Files:

  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/rendering/engine.py
  • src/aiconfigurator/generator/builders/fpm_builder.py

⚙️ CodeRabbit configuration file

src/aiconfigurator/generator/**: - Enforce the generator development rules from .claude/rules/generator-development.md.

  • Trace changes across the pipeline: input parsing, defaults, rule evaluation, parameter mapping, template rendering, and emitted artifacts.
  • For .j2 templates and .rule files, verify # Guard: and # Why: comments are preserved and followed. Flag removals or bypasses unless the PR explicitly justifies them.
  • Check cross-backend consistency across TRT-LLM, vLLM, and SGLang when a backend-specific rule, template, parameter, or versioned artifact changes.
  • For new user-facing generator parameters, require matching CLI, SDK/profiler bridge, generator validator, docs, and test coverage updates where applicable.
  • For versioned template changes, verify the affected backend versions against src/aiconfigurator/generator/config/backend_version_matrix.yaml.

Files:

  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/rendering/engine.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
src/aiconfigurator/cli/**

⚙️ CodeRabbit configuration file

src/aiconfigurator/cli/**: - Check that CLI argument changes preserve backward compatibility, validation behavior, defaults, and plain-output expectations.

  • For new or changed user-facing options, verify docs updates and generator/SDK wiring.
  • Watch for non-TTY assumptions in tests or output formatting.

Files:

  • src/aiconfigurator/cli/main.py
**/*.md

📄 CodeRabbit inference engine (.claude/rules/generator/config_schema.md)

**/*.md: Add computation rules in the rules authoring system when a new parameter requires non-trivial value computation beyond simple defaults
Add template modifications in the template authoring system when a new parameter requires special handling in generated artifacts

Files:

  • docs/dynamo_deployment_guide.md
  • README.md
  • docs/cli_user_guide.md
  • docs/generator_overview.md
docs/**

⚙️ CodeRabbit configuration file

docs/**: - Check that docs match changed CLI, SDK, generator, backend, and support-matrix behavior.

  • Flag docs that describe unsupported runtimes, stale command names, or behavior not covered by tests or support-matrix evidence.

Files:

  • docs/dynamo_deployment_guide.md
  • docs/cli_user_guide.md
  • docs/generator_overview.md
src/aiconfigurator/generator/api.py

📄 CodeRabbit inference engine (.claude/rules/generator/debugging.md)

Review api.py:parse_cli_params() to verify dotted-path resolution and check the parsed input dict before processing when debugging overrides that are not taking effect

Files:

  • src/aiconfigurator/generator/api.py
tests/unit/generator/test_*.py

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Test individual functions in isolation using unit tests with mocked schema loading and template rendering

Files:

  • tests/unit/generator/test_fpm_artifacts.py
🪛 ast-grep (0.44.1)
tests/unit/generator/test_fpm_artifacts.py

[info] 25-31: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"cudagraph_mode": "FULL",
"max_capture_size": 1024,
"compile_sizes": [1, 2, 4, 8],
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[error] 191-197: Command coming from incoming request
Context: subprocess.run(
["bash", "-n"],
input=script,
text=True,
capture_output=True,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 285-292: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=10,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 297-304: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=10,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 markdownlint-cli2 (0.22.1)
docs/cli_user_guide.md

[warning] 18-18: Link fragments should be valid

(MD051, link-fragments)

🔇 Additional comments (16)
README.md (1)

102-104: LGTM!

docs/cli_user_guide.md (2)

18-18: 📐 Maintainability & Code Quality

Verify the in-page link target.

Please confirm the #deployment-target-selection fragment still resolves in the rendered markdown; markdownlint already flagged this line.

Source: Linters/SAST tools


689-689: LGTM!

Also applies to: 698-750, 998-998

docs/dynamo_deployment_guide.md (1)

3-3: LGTM!

Also applies to: 488-513

docs/generator_overview.md (1)

13-13: LGTM!

Also applies to: 96-96, 176-205

src/aiconfigurator/generator/main.py (1)

66-71: LGTM!

Also applies to: 98-98

src/aiconfigurator/generator/api.py (2)

277-282: 📐 Maintainability & Code Quality | ⚡ Quick win

Docstring lists 'fpm' but doesn't describe it.

Every other option gets an explanatory clause ("...generates Kustomize overlays..."); 'fpm' is added to the value list but has no matching description, unlike generate_naive_config's consistently terse style.

📝 Suggested docstring addition
         deployment_target: Deployment platform ('dynamo-j2', 'dynamo-python', 'llm-d-helm',
             'llm-d-kustomize', or 'fpm').
             'dynamo-j2' uses typed Dynamo builders, 'dynamo-python' uses Dynamo's Python config modifiers,
             'llm-d-helm' generates Helm values for llm-d-modelservice chart, and 'llm-d-kustomize'
-            generates Kustomize overlays for llm-d modelserver guides.
+            generates Kustomize overlays for llm-d modelserver guides. 'fpm' emits a reusable
+            keepalive resource Pod plus a standalone run.sh for FPM data collection.

318-318: LGTM!

Also applies to: 777-777, 675-676

src/aiconfigurator/generator/artifacts.py (1)

19-19: LGTM!

Also applies to: 44-44

src/aiconfigurator/generator/aggregators.py (1)

286-292: LGTM!

src/aiconfigurator/generator/rendering/engine.py (1)

255-256: LGTM!

Also applies to: 709-725

src/aiconfigurator/generator/builders/fpm_builder.py (2)

40-48: 🎯 Functional Correctness

No DynConfig key mismatch here
enable_router, router_mode, router_config, and planner_config match the DynConfig schema and are already covered by the fail-fast guard.

			> Likely an incorrect or invalid review comment.

101-120: 📐 Maintainability & Code Quality

No action needed The VllmWorker name is part of the current generator contract, so this check matches the rest of the pipeline.

			> Likely an incorrect or invalid review comment.
tests/unit/cli/test_cli_workflow.py (1)

764-764: LGTM!

tests/unit/generator/test_fpm_artifacts.py (2)

1-547: LGTM!


466-476: 🎯 Functional Correctness

No issue here. K8sConfig.worker_extra_pod_spec is a supported override path, and fpm_builder explicitly rejects mainContainer.envFrom, so this test exercises the intended case.

			> Likely an incorrect or invalid review comment.

Comment thread src/aiconfigurator/cli/main.py
Comment on lines +130 to +152
def _collect_concrete_env(worker: DGDService, main_container: MainContainer) -> list[tuple[str, str]]:
resolved: list[tuple[str, str]] = []
entries = list(worker.envs or []) + list(main_container.env or [])
for entry in entries:
if not isinstance(entry, dict):
raise TypeError("FPM environment entries must be mappings")
if "valueFrom" in entry:
raise ValueError("FPM V1 does not support valueFrom environment entries")

name = entry.get("name")
if not isinstance(name, str) or not _ENV_NAME_RE.fullmatch(name):
raise ValueError(f"Invalid shell environment variable name: {name!r}")
if "value" not in entry or entry["value"] is None:
raise ValueError(f"Environment variable {name} must have a concrete value")

value = entry["value"]
if isinstance(value, bool):
resolved.append((name, "true" if value else "false"))
elif isinstance(value, (str, int, float)):
resolved.append((name, str(value)))
else:
raise TypeError(f"Environment variable {name} must have a scalar value")
return resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "env_from_secret|envFromSecret" src/aiconfigurator/generator/builders/dgd_model.py src/aiconfigurator/generator/builders/k8s_builder.py

Repository: ai-dynamo/aiconfigurator

Length of output: 1071


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== generator-development rules ==\n'
sed -n '1,220p' .claude/rules/generator-development.md

printf '\n== dgd_model outline ==\n'
ast-grep outline src/aiconfigurator/generator/builders/dgd_model.py --view expanded

printf '\n== k8s_builder outline ==\n'
ast-grep outline src/aiconfigurator/generator/builders/k8s_builder.py --view expanded

printf '\n== fpm_builder around target lines ==\n'
sed -n '1,220p' src/aiconfigurator/generator/builders/fpm_builder.py

Repository: ai-dynamo/aiconfigurator

Length of output: 21100


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== fpm_builder lowering path ==\n'
rg -n "def _lower_worker_to_pod|env_from_secret|envFrom" src/aiconfigurator/generator/builders/fpm_builder.py src/aiconfigurator/generator/builders/k8s_builder.py src/aiconfigurator/generator/builders/dgd_model.py

printf '\n== fpm_builder relevant section ==\n'
sed -n '220,420p' src/aiconfigurator/generator/builders/fpm_builder.py

printf '\n== k8s_builder env handling section ==\n'
sed -n '90,150p' src/aiconfigurator/generator/builders/k8s_builder.py

printf '\n== dgd_model service serialization section ==\n'
sed -n '180,230p' src/aiconfigurator/generator/builders/dgd_model.py

Repository: ai-dynamo/aiconfigurator

Length of output: 12260


Reject envFromSecret for FPM V1 too. DGDService.envFromSecret is serialized on the worker service but never carried into the generated Pod or run.sh, so secret-backed env injection is silently lost and only fails later at runtime.

🛡️ Suggested guard
 def _build_single_worker(context: dict[str, Any], backend: str, resolved_facts: Any) -> DGDService:
     ...
     worker = workers[0][1]
+    if worker.env_from_secret:
+        raise ValueError("FPM V1 does not support DGDService.envFromSecret")
     if worker.replicas != 1:
         raise ValueError("FPM V1 requires worker replicas=1")
🤖 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 `@src/aiconfigurator/generator/builders/fpm_builder.py` around lines 130 - 152,
The _collect_concrete_env helper only validates worker.envs and
main_container.env, but FPM V1 also needs to reject envFromSecret on DGDService
because those secret-backed variables are not propagated into the generated Pod
or run.sh. Update the FPM builder path that assembles environment handling to
detect envFromSecret on the worker service and fail fast with a clear error,
alongside the existing valueFrom checks, so the validation is enforced in the
same code path as _collect_concrete_env.

Comment thread src/aiconfigurator/generator/builders/fpm_builder.py
Comment thread src/aiconfigurator/generator/builders/fpm_builder.py Outdated
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

AIC Accuracy Regression Testing

Workflow result: success

Old revision: 32d9db954276e62f7588aafd9081c0926f18224c

Summary

  • # samples added: 0
  • ttft_mape_improvement_%: 0.000000
  • tpot_mape_improvement_%: 0.000000
Comparison summary table
partition num_samples_added ttft_mape_improvement_% tpot_mape_improvement_%
all 0 0.000000 0.000000
agg 0 0.000000 0.000000
disagg 0 0.000000 0.000000
MiniMax-M2.5 0 0.000000 0.000000
Qwen3.5-397B-A17B 0 0.000000 0.000000
Kimi-K2.5 0 0.000000 0.000000
DeepSeek-V3 0 0.000000 0.000000
DeepSeek-R1-NVFP4 0 0.000000 0.000000
DeepSeek-V3.1-NVFP4 0 0.000000 0.000000
Qwen3-32B-NVFP4 0 0.000000 0.000000
DeepSeek-R1 0 0.000000 0.000000
Qwen3-32B 0 0.000000 0.000000
Qwen3-235B-A22B-FP8 0 0.000000 0.000000
Llama-3.1-8B-Instruct-FP8 0 0.000000 0.000000
b300_sxm 0 0.000000 0.000000
gb200 0 0.000000 0.000000
b200_sxm 0 0.000000 0.000000
gb300 0 0.000000 0.000000
h200_sxm 0 0.000000 0.000000
h100_sxm 0 0.000000 0.000000
vllm-agg 0 0.000000 0.000000
sglang-agg 0 0.000000 0.000000
trtllm-disagg 0 0.000000 0.000000
sglang-disagg 0 0.000000 0.000000
trtllm-agg 0 0.000000 0.000000
vllm-disagg 0 0.000000 0.000000
MiniMax-M2.5|b300_sxm|vllm|agg 0 0.000000 0.000000
Qwen3.5-397B-A17B|b300_sxm|sglang|agg 0 0.000000 0.000000
Kimi-K2.5|gb200|trtllm|disagg 0 0.000000 0.000000
Kimi-K2.5|b200_sxm|vllm|agg 0 0.000000 0.000000
Kimi-K2.5|b300_sxm|vllm|agg 0 0.000000 0.000000
MiniMax-M2.5|b200_sxm|vllm|agg 0 0.000000 0.000000
DeepSeek-V3|gb200|trtllm|disagg 0 0.000000 0.000000
DeepSeek-V3|gb300|trtllm|disagg 0 0.000000 0.000000
DeepSeek-V3|gb200|sglang|disagg 0 0.000000 0.000000
DeepSeek-V3|gb300|sglang|disagg 0 0.000000 0.000000
DeepSeek-V3|h200_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-V3|b200_sxm|trtllm|disagg 0 0.000000 0.000000
DeepSeek-V3|h200_sxm|sglang|disagg 0 0.000000 0.000000
MiniMax-M2.5|h200_sxm|vllm|agg 0 0.000000 0.000000
Qwen3.5-397B-A17B|b200_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-V3|b200_sxm|sglang|disagg 0 0.000000 0.000000
DeepSeek-V3|b200_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-V3|b200_sxm|trtllm|agg 0 0.000000 0.000000
DeepSeek-V3|h200_sxm|trtllm|disagg 0 0.000000 0.000000
DeepSeek-V3|h100_sxm|trtllm|disagg 0 0.000000 0.000000
DeepSeek-V3|h200_sxm|trtllm|agg 0 0.000000 0.000000
Kimi-K2.5|gb200|vllm|disagg 0 0.000000 0.000000
DeepSeek-V3|b300_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-R1-NVFP4|b200_sxm|trtllm|agg 0 0.000000 0.000000
DeepSeek-V3.1-NVFP4|b200_sxm|trtllm|agg 0 0.000000 0.000000
Qwen3-32B-NVFP4|b200_sxm|trtllm|disagg 0 0.000000 0.000000
Qwen3-32B-NVFP4|b200_sxm|trtllm|agg 0 0.000000 0.000000
DeepSeek-R1|gb200|trtllm|agg 0 0.000000 0.000000
Qwen3-32B|gb200|trtllm|agg 0 0.000000 0.000000
DeepSeek-V3.1-NVFP4|gb200|trtllm|agg 0 0.000000 0.000000
Qwen3-32B-NVFP4|gb200|trtllm|disagg 0 0.000000 0.000000
Qwen3-32B-NVFP4|gb200|trtllm|agg 0 0.000000 0.000000
Qwen3-32B|h100_sxm|sglang|agg 0 0.000000 0.000000
Qwen3-32B|h100_sxm|sglang|disagg 0 0.000000 0.000000
Qwen3-235B-A22B-FP8|h100_sxm|trtllm|agg 0 0.000000 0.000000
Qwen3-32B|h100_sxm|trtllm|agg 0 0.000000 0.000000
Qwen3-32B|h100_sxm|vllm|agg 0 0.000000 0.000000
Qwen3-235B-A22B-FP8|h200_sxm|sglang|agg 0 0.000000 0.000000
Qwen3-235B-A22B-FP8|h200_sxm|vllm|agg 0 0.000000 0.000000
Llama-3.1-8B-Instruct-FP8|h200_sxm|vllm|agg 0 0.000000 0.000000
MiniMax-M2.5|h100_sxm|vllm|agg 0 0.000000 0.000000
DeepSeek-R1|b200_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-R1|h200_sxm|sglang|agg 0 0.000000 0.000000
DeepSeek-R1|b200_sxm|trtllm|agg 0 0.000000 0.000000
DeepSeek-R1|h200_sxm|trtllm|agg 0 0.000000 0.000000
Comparison plot AIC accuracy regression testing comparison plot

Artifact bundle: accuracy-regression-testing-results

Ethan-ES added 2 commits July 9, 2026 18:06
Signed-off-by: etshen <etshen@nvidia.com>
Signed-off-by: etshen <etshen@nvidia.com>
@Ethan-ES
Ethan-ES force-pushed the etshen/fpm-generator-v1 branch from e65a757 to b679f40 Compare July 9, 2026 10:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@src/aiconfigurator/generator/builders/fpm_builder.py`:
- Around line 731-768: The resource lowering in _lower_resources() updates
nvidia.com/gpu to gpu_limit but leaves custom resource values unchanged, so EFA
can still be over-requested per pod. Adjust the custom resource handling in
_lower_resources() to scale the EFA count in proportion to gpu_limit, keeping
the transport.yaml 1:1 GPU-to-EFA relationship intact, and preserve the existing
validation for resources.limits, resources.requests, and resources.custom.
🪄 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: CHILL

Plan: Enterprise

Run ID: 03534917-9b9b-4622-b920-76b900e283f3

📥 Commits

Reviewing files that changed from the base of the PR and between e65a757 and b679f40.

📒 Files selected for processing (15)
  • README.md
  • docs/cli_user_guide.md
  • docs/dynamo_deployment_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/cli/main.py
  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/api.py
  • src/aiconfigurator/generator/artifacts.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/config/deployment_config.yaml
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/rendering/engine.py
  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/aiconfigurator/generator/aggregators.py
  • src/aiconfigurator/generator/main.py
  • src/aiconfigurator/generator/artifacts.py
  • tests/unit/cli/test_cli_workflow.py
  • src/aiconfigurator/generator/rendering/engine.py
  • src/aiconfigurator/cli/main.py
  • docs/dynamo_deployment_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/generator/api.py
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: Build and Test (e2e)
  • GitHub Check: Rust/Python engine-step parity
  • GitHub Check: Cargo Deny
  • GitHub Check: Build and Test (unit)
  • GitHub Check: AIC Accuracy Regression Testing
🧰 Additional context used
📓 Path-based instructions (10)
src/aiconfigurator/generator/config/deployment_config.yaml

📄 CodeRabbit inference engine (.claude/rules/generator/config_schema.md)

src/aiconfigurator/generator/config/deployment_config.yaml: Add new parameters to src/aiconfigurator/generator/config/deployment_config.yaml with proper YAML structure including key name, required status, default value, optional backend-specific defaults, and optional backend constraints
Ensure string defaults in YAML are double-quoted inside single quotes (e.g., default: '"my-string"') to allow proper Jinja2 evaluation
Guard Jinja2 expressions in default values against None/empty values by using conditional logic (e.g., 'model_path.split("/")[-1] if model_path else ""') to prevent runtime errors
Avoid circular default references where parameter A defaults to an expression using parameter B and B defaults to an expression using A, as this produces silent None values

Check src/aiconfigurator/generator/config/deployment_config.yaml default expressions and evaluate them manually with test inputs when debugging missing or None parameter values

Input schema and default values for backend template rendering must be defined in deployment_config.yaml

src/aiconfigurator/generator/config/deployment_config.yaml: Update deployment_config.yaml to add schema entries with section, default, and required status for new user-facing parameters, and add backend_defaults if behavior differs by backend
Verify that default image expressions in deployment_config.yaml resolve correctly for new backend versions and update container image references if the Dynamo release includes new images

Files:

  • src/aiconfigurator/generator/config/deployment_config.yaml
**/*.{yaml,yml,json}

📄 CodeRabbit inference engine (.claude/rules/generator/guard_rails.md)

**/*.{yaml,yml,json}: build_config nesting is version-dependent: Pre-1.2.0rc5 places it inside build_config. Post-1.2.0rc5 places it at top-level. Wrong placement is silently ignored.
Template variables must be top-level keys; nested paths like build_config.max_batch_size are undefined because engine.py flattens the context.
cache_transceiver_config lifecycle: Absent pre-1.0.0rc4. In engine YAML 1.0.0rc4-1.3.0rc1. In CLI --override-engine-args post-1.3.0rc5.
cache_transceiver_config.backend must be set to 'DEFAULT' or omission causes TRT-LLM to reject config in disagg mode.
Engine params must go into --override-engine-args JSON; TRT-LLM's Dynamo argparser only accepts specific direct CLI flags.
max_num_tokens % tokens_per_block == 0 must be true; TRT-LLM asserts block alignment and violation crashes engine startup.
cache_transceiver_max_tokens_in_buffer must align to block size; same block-alignment assertion applies as max_num_tokens.
Prefill deployment: Set disable_overlap_scheduler = true to prevent hangs caused by overlap scheduler on prefill.
Decode/aggregation deployment: Set disable_overlap_scheduler = false to avoid performance degradation.
MoE models: Ensure TP = moe_tp * moe_ep to prevent out-of-memory errors from model replication per GPU.
KV cache dtype: Convert literal "float16" or "bfloat16" to "auto" for TRT-LLM compatibility; literal strings are not accepted.
SGLang backend: Do NOT emit --moe-dense-tp-size; SGLang only accepts value 1 or None, other values crash startup.
SGLang backend: KV transfer backend default must be "nixl" for disaggregated mode (SGLang >=0.5.6.post2 requires explicit backend).
SGLang aggregation mode: Set enable_mixed_chunk = true to avoid poor prefill/decode scheduling performance.
SGLang backend: Convert KV cache dtype "fp8" to "fp8_e4m3"; SGLang does not accept the literal "fp8" string.
SGLang backend: Convert KV cache dtype "bfloat16" to "auto"; SGLang interprets the li...

Files:

  • src/aiconfigurator/generator/config/deployment_config.yaml
src/aiconfigurator/generator/**

📄 CodeRabbit inference engine (AGENTS.md)

Before making any change under src/aiconfigurator/generator/**, you must read .claude/rules/generator-development.md first.

Files:

  • src/aiconfigurator/generator/config/deployment_config.yaml
  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/builders/fpm_builder.py

⚙️ CodeRabbit configuration file

src/aiconfigurator/generator/**: - Enforce the generator development rules from .claude/rules/generator-development.md.

  • Trace changes across the pipeline: input parsing, defaults, rule evaluation, parameter mapping, template rendering, and emitted artifacts.
  • For .j2 templates and .rule files, verify # Guard: and # Why: comments are preserved and followed. Flag removals or bypasses unless the PR explicitly justifies them.
  • Check cross-backend consistency across TRT-LLM, vLLM, and SGLang when a backend-specific rule, template, parameter, or versioned artifact changes.
  • For new user-facing generator parameters, require matching CLI, SDK/profiler bridge, generator validator, docs, and test coverage updates where applicable.
  • For versioned template changes, verify the affected backend versions against src/aiconfigurator/generator/config/backend_version_matrix.yaml.

Files:

  • src/aiconfigurator/generator/config/deployment_config.yaml
  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
**/*

⚙️ CodeRabbit configuration file

**/*: - Prefer applicable inline comments. When the correct fix is clear, small, and limited to the commented diff hunk, include it as a GitHub Suggested Change so the author can apply it with one click.

  • Do not use a suggested change when the fix requires broader design choices, multiple files, generated artifacts, unavailable context, or validation that cannot be inferred from the diff.
  • If a comment is not directly applicable, state the smallest concrete next step and why a one-click suggestion is not safe.

Files:

  • src/aiconfigurator/generator/config/deployment_config.yaml
  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/generator/test_fpm_artifacts.py
  • docs/cli_user_guide.md
src/aiconfigurator/generator/**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/debugging.md)

When debugging generator output issues, verify template variable names match the rendering context in src/aiconfigurator/generator/rendering/engine.py:make_worker_context()

Files:

  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/guard_rails.md)

**/*.py: Catch unsupported system/backend/version combinations early with fast validation to prevent wasting user time on late failures after profiling.
MoE model detection must use config.json, not model name patterns, to correctly identify MoE models with non-standard naming.
Use model_family not model_name for model compatibility checks; model_name includes size/quantization info that changes across variants.
safe_model_name must be generated BEFORE saving results to avoid race condition with raw model_path containing slashes.
Quantization type must be inferred from model config, not name patterns, to handle inconsistent naming conventions.

Files:

  • src/aiconfigurator/generator/builders/k8s_builder.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/generator/test_fpm_artifacts.py
tests/unit/generator/test_*.py

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Test individual functions in isolation using unit tests with mocked schema loading and template rendering

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - Check that tests cover the changed behavior rather than only the happy path.

  • Watch for fixtures or golden outputs that mask backend drift, support-matrix ordering changes, or CLI output regressions.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
**/*.md

📄 CodeRabbit inference engine (.claude/rules/generator/config_schema.md)

**/*.md: Add computation rules in the rules authoring system when a new parameter requires non-trivial value computation beyond simple defaults
Add template modifications in the template authoring system when a new parameter requires special handling in generated artifacts

Files:

  • docs/cli_user_guide.md
docs/**

⚙️ CodeRabbit configuration file

docs/**: - Check that docs match changed CLI, SDK, generator, backend, and support-matrix behavior.

  • Flag docs that describe unsupported runtimes, stale command names, or behavior not covered by tests or support-matrix evidence.

Files:

  • docs/cli_user_guide.md
🪛 ast-grep (0.44.1)
tests/unit/generator/test_fpm_artifacts.py

[info] 25-31: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"cudagraph_mode": "FULL",
"max_capture_size": 1024,
"compile_sizes": [1, 2, 4, 8],
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[error] 253-259: Command coming from incoming request
Context: subprocess.run(
["bash", "-n"],
input=script,
text=True,
capture_output=True,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 347-354: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=10,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 363-370: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=10,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 425-432: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=12,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 479-486: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=8,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 674-680: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
timeout=5,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 718-725: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=5,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 794-801: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=8,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 markdownlint-cli2 (0.22.1)
docs/cli_user_guide.md

[warning] 18-18: Link fragments should be valid

(MD051, link-fragments)

🔇 Additional comments (8)
docs/cli_user_guide.md (2)

18-18: LGTM!

Also applies to: 689-689, 1018-1018


770-770: 📐 Maintainability & Code Quality

No change needed for the 0.24.0 flag note. extra_cli_args is an intentional raw passthrough here, and the doc already scopes those 0.24.0-only flags as unvalidated against a 0.24.0 runtime image.

			> Likely an incorrect or invalid review comment.
src/aiconfigurator/generator/builders/fpm_builder.py (3)

274-296: envFromSecret still silently dropped for every FPM render.

_collect_concrete_env only walks worker.envs + main_container.env; it never checks worker.env_from_secret. Since k8s_builder.py's render_worker unconditionally sets env_from_secret="hf-token-secret" on every vLLM worker, this means every FPM run.sh today silently loses HF_TOKEN injection — not just an edge case.


329-347: Explicit empty --benchmark-output-path still diverges from the value run.sh waits on.

value = cli_value or env_value treats an explicit empty string as absent, and the later if not value: raise runs too late (after args/env are already mutated).


483-491: Engine termination is still unbounded in both cleanup() and the happy-path shutdown.

A stuck engine ignoring SIGTERM can hang the reusable Pod indefinitely for all future collection attempts, unlike the benchmark-wait loop which is correctly bounded by wait_timeout_seconds.

Also applies to: 527-529

src/aiconfigurator/generator/config/deployment_config.yaml (1)

131-135: LGTM!

src/aiconfigurator/generator/builders/k8s_builder.py (1)

229-229: LGTM!

Also applies to: 536-536, 830-830

tests/unit/generator/test_fpm_artifacts.py (1)

1-969: LGTM!

Comment thread src/aiconfigurator/generator/builders/fpm_builder.py
Signed-off-by: etshen <etshen@nvidia.com>
@Ethan-ES

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/unit/generator/test_fpm_artifacts.py (1)

12-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Move these contract tests out of the unit-test suite.

These ranges exercise the complete renderer and real Bash process trees rather than isolated functions. Move them and their helpers to the integration/contract suite, retaining mocked function-level coverage here.

A one-click change is unsafe because the destination and CI test-discovery configuration are unavailable.

As per coding guidelines, tests/unit/generator/test_*.py must “Test individual functions in isolation using unit tests with mocked schema loading and template rendering.” As per path instructions, broader multi-file changes should not use a suggested change.

Also applies to: 300-342, 548-552, 628-628, 850-887, 1052-1053, 1072-1072

🤖 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 `@tests/unit/generator/test_fpm_artifacts.py` around lines 12 - 15, Move the
contract-test ranges and their supporting helpers from
tests/unit/generator/test_fpm_artifacts.py into the repository’s established
integration/contract test suite, preserving mocked function-level coverage in
the unit file. Update test-discovery or CI configuration only as needed to run
the relocated tests, and verify the real renderer and Bash process-tree coverage
remains included without treating it as isolated unit testing.

Sources: Coding guidelines, Path instructions

🤖 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 `@tests/unit/generator/test_fpm_artifacts.py`:
- Around line 596-599: Update the run.sh rewrites in the test cases around
_render(params), including both occurrences near the 596 and 663 sections, to
assert that replacing engine_shutdown_grace_seconds=30 matched exactly once.
Preserve the rewritten value while making backend assignment drift fail
immediately with a clear assertion.

---

Nitpick comments:
In `@tests/unit/generator/test_fpm_artifacts.py`:
- Around line 12-15: Move the contract-test ranges and their supporting helpers
from tests/unit/generator/test_fpm_artifacts.py into the repository’s
established integration/contract test suite, preserving mocked function-level
coverage in the unit file. Update test-discovery or CI configuration only as
needed to run the relocated tests, and verify the real renderer and Bash
process-tree coverage remains included without treating it as isolated unit
testing.
🪄 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: CHILL

Plan: Enterprise

Run ID: 6be892f7-0949-4cf7-ae83-acce36d0d6bb

📥 Commits

Reviewing files that changed from the base of the PR and between b679f40 and 9581f22.

📒 Files selected for processing (4)
  • src/aiconfigurator/cli/main.py
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/aiconfigurator/generator/builders/fpm_builder.py
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
  • GitHub Check: Collect snapshot (old)
  • GitHub Check: Collect snapshot (new)
  • GitHub Check: Rust/Python engine-step parity
  • GitHub Check: Build and Test (unit)
  • GitHub Check: Build and Test (e2e)
  • GitHub Check: Cargo Deny
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/guard_rails.md)

**/*.py: Catch unsupported system/backend/version combinations early with fast validation to prevent wasting user time on late failures after profiling.
MoE model detection must use config.json, not model name patterns, to correctly identify MoE models with non-standard naming.
Use model_family not model_name for model compatibility checks; model_name includes size/quantization info that changes across variants.
safe_model_name must be generated BEFORE saving results to avoid race condition with raw model_path containing slashes.
Quantization type must be inferred from model config, not name patterns, to handle inconsistent naming conventions.

Files:

  • src/aiconfigurator/cli/main.py
  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
**/*

⚙️ CodeRabbit configuration file

**/*: - Prefer applicable inline comments. When the correct fix is clear, small, and limited to the commented diff hunk, include it as a GitHub Suggested Change so the author can apply it with one click.

  • Do not use a suggested change when the fix requires broader design choices, multiple files, generated artifacts, unavailable context, or validation that cannot be inferred from the diff.
  • If a comment is not directly applicable, state the smallest concrete next step and why a one-click suggestion is not safe.

Files:

  • src/aiconfigurator/cli/main.py
  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
src/aiconfigurator/cli/**

⚙️ CodeRabbit configuration file

src/aiconfigurator/cli/**: - Check that CLI argument changes preserve backward compatibility, validation behavior, defaults, and plain-output expectations.

  • For new or changed user-facing options, verify docs updates and generator/SDK wiring.
  • Watch for non-TTY assumptions in tests or output formatting.

Files:

  • src/aiconfigurator/cli/main.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - Check that tests cover the changed behavior rather than only the happy path.

  • Watch for fixtures or golden outputs that mask backend drift, support-matrix ordering changes, or CLI output regressions.

Files:

  • tests/unit/cli/test_cli_workflow.py
  • tests/unit/generator/test_fpm_artifacts.py
tests/unit/generator/test_*.py

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Test individual functions in isolation using unit tests with mocked schema loading and template rendering

Files:

  • tests/unit/generator/test_fpm_artifacts.py
🪛 ast-grep (0.44.1)
tests/unit/generator/test_fpm_artifacts.py

[error] 610-617: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=8,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 676-683: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=8,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🔇 Additional comments (8)
src/aiconfigurator/cli/main.py (4)

140-144: LGTM!


2307-2323: LGTM!


2370-2371: LGTM!


2439-2440: LGTM!

tests/unit/cli/test_cli_workflow.py (4)

25-25: LGTM!


199-243: LGTM!


263-282: LGTM!


830-830: LGTM!

Comment thread tests/unit/generator/test_fpm_artifacts.py Outdated
args.extend(extra_cli_args)

env = _collect_concrete_env(worker, main_container)
_require_cli_option(args, "--benchmark-mode", expected="agg")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid OOM during data collection, we switched to disaggregated "prefill" and "decode".

Signed-off-by: etshen <etshen@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/unit/generator/test_fpm_artifacts.py (2)

121-122: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Default point_types for mode="agg" doesn't match real agg output shape.

point_types = ["prefill" if mode == "agg" else mode] yields a single "prefill" point for agg, but the only agg usage in this suite (line 539) explicitly passes ["prefill", "decode"]. If a future test calls _benchmark_result(mode="agg") without an explicit point_types, it'll silently produce an incomplete/wrong payload.

♻️ Proposed fix
     if point_types is None:
-        point_types = ["prefill" if mode == "agg" else mode]
+        point_types = ["prefill", "decode"] if mode == "agg" else [mode]
🤖 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 `@tests/unit/generator/test_fpm_artifacts.py` around lines 121 - 122, Update
the defaulting logic in _benchmark_result so mode="agg" uses both "prefill" and
"decode" point types, matching the explicitly configured aggregate output shape;
retain the existing single-type defaults for other modes.

1322-1341: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse _set_benchmark_mode instead of re-deriving the index lookup.

Both tests manually reimplement the same args.index("--benchmark-mode") + assignment already provided by the helper.

♻️ Proposed fix
 def test_fpm_accepts_supported_benchmark_modes(benchmark_mode):
     params = _params()
-    args = params["params"]["agg"]["extra_cli_args"]
-    index = args.index("--benchmark-mode")
-    args[index + 1] = benchmark_mode
+    _set_benchmark_mode(params, benchmark_mode)

     artifacts = _render(params)
 def test_fpm_rejects_unsupported_benchmark_mode():
     params = _params()
-    args = params["params"]["agg"]["extra_cli_args"]
-    index = args.index("--benchmark-mode")
-    args[index + 1] = "disagg"
+    _set_benchmark_mode(params, "disagg")

     with pytest.raises(ValueError, match="agg, prefill, decode"):
🤖 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 `@tests/unit/generator/test_fpm_artifacts.py` around lines 1322 - 1341, Update
both benchmark-mode tests to use the existing _set_benchmark_mode helper for
applying the parameter instead of manually locating --benchmark-mode and
assigning the following argument. Pass each test’s benchmark mode to the helper
while preserving the current artifact and ValueError assertions.
🤖 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.

Nitpick comments:
In `@tests/unit/generator/test_fpm_artifacts.py`:
- Around line 121-122: Update the defaulting logic in _benchmark_result so
mode="agg" uses both "prefill" and "decode" point types, matching the explicitly
configured aggregate output shape; retain the existing single-type defaults for
other modes.
- Around line 1322-1341: Update both benchmark-mode tests to use the existing
_set_benchmark_mode helper for applying the parameter instead of manually
locating --benchmark-mode and assigning the following argument. Pass each test’s
benchmark mode to the helper while preserving the current artifact and
ValueError assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c4da3201-c3c7-46be-b11a-0db26707459d

📥 Commits

Reviewing files that changed from the base of the PR and between 9581f22 and 0a3f94d.

📒 Files selected for processing (5)
  • docs/cli_user_guide.md
  • docs/dynamo_deployment_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/generator/builders/fpm_builder.py
  • tests/unit/generator/test_fpm_artifacts.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/cli_user_guide.md
  • docs/generator_overview.md
  • src/aiconfigurator/generator/builders/fpm_builder.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
**/*

📄 CodeRabbit inference engine (.claude/rules/repo-guide.md)

**/*: Treat this file as the only always-injected rule file; do not add new always-on rules here without human approval. New rule files must include paths: frontmatter.
When reviewing changes in a governed area, read that area's rule files first, even if path-based auto-loading does not occur during a read-only review. Rule violations are review findings even when the code works.
A task must remain within its module: collector tasks may change only collector/ and its tests, generator tasks only src/aiconfigurator/generator/ and its tests, and SDK tasks must not modify either. Cross-module contract changes require explicit human approval.

Files:

  • docs/dynamo_deployment_guide.md
  • tests/unit/generator/test_fpm_artifacts.py

⚙️ CodeRabbit configuration file

**/*: - Prefer applicable inline comments. When the correct fix is clear, small, and limited to the commented diff hunk, include it as a GitHub Suggested Change so the author can apply it with one click.

  • Do not use a suggested change when the fix requires broader design choices, multiple files, generated artifacts, unavailable context, or validation that cannot be inferred from the diff.
  • If a comment is not directly applicable, state the smallest concrete next step and why a one-click suggestion is not safe.

Files:

  • docs/dynamo_deployment_guide.md
  • tests/unit/generator/test_fpm_artifacts.py
docs/**

⚙️ CodeRabbit configuration file

docs/**: - Check that docs match changed CLI, SDK, generator, backend, and support-matrix behavior.

  • Flag docs that describe unsupported runtimes, stale command names, or behavior not covered by tests or support-matrix evidence.

Files:

  • docs/dynamo_deployment_guide.md
tests/unit/generator/**

📄 CodeRabbit inference engine (.claude/rules/generator/cross_module_impact.md)

Update generator test fixtures and assertions when parameters are renamed.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/unit/generator/**/*.py

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

tests/unit/generator/**/*.py: Use fast unit tests for pure generator logic, testing individual functions in isolation and mocking schema loading and template rendering.
Test generator edge cases including MoE, disaggregated mode, aggregated mode, speculative decoding, prefix caching, minimal configuration, PVC configuration, each backend, and benchmark mode.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/**/*.{py,yaml,txt,sh}

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Use integration tests for the full input-to-artifacts pipeline, comparing output against golden snapshots without external dependencies.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/unit/generator/test_*.py

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Place generator unit tests in tests/unit/generator/ and use descriptive test files such as test_aggregators.py, test_rule_engine.py, and backend-specific CLI argument tests.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (AGENTS.md)

Run ruff check . and ruff format --check . to validate Python linting and formatting.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Run unit tests with pytest -m unit; use pytest -m "unit or build" for the build-test subset when required data is available.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - Check that tests cover the changed behavior rather than only the happy path.

  • Watch for fixtures or golden outputs that mask backend drift, support-matrix ordering changes, or CLI output regressions.

Files:

  • tests/unit/generator/test_fpm_artifacts.py
🪛 ast-grep (0.44.1)
tests/unit/generator/test_fpm_artifacts.py

[error] 182-189: Command coming from incoming request
Context: subprocess.run(
["bash", str(script_path)],
text=True,
capture_output=True,
env=env,
timeout=8,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[info] 162-162: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (8)
tests/unit/generator/test_fpm_artifacts.py (6)

690-769: Shutdown-grace assertion fix confirmed applied.

Both rewrites of engine_shutdown_grace_seconds=30 are now preceded by assert script.count(...) == 1, addressing the earlier review concern about a silently-no-op .replace() masking backend drift.

Also applies to: 772-839


386-424: Zombie-aware process check and bounded-wait cleanup look solid.

_process_is_running correctly treats zombie/dead states as "not running" via /proc/<pid>/status, and _assert_process_stopped polls with a deadline before force-killing and failing — good hygiene for these subprocess tests.


534-598: Good schema-v1 acceptance/rejection coverage.

The parametrized accept-cases (prefill/decode/agg point types) and the reject-cases (schema version, mode mismatch, coverage, result count, point type, dp_rank, non-object payload) give solid edge-case coverage of the runtime validation contract, satisfying the "Test generator edge cases including... benchmark mode" expectation.

Also applies to: 671-680


600-668: DP wait/local-range logic and multinode arg assertions look correct.

Rank-file naming (base.stem/base.suffix), local data-parallel-size-local/start-rank derivation, and glob-based output verification are all internally consistent with the fake engine's writes.

Also applies to: 1125-1207


113-122: 🎯 Functional Correctness

list[str] | None is fine here. The repo targets Python 3.10+, and this file already enables from __future__ import annotations, so the annotation won’t break imports.

			> Likely an incorrect or invalid review comment.

146-192: 🚀 Performance & Scalability

No marker change needed These subprocess-based run.sh tests are already under pytest.mark.unit, and unit is defined to include lightweight integration tests.

docs/dynamo_deployment_guide.md (2)

489-501: Section 6 content checks out against the FPM test suite.

Artifact list, Pod/LeaderWorkerSet split, extra_cli_args/extra_env injection points, and the --benchmark-mode contract all match the behavior exercised in tests/unit/generator/test_fpm_artifacts.py.


513-513: 📐 Maintainability & Code Quality

Cross-reference is valid. cli_user_guide.md#fpm-v1-resource-workload-and-run-script exists, so there’s nothing to fix here.

			> Likely an incorrect or invalid review comment.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants