Skip to content

feat: resolve Slurm serving deployments - #890

Merged
nabinchha merged 22 commits into
feat/slurm-executionfrom
codex/866-slurm-serving-resolution
Aug 28, 2026
Merged

feat: resolve Slurm serving deployments#890
nabinchha merged 22 commits into
feat/slurm-executionfrom
codex/866-slurm-serving-resolution

Conversation

@nabinchha

@nabinchha nabinchha commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

📋 Summary

Adds the pure, package-owned Slurm serving resolver for vLLM deployments. It combines inspected images, authored serving configuration, and planner-owned placement into deterministic process, readiness, backend, and logical-endpoint records without submitting work or managing processes.

🔗 Related Issue

Closes #866

🔄 Changes

Added

  • Resolve single-node and multi-node tensor/pipeline topologies into immutable process, rendezvous, readiness, backend, and logical-endpoint contracts.
  • Add a planner-owned resolution context that binds each placed deployment to its logical endpoint claim before service resolution.
  • Add deterministic single-node, multi-node, and multiple-node-group goldens, negative and round-trip coverage, package import checks, and wheel-install smoke coverage.

Changed

  • Preserve model aliases, model sources, served model names, launch timing, backpressure, environment bindings, and tokenized extra arguments as distinct inputs.
  • Preserve the inspected vLLM runtime version as digest-bound provenance without a package-version compatibility matrix.
  • Centralize shared constrained scalar aliases in data_designer.slurm.types while retaining temporary compatibility re-exports for in-flight Stage 2 branches.
  • Split shared environment bindings and vLLM-specific configuration from the general run records while preserving public configuration exports.
  • Revalidate launch arguments, environment bindings, topology, ordering, rendezvous, readiness, and network identities when persisted resolved records are loaded.
  • Name deployment-wide and node-group-local replica indices explicitly; retain node_index with a Stage 2 migration TODO.
  • Split serving tests by resolver behavior, persisted-record invariants, and launch-policy validation.

Fixed

  • Reject mismatched or colliding planner inputs before constructing a resolved service and normalize inconsistent output records to VllmServerResolutionError.
  • Reject partial resource allocations, inconsistent rendezvous state, noncanonical process layouts, and network collisions.
  • Reject duplicate or conflicting options, option terminators, secret-shaped values, underscore aliases, single- and double-dash abbreviations, attached short topology aliases, alternate transports, and compiler/runtime-owned vLLM flags or environment names.
  • Preserve least-connections balancing and positive whole-second Retry-After behavior.
  • Reject expert-parallel replicas that span multiple nodes while preserving independent single-node expert-parallel replicas in wider allocations.
  • Reject ambiguous readiness paths without interpreting opaque plugin-owned payloads.

🧪 Testing

  • Slurm package suite passes (634 tests)
  • Serving suite passes (77 tests)
  • E2E tests added/updated (not applicable; this resolver is pure and runtime-neutral)
  • make check-slurm passes
  • make test-slurm-wheel-install passes

✅ Checklist

  • Follows commit message conventions
  • Commits are signed off (DCO)
  • Architecture contract and issue acceptance criteria reflect version-agnostic runtime provenance

Review Focus


Description updated with AI

@nabinchha
nabinchha requested a review from a team as a code owner August 25, 2026 16:08
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds a package-owned resolver that converts inspected images, authored vLLM configuration, and planner placement into immutable Slurm serving contracts.

  • Introduces resolved process, rendezvous, readiness, backend, and logical-endpoint records.
  • Adds planner-to-serving endpoint binding and cross-record validation.
  • Extracts shared environment and vLLM launch-policy configuration.
  • Adds golden, negative, round-trip, package-import, and wheel-install coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/data-designer-slurm/src/data_designer/slurm/serving/resolver.py Resolves planner placement and authored vLLM policy into deterministic deployment-wide process and endpoint records.
packages/data-designer-slurm/src/data_designer/slurm/serving/deployment.py Defines immutable resolved deployment contracts and revalidates topology, process placement, readiness, rendezvous, and network identities.
packages/data-designer-slurm/src/data_designer/slurm/config/vllm.py Defines the authored vLLM lifecycle, launch timing, readiness, backpressure, argument, and environment configuration.
packages/data-designer-slurm/src/data_designer/slurm/config/vllm_validation.py Centralizes validation for vLLM-owned arguments, environment bindings, readiness paths, and plaintext-secret shapes.
packages/data-designer-slurm/src/data_designer/slurm/planning/models.py Extends planner-owned topology and placement contracts used to bind deployments to serving endpoint claims.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Authored vLLM configuration] --> D[Serving resolver]
    B[Inspected serving image] --> D
    C[Planner placement and endpoint claims] --> D
    D --> E[Resolved process records]
    D --> F[Rendezvous and readiness records]
    D --> G[Backend endpoints]
    D --> H[Logical endpoint]
    E --> I[Persisted resolved deployment]
    F --> I
    G --> I
    H --> I
Loading

Reviews (23): Last reviewed commit: "fix option argument validation gaps" | Re-trigger Greptile

Comment thread packages/data-designer-slurm/src/data_designer/slurm/serving/context.py Outdated
return values


def validate_vllm_environment_bindings(

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.

VLLM_API_KEY seems worth treating as an owned environment name unless we add an explicit auth contract. vLLM turns it into bearer authentication for /v1, while ResolvedLogicalEndpoint has no credential or header-forwarding input, so readiness can succeed but generation requests through the proxy can return 401. Could we reject it for V1, or carry the secret reference into the logical-endpoint contract?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed and addressed in 35d44f5. VLLM_API_KEY is now rejected as runtime-owned at both the authored configuration and persisted VllmLaunchPolicy boundaries. V1 will not accept bearer authentication until credential or header forwarding is explicit in the logical-endpoint contract.

Comment thread packages/data-designer-slurm/src/data_designer/slurm/config/run.py Outdated
class PortClaim(ContractValue):
name: Identifier
role: Literal["http", "rendezvous", "logical_endpoint"]
# TODO: Rename node_index to allocation_node_index after downstream Stage 2 branches converge on this contract.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@andreatnvidia while reviewing this, I noticed a few things to change in the agreed upon contract. To not disrupt the parallel work stream, I added TODO's to reconcile later after perhaps M0 and M1 gates close.

return True
return flag.startswith("--") and any(
owned_flag.startswith(flag) for owned_flag in _OWNED_VLLM_FLAGS if owned_flag.startswith("--")
)

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.

extra_args still has a short-option escape hatch: -t 4 gets past this check, but argparse treats -t as the owned -tp option. That can change tensor parallelism at launch while the resolved topology still says something else. Could we run the abbreviation check against the single-dash aliases as well and cover their unambiguous prefixes in the rejection tests?

@nabinchha nabinchha Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Addressed in 56c7b677. The owned-flag abbreviation check now applies within both the single-dash and double-dash namespaces, so -t is rejected as an abbreviation of the runtime-owned -tp option. Regression coverage exercises the tokenized ["-t", "4"] form and all currently unambiguous owned short prefixes (-a, -as, -dc, -e, -pc, and -t) at both the authored-configuration and persisted launch-policy boundaries. The full Slurm suite passes with 638 tests.

Comment thread packages/data-designer-slurm/src/data_designer/slurm/serving/resolver.py Outdated
raise ValueError("vLLM argument option terminators are not supported")
if _is_reserved_vllm_flag(candidate_flag):
raise ValueError(f"vLLM argument {candidate_flag!r} is owned by the compiler or runtime")
if candidate_flag.startswith("--") and is_secret_bearing_name(candidate_flag.removeprefix("--")):

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.

There's another credential path through extra_args: only option names are checked, so an opaque value token such as --hf-overrides, {"api_key":"..."} is accepted and then copied into ResolvedVllmLaunchPolicy. Since the resolved plan is meant to contain no credentials, can we reject secret-bearing values before persistence or model them with SecretRef instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 505a7f5. The authored VllmServerConfig and persisted ResolvedVllmLaunchPolicy now share recursive secret-key validation for structured and assignment-shaped argument payloads, including standalone JSON values and --flag=value JSON. Non-null values under secret-bearing keys are rejected without echoing payload contents, while non-secret plugin-owned JSON remains accepted. Regression coverage exercises both boundaries.

@@ -157,8 +93,6 @@ def validate_input(self) -> BuilderInput:
valid = isinstance(self.inline.get("columns"), list)
if not valid:

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.

I think this boundary still needs a recursive secret check. BuilderInput.inline accepts an arbitrary serialized Data Designer config once the outer shape matches, and that object is copied into the resolved builder and plan. An inline payload containing something like api_key: "..." will therefore persist the credential in both authored and resolved manifests. Could we reject secret-bearing keys here, or explicitly externalize them before persistence?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 505a7f5. BuilderInput and ResolvedBuilderInput now both apply the same recursive persisted-JSON secret check. Non-null values under secret-bearing keys are rejected, canonical null secret fields remain accepted, known non-secret relational keys remain allowed, and validation errors do not include the rejected value. Added authored and resolved-record regression coverage.

"""Raised when planner inputs cannot produce a supported vLLM server specification."""


@dataclass(frozen=True)

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.

This context keeps the two values together, but it doesn't prove they came from the same plan. A valid deployment from plan A can be paired with plan B's same-named logical endpoint claim, and the resolver will publish plan B's port. Could the boundary take a plan plus deployment ID again, or carry a shared plan identity on both inputs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 505a7f5. I removed VllmServerResolutionContext. resolve_vllm_server now takes the complete ResolvedSlurmRunPlan plus a deployment ID and derives both the deployment placement and client-owned logical endpoint from that one plan. It also checks the client host and network collision at the boundary, so independently composed plan fragments are no longer representable.

raise ValueError("resolved server nodes must divide evenly into replica groups")
if self.gpus_per_node % self.topology.tensor_parallel:
raise ValueError("resolved server GPUs must divide evenly into tensor-parallel lanes")
expected_topology = ResolvedTopology(

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.

Would it be worth centralizing this arithmetic on ResolvedTopology? The same seven fields are derived in planning/models.py, while the resolver also assumes pipeline_parallel == nodes_per_replica. A small derive(...) helper would let each boundary compare against its own inputs without requiring future topology changes in two places.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 505a7f5. ResolvedTopology.derive now owns the seven derived topology fields and validates the node-group and GPU-lane divisibility inputs. Both ResolvedDeployment and ResolvedVllmServerDeployment compare against that shared derivation, with focused valid and invalid derivation tests.

)
)

try:

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.

Could the try cover the whole derivation rather than only the final aggregate construction? Intermediate records can still raise raw pydantic.ValidationError; for example, a valid long deployment ID produces an over-limit derived process ID before reaching this block. Wrapping all record construction would keep callers on VllmServerResolutionError as constraints evolve.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 505a7f5. The public resolver now wraps the entire private derivation call, so Pydantic ValidationError from any intermediate or aggregate record is normalized to VllmServerResolutionError. The regression test uses a maximum-length valid deployment ID that makes an intermediate derived process ID invalid, confirming that the raw validation error no longer escapes.

for value in values:
validate_plain_text(value, field_name="vLLM argument")
flag = value.partition("=")[0].replace("_", "-")
candidate_flag = flag.split(maxsplit=1)[0]

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.

Small parsing edge here: candidate_flag is computed from the unstripped token. A whitespace-only value raises IndexError, while leading whitespace makes an owned option look like a non-option and bypasses the reserved and secret checks. Requiring canonical tokens with value == value.strip() before splitting would keep both cases inside the config validation boundary.

@andreatnvidia

Copy link
Copy Markdown
Contributor

One coordination point with #893: the branches currently conflict in config/__init__.py and contracts.py, and the digest conflict needs a semantic choice rather than just conflict-marker cleanup. This branch aliases compute_sha256 to canonical JSON bytes, while #893 introduces persisted-text hashing. Could we land that shared scalar and digest migration as a jointly owned prerequisite, or rebase after #893 and remove the temporary compatibility surface? That would leave one clear digest API for the later integration.

Add pure, package-owned vLLM compatibility and deterministic process, readiness, backend, and logical endpoint resolution. Validate topology, launch inputs, and network identities with single-node and multi-node golden coverage.

Closes #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Revalidate persisted launch policy inputs, require canonical process ordering, and normalize resolver errors. Reject vLLM CLI aliases and transports that could override compiler-owned topology or endpoints.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Preserve independent single-node expert-parallel replicas while rejecting cross-node EP. Block attached compiler-owned vLLM topology aliases, require canonical runtime versions, and cover the boundaries with regression tests.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Reject unmodeled topology, plugin, LoRA, speculative-model, and environment overrides at authored and persisted boundaries. Validate JSON arguments, secret references, readiness paths, and compatibility version lengths.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Derive serving placement and client endpoint records from the same resolved plan so callers cannot mix contracts across plans. Reject vLLM API authentication until the logical endpoint models credential forwarding.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
- enforce plan-owned environment and endpoint behavior
- limit compatibility to tested vLLM release series
- split shared and vLLM configuration from run records
- cover multi-group ordering and launch delays

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Use action-named shared helpers for option extraction and duration
conversion while keeping vLLM flag canonicalization backend-specific.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Track the tested runtime range and contract revision without repeating
baseline vLLM or package-owned behaviors as capability booleans.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Preserve inspected runtime versions as digest-bound provenance without
hard-coded support gates or redundant compatibility records. Continue to
validate persisted text and compiler-owned vLLM arguments.

Refs #866

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
- make vLLM resolution consume placement inputs before plan assembly
- keep serving internals backend-specific and remove speculative exports
- clarify validation ownership, secret redaction, and digest semantics
- Join placement and endpoint claims through one planner-owned context.\n- Normalize inconsistent resolved records to the serving error boundary.\n- Split resolver, record, and launch-policy tests by ownership.

Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Derive deployment and endpoint inputs from one resolved plan and centralize topology arithmetic. Reject plaintext secrets in persisted builder and vLLM argument payloads, normalize resolver errors, and require canonical argv tokens.
@nabinchha
nabinchha force-pushed the codex/866-slurm-serving-resolution branch from 505a7f5 to 5ed2f07 Compare August 27, 2026 21:30
Comment thread packages/data-designer-slurm/src/data_designer/slurm/config/run.py Outdated
@nabinchha
nabinchha merged commit 69f4c98 into feat/slurm-execution Aug 28, 2026
7 checks passed
@nabinchha
nabinchha deleted the codex/866-slurm-serving-resolution branch August 28, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants