Skip to content

Commit aa4472c

Browse files
rwgkcursoragent
andcommitted
pathfinder: split compatibility policy surface
Separate item validation, pairwise CTK coherence, and driver checks so later component- and pipeline-aware rules can land without changing current guard-rails behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent a441f10 commit aa4472c

1 file changed

Lines changed: 140 additions & 64 deletions

File tree

cuda_pathfinder/cuda/pathfinder/_compatibility_guard_rails.py

Lines changed: 140 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,15 @@
5454
ItemKind: TypeAlias = str
5555
PackagedWith: TypeAlias = str
5656
CtkVersionConstraintArg: TypeAlias = str | SpecifierSet | None
57+
PairwiseItemRelation: TypeAlias = str
5758

5859
_CTK_VERSION_RE = re.compile(r"^(?P<major>\d+)\.(?P<minor>\d+)")
5960
_CTK_VERSION_CONSTRAINT_ERROR = (
6061
"ctk_version must be None, a non-empty PEP 440 specifier string like '>=13.2,<14', "
6162
"or a packaging.specifiers.SpecifierSet."
6263
)
64+
_PAIRWISE_ITEM_RELATION_NONE = "none"
65+
_PAIRWISE_ITEM_RELATION_EXACT_CTK_MATCH_REQUIRED = "exact-ctk-match-required"
6366

6467
_STATIC_LIBS_PACKAGED_WITH: dict[str, PackagedWith] = {
6568
"cudadevrt": "ctk",
@@ -392,57 +395,133 @@ def _resolve_binary_item(utility_name: str, abs_path: str) -> ResolvedItem:
392395
)
393396

394397

398+
def _unsupported_packaging_message(
399+
item: ResolvedItem, *, allow_compatibility_neutral_driver_libraries: bool = False
400+
) -> str:
401+
message = "v1 compatibility checks only give definitive answers for packaged_with='ctk' items"
402+
if allow_compatibility_neutral_driver_libraries:
403+
message += ", plus compatibility-neutral driver libraries"
404+
return f"{message}. {item.describe()} is packaged_with={item.packaged_with!r}."
405+
406+
407+
def _missing_ctk_metadata_message(item: ResolvedItem) -> str:
408+
return (
409+
"v1 compatibility checks require either an enclosing CUDA Toolkit root "
410+
"with cuda.h or wheel metadata that can be traced to an installed "
411+
f"cuda-toolkit distribution. Could not determine the CTK version for {item.describe()}."
412+
)
413+
414+
415+
def _ctk_constraint_failure_message(item: ResolvedItem, constraint: CtkVersionConstraint) -> str:
416+
assert item.ctk_version is not None
417+
return f"{item.describe()} resolves to CTK {item.ctk_version}, which does not satisfy ctk_version{constraint}."
418+
419+
420+
def _ctk_pair_mismatch_message(item1: ResolvedItem, item2: ResolvedItem) -> str:
421+
assert item1.ctk_version is not None
422+
assert item2.ctk_version is not None
423+
return (
424+
f"{item1.describe()} resolves to CTK {item1.ctk_version}, while "
425+
f"{item2.describe()} resolves to CTK {item2.ctk_version}. "
426+
"v1 requires an exact CTK major.minor match."
427+
)
428+
429+
430+
def _driver_major_mismatch_message(driver_cuda_version: DriverCudaVersion, item: ResolvedItem) -> str:
431+
assert item.ctk_version is not None
432+
return (
433+
f"Driver version {driver_cuda_version.encoded} only supports CUDA major version {driver_cuda_version.major}, "
434+
f"but {item.describe()} requires CTK {item.ctk_version}. "
435+
"v1 requires driver_major >= ctk_major."
436+
)
437+
438+
439+
def _compatible_pair_message(driver_cuda_version: DriverCudaVersion, item1: ResolvedItem, item2: ResolvedItem) -> str:
440+
assert item1.ctk_version is not None
441+
return (
442+
f"{item1.describe()} and {item2.describe()} both resolve to CTK {item1.ctk_version}, "
443+
f"and driver version {driver_cuda_version.encoded} satisfies the v1 driver guard rail."
444+
)
445+
446+
447+
def _supported_packaging_result(item: ResolvedItem) -> CompatibilityResult | None:
448+
if item.packaged_with == "ctk":
449+
return None
450+
return CompatibilityResult(status="insufficient_metadata", message=_unsupported_packaging_message(item))
451+
452+
453+
def _ctk_metadata_result(item: ResolvedItem) -> CompatibilityResult | None:
454+
if item.ctk_version is not None and item.ctk_version_source is not None:
455+
return None
456+
return CompatibilityResult(status="insufficient_metadata", message=_missing_ctk_metadata_message(item))
457+
458+
459+
def _classify_pairwise_item_relation(item1: ResolvedItem, item2: ResolvedItem) -> PairwiseItemRelation:
460+
if item1.packaged_with == "driver" or item2.packaged_with == "driver":
461+
return _PAIRWISE_ITEM_RELATION_NONE
462+
return _PAIRWISE_ITEM_RELATION_EXACT_CTK_MATCH_REQUIRED
463+
464+
465+
def _ctk_coherence_result(item1: ResolvedItem, item2: ResolvedItem) -> CompatibilityResult | None:
466+
assert item1.ctk_version is not None
467+
assert item2.ctk_version is not None
468+
if item1.ctk_version == item2.ctk_version:
469+
return None
470+
return CompatibilityResult(status="incompatible", message=_ctk_pair_mismatch_message(item1, item2))
471+
472+
473+
def _pipeline_compatibility_result(_item1: ResolvedItem, _item2: ResolvedItem) -> CompatibilityResult | None:
474+
# v1 has no pipeline-sensitive rules yet, but this separate hook keeps the
475+
# policy surface ready for nvrtc/nvJitLink and nvvm work.
476+
return None
477+
478+
479+
def _pairwise_policy_result(item1: ResolvedItem, item2: ResolvedItem) -> CompatibilityResult | None:
480+
relation = _classify_pairwise_item_relation(item1, item2)
481+
if relation == _PAIRWISE_ITEM_RELATION_NONE:
482+
return None
483+
if relation == _PAIRWISE_ITEM_RELATION_EXACT_CTK_MATCH_REQUIRED:
484+
result = _ctk_coherence_result(item1, item2)
485+
if result is not None:
486+
return result
487+
return _pipeline_compatibility_result(item1, item2)
488+
raise AssertionError(f"Unhandled pairwise item relation: {relation!r}")
489+
490+
491+
def _driver_compatibility_result(
492+
driver_cuda_version: DriverCudaVersion, item: ResolvedItem
493+
) -> CompatibilityResult | None:
494+
assert item.ctk_version is not None
495+
if driver_cuda_version.major >= item.ctk_version.major:
496+
return None
497+
return CompatibilityResult(
498+
status="incompatible",
499+
message=_driver_major_mismatch_message(driver_cuda_version, item),
500+
)
501+
502+
395503
def compatibility_check(
396504
driver_cuda_version: DriverCudaVersion, item1: ResolvedItem, item2: ResolvedItem
397505
) -> CompatibilityResult:
398506
for item in (item1, item2):
399-
if item.packaged_with != "ctk":
400-
return CompatibilityResult(
401-
status="insufficient_metadata",
402-
message=(
403-
"v1 compatibility checks only give definitive answers for "
404-
f"packaged_with='ctk' items. {item.describe()} is packaged_with={item.packaged_with!r}."
405-
),
406-
)
407-
if item.ctk_version is None or item.ctk_version_source is None:
408-
return CompatibilityResult(
409-
status="insufficient_metadata",
410-
message=(
411-
"v1 compatibility checks require either an enclosing CUDA Toolkit root "
412-
"with cuda.h or wheel metadata that can be traced to an installed "
413-
f"cuda-toolkit distribution. Could not determine the CTK version for {item.describe()}."
414-
),
415-
)
507+
result = _supported_packaging_result(item)
508+
if result is not None:
509+
return result
510+
result = _ctk_metadata_result(item)
511+
if result is not None:
512+
return result
416513

417-
assert item1.ctk_version is not None
418-
assert item2.ctk_version is not None
514+
result = _pairwise_policy_result(item1, item2)
515+
if result is not None:
516+
return result
419517

420-
if item1.ctk_version != item2.ctk_version:
421-
return CompatibilityResult(
422-
status="incompatible",
423-
message=(
424-
f"{item1.describe()} resolves to CTK {item1.ctk_version}, while "
425-
f"{item2.describe()} resolves to CTK {item2.ctk_version}. "
426-
"v1 requires an exact CTK major.minor match."
427-
),
428-
)
429-
430-
if driver_cuda_version.major < item1.ctk_version.major:
431-
return CompatibilityResult(
432-
status="incompatible",
433-
message=(
434-
f"Driver version {driver_cuda_version.encoded} only supports CUDA major version {driver_cuda_version.major}, "
435-
f"but {item1.describe()} requires CTK {item1.ctk_version}. "
436-
"v1 requires driver_major >= ctk_major."
437-
),
438-
)
518+
result = _driver_compatibility_result(driver_cuda_version, item1)
519+
if result is not None:
520+
return result
439521

440522
return CompatibilityResult(
441523
status="compatible",
442-
message=(
443-
f"{item1.describe()} and {item2.describe()} both resolve to CTK {item1.ctk_version}, "
444-
f"and driver version {driver_cuda_version.encoded} satisfies the v1 driver guard rail."
445-
),
524+
message=_compatible_pair_message(driver_cuda_version, item1, item2),
446525
)
447526

448527

@@ -474,33 +553,31 @@ def _enforce_supported_packaging(self, item: ResolvedItem) -> None:
474553
if item.packaged_with == "ctk":
475554
return
476555
raise CompatibilityInsufficientMetadataError(
477-
"v1 compatibility checks only give definitive answers for "
478-
f"packaged_with='ctk' items, plus compatibility-neutral driver libraries. "
479-
f"{item.describe()} is packaged_with={item.packaged_with!r}."
556+
_unsupported_packaging_message(item, allow_compatibility_neutral_driver_libraries=True)
480557
)
481558

482559
def _enforce_ctk_metadata(self, item: ResolvedItem) -> None:
483-
if item.ctk_version is not None and item.ctk_version_source is not None:
560+
result = _ctk_metadata_result(item)
561+
if result is None:
484562
return
485-
raise CompatibilityInsufficientMetadataError(
486-
"v1 compatibility checks require either an enclosing CUDA Toolkit root "
487-
"with cuda.h or wheel metadata that can be traced to an installed "
488-
f"cuda-toolkit distribution. Could not determine the CTK version for {item.describe()}."
489-
)
563+
result.require_compatible()
490564

491565
def _enforce_constraints(self, item: ResolvedItem) -> None:
492566
assert item.ctk_version is not None
493567
if self._ctk_version_constraint is not None and not self._ctk_version_constraint.matches(item.ctk_version):
494-
raise CompatibilityCheckError(
495-
f"{item.describe()} resolves to CTK {item.ctk_version}, which does not satisfy "
496-
f"ctk_version{self._ctk_version_constraint}."
497-
)
568+
raise CompatibilityCheckError(_ctk_constraint_failure_message(item, self._ctk_version_constraint))
498569

499-
def _anchor_item(self) -> ResolvedItem | None:
500-
for item in self._resolved_items:
501-
if item.packaged_with == "ctk":
502-
return item
503-
return None
570+
def _enforce_driver_compatibility(self, item: ResolvedItem) -> None:
571+
result = _driver_compatibility_result(self._get_driver_cuda_version(), item)
572+
if result is None:
573+
return
574+
result.require_compatible()
575+
576+
def _enforce_pairwise_compatibility(self, prior_item: ResolvedItem, item: ResolvedItem) -> None:
577+
result = _pairwise_policy_result(prior_item, item)
578+
if result is None:
579+
return
580+
result.require_compatible()
504581

505582
def _remember(self, item: ResolvedItem) -> None:
506583
if item not in self._resolved_items:
@@ -520,10 +597,9 @@ def _register_and_check(self, item: ResolvedItem) -> None:
520597
self._enforce_supported_packaging(item)
521598
self._enforce_ctk_metadata(item)
522599
self._enforce_constraints(item)
523-
anchor = self._anchor_item()
524-
if anchor is None:
525-
anchor = item
526-
compatibility_check(self._get_driver_cuda_version(), anchor, item).require_compatible()
600+
for prior_item in self._resolved_items:
601+
self._enforce_pairwise_compatibility(prior_item, item)
602+
self._enforce_driver_compatibility(item)
527603
self._remember(item)
528604

529605
def load_nvidia_dynamic_lib(self, libname: str) -> LoadedDL:

0 commit comments

Comments
 (0)