Spaces:
Sleeping
Sleeping
Commit ·
7e13d74
1
Parent(s): 2409b81
Structural PKG.* checks @919af26
Browse files
tools/spec_sync/state.json
CHANGED
|
@@ -6,6 +6,10 @@
|
|
| 6 |
"synced_at": "2026-06-02T00:00:00Z",
|
| 7 |
"synced_by": "initial-setup",
|
| 8 |
"rules_pinned_against": [
|
| 9 |
-
"AA.002 supported-file-types (validate.py:_AA_002_ALLOWED)"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
]
|
| 11 |
}
|
|
|
|
| 6 |
"synced_at": "2026-06-02T00:00:00Z",
|
| 7 |
"synced_by": "initial-setup",
|
| 8 |
"rules_pinned_against": [
|
| 9 |
+
"AA.002 supported-file-types (validate.py:_AA_002_ALLOWED) — foundation",
|
| 10 |
+
"PKG.1 interface file (validate.py:_check_pkg_layout) — local SDK packaging spec",
|
| 11 |
+
"PKG.6 package manifest (validate.py:_check_pkg_layout) — local SDK packaging spec",
|
| 12 |
+
"PKG.NO-ROOT-USD no root USDs (validate.py:_check_pkg_layout) — local SDK packaging spec",
|
| 13 |
+
"PKG.NO-ARCHIVES no zip files (validate.py:_check_pkg_layout) — local SDK packaging spec"
|
| 14 |
]
|
| 15 |
}
|
tools/validation/plugins/simready-report/skills/simready-report/validate.py
CHANGED
|
@@ -692,21 +692,33 @@ _ATOMIC_ASSET_PATHS = (f"{_FOUNDATION_SPECS_BASE}/core/atomic_asset/"
|
|
| 692 |
|
| 693 |
|
| 694 |
def run_preliminary_checks(root: Path) -> list[dict]:
|
| 695 |
-
"""Preliminary check phase: filesystem-only
|
| 696 |
-
|
| 697 |
-
|
| 698 |
-
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
"""
|
| 709 |
-
|
|
|
|
|
|
|
|
|
|
| 710 |
|
| 711 |
|
| 712 |
# AA.002 supported-file-types — hardcoded from the foundation spec at
|
|
@@ -777,6 +789,128 @@ def _check_aa_002_supported_file_types(root: Path) -> list[dict]:
|
|
| 777 |
return issues
|
| 778 |
|
| 779 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 780 |
def discover_assets(
|
| 781 |
root: Path, exclude: Path | None = None,
|
| 782 |
) -> tuple[list[Path], list[dict]]:
|
|
|
|
| 692 |
|
| 693 |
|
| 694 |
def run_preliminary_checks(root: Path) -> list[dict]:
|
| 695 |
+
"""Preliminary check phase: filesystem-only checks, evaluated
|
| 696 |
+
before USD traversal.
|
| 697 |
+
|
| 698 |
+
Cheap, deterministic, runs every validation. The point is to
|
| 699 |
+
surface ALL filesystem-visible spec violations in a single
|
| 700 |
+
roundtrip — partners fix everything at once instead of getting
|
| 701 |
+
piece-meal feedback over multiple iterations.
|
| 702 |
+
|
| 703 |
+
Each check has a strong link to its source-of-truth spec section.
|
| 704 |
+
Two sources are in play:
|
| 705 |
+
- Foundation specs (NVIDIA/simready-foundation): AA.002.
|
| 706 |
+
Drift-watched via tools/spec_sync/.
|
| 707 |
+
- SDK packaging spec (docs/sdk/packaging-spec.md): PKG.*.
|
| 708 |
+
Lives in this repo, no drift watch needed.
|
| 709 |
+
|
| 710 |
+
Implemented:
|
| 711 |
+
- AA.002 supported-file-types (foundation)
|
| 712 |
+
- PKG.1 interface file convention (SDK §"Discovery Rules" #1+#4)
|
| 713 |
+
- PKG.6 package manifest required (SDK §"Discovery Rules" #6)
|
| 714 |
+
- PKG.NO-ROOT-USD no USDs at dataset root (SDK §"Folder Structure")
|
| 715 |
+
- PKG.NO-ARCHIVES no zip files (SDK §"Folder Structure" — packages
|
| 716 |
+
ship unpacked)
|
| 717 |
"""
|
| 718 |
+
issues: list[dict] = []
|
| 719 |
+
issues.extend(_check_aa_002_supported_file_types(root))
|
| 720 |
+
issues.extend(_check_pkg_layout(root))
|
| 721 |
+
return issues
|
| 722 |
|
| 723 |
|
| 724 |
# AA.002 supported-file-types — hardcoded from the foundation spec at
|
|
|
|
| 789 |
return issues
|
| 790 |
|
| 791 |
|
| 792 |
+
# SDK packaging spec — the SimReady asset packaging convention this
|
| 793 |
+
# repo's docs/sdk/packaging-spec.md mandates. Independent from the
|
| 794 |
+
# foundation specs (which cover USD-content, not packaging structure).
|
| 795 |
+
_SDK_PACKAGING_SPEC_URL = ("https://github.com/NVIDIA-dev/simready-oem-library-pm/"
|
| 796 |
+
"blob/main/docs/sdk/packaging-spec.md")
|
| 797 |
+
_SDK_PACKAGING_SPEC_FOLDER = f"{_SDK_PACKAGING_SPEC_URL}#folder-structure"
|
| 798 |
+
_SDK_PACKAGING_SPEC_DISCOVERY = f"{_SDK_PACKAGING_SPEC_URL}#discovery-rules"
|
| 799 |
+
_SDK_PACKAGING_SPEC_MANIFEST = f"{_SDK_PACKAGING_SPEC_URL}#package-manifest-wrapp"
|
| 800 |
+
|
| 801 |
+
|
| 802 |
+
def _check_pkg_layout(root: Path) -> list[dict]:
|
| 803 |
+
"""Checks against the SDK packaging spec's structural requirements.
|
| 804 |
+
|
| 805 |
+
Spec: docs/sdk/packaging-spec.md (in this repo). Codes follow the
|
| 806 |
+
spec's own numbered Discovery Rules where applicable.
|
| 807 |
+
|
| 808 |
+
Rules enforced:
|
| 809 |
+
PKG.1 Each top-level dir must contain
|
| 810 |
+
<dirname>/<dirname>.usd (Discovery Rules #1+#4).
|
| 811 |
+
PKG.6 Each top-level dir must contain .<dirname>.wrapp
|
| 812 |
+
(Discovery Rules #6 — "required, flag as error").
|
| 813 |
+
PKG.NO-ROOT-USD No USD files at the dataset root — each asset
|
| 814 |
+
must live in its own directory per Folder
|
| 815 |
+
Structure.
|
| 816 |
+
PKG.NO-ARCHIVES No .zip files anywhere — SimReady packages ship
|
| 817 |
+
unpacked per Folder Structure.
|
| 818 |
+
"""
|
| 819 |
+
issues: list[dict] = []
|
| 820 |
+
try:
|
| 821 |
+
entries = sorted(root.iterdir())
|
| 822 |
+
except OSError as e:
|
| 823 |
+
return [{
|
| 824 |
+
"code": "PKG.READ-FAILED",
|
| 825 |
+
"severity": "failure",
|
| 826 |
+
"path": str(root),
|
| 827 |
+
"spec_url": _SDK_PACKAGING_SPEC_URL,
|
| 828 |
+
"msg": f"Could not read dataset root: {e}",
|
| 829 |
+
}]
|
| 830 |
+
|
| 831 |
+
has_any_bundle_dir = False
|
| 832 |
+
for entry in entries:
|
| 833 |
+
rel = entry.name
|
| 834 |
+
if entry.is_file():
|
| 835 |
+
suffix = entry.suffix.lower()
|
| 836 |
+
if suffix == ".zip":
|
| 837 |
+
issues.append({
|
| 838 |
+
"code": "PKG.NO-ARCHIVES",
|
| 839 |
+
"severity": "failure",
|
| 840 |
+
"path": rel,
|
| 841 |
+
"spec_url": _SDK_PACKAGING_SPEC_FOLDER,
|
| 842 |
+
"msg": (f"'{rel}' is a zip archive. SimReady packages "
|
| 843 |
+
f"must be delivered as unpacked directories — "
|
| 844 |
+
f"extract all archives and re-publish."),
|
| 845 |
+
})
|
| 846 |
+
elif suffix in {".usd", ".usda", ".usdc", ".usdz"}:
|
| 847 |
+
issues.append({
|
| 848 |
+
"code": "PKG.NO-ROOT-USD",
|
| 849 |
+
"severity": "failure",
|
| 850 |
+
"path": rel,
|
| 851 |
+
"spec_url": _SDK_PACKAGING_SPEC_FOLDER,
|
| 852 |
+
"msg": (f"'{rel}' is a USD file at the dataset root. "
|
| 853 |
+
f"Each asset must live in its own directory: "
|
| 854 |
+
f"<asset_name>/<asset_name>.usd."),
|
| 855 |
+
})
|
| 856 |
+
continue
|
| 857 |
+
if not entry.is_dir():
|
| 858 |
+
continue
|
| 859 |
+
if entry.name.startswith(".") or entry.name in _SKIP_DIR_NAMES:
|
| 860 |
+
continue
|
| 861 |
+
has_any_bundle_dir = True
|
| 862 |
+
|
| 863 |
+
# PKG.1 — interface file convention
|
| 864 |
+
interface_candidates = [
|
| 865 |
+
entry / f"{entry.name}.usd",
|
| 866 |
+
entry / f"{entry.name}.usda",
|
| 867 |
+
entry / f"{entry.name}.usdc",
|
| 868 |
+
]
|
| 869 |
+
if not any(p.is_file() for p in interface_candidates):
|
| 870 |
+
try:
|
| 871 |
+
found = [str(p.relative_to(entry))
|
| 872 |
+
for p in sorted(entry.rglob("*"))
|
| 873 |
+
if p.is_file() and p.suffix.lower() in USD_EXTS][:5]
|
| 874 |
+
except OSError:
|
| 875 |
+
found = []
|
| 876 |
+
hint = (f" Found USDs here: {', '.join(found)}"
|
| 877 |
+
if found else " No USD files found in this directory.")
|
| 878 |
+
issues.append({
|
| 879 |
+
"code": "PKG.1",
|
| 880 |
+
"severity": "failure",
|
| 881 |
+
"path": rel + "/",
|
| 882 |
+
"spec_url": _SDK_PACKAGING_SPEC_DISCOVERY,
|
| 883 |
+
"msg": (f"Directory '{rel}/' must contain an interface "
|
| 884 |
+
f"file named '{rel}.usd' (or .usda/.usdc) per "
|
| 885 |
+
f"the SimReady packaging spec.{hint}"),
|
| 886 |
+
})
|
| 887 |
+
|
| 888 |
+
# PKG.6 — package manifest
|
| 889 |
+
manifest = entry / f".{entry.name}.wrapp"
|
| 890 |
+
if not manifest.is_file():
|
| 891 |
+
issues.append({
|
| 892 |
+
"code": "PKG.6",
|
| 893 |
+
"severity": "failure",
|
| 894 |
+
"path": rel + "/",
|
| 895 |
+
"spec_url": _SDK_PACKAGING_SPEC_MANIFEST,
|
| 896 |
+
"msg": (f"Directory '{rel}/' is missing the required "
|
| 897 |
+
f"package manifest '.{rel}.wrapp'."),
|
| 898 |
+
})
|
| 899 |
+
|
| 900 |
+
if not has_any_bundle_dir and not issues:
|
| 901 |
+
issues.append({
|
| 902 |
+
"code": "PKG.EMPTY",
|
| 903 |
+
"severity": "failure",
|
| 904 |
+
"path": ".",
|
| 905 |
+
"spec_url": _SDK_PACKAGING_SPEC_FOLDER,
|
| 906 |
+
"msg": (f"Dataset root contains no asset directories. Per "
|
| 907 |
+
f"the SimReady packaging spec, each asset lives in "
|
| 908 |
+
f"its own top-level directory."),
|
| 909 |
+
})
|
| 910 |
+
|
| 911 |
+
return issues
|
| 912 |
+
|
| 913 |
+
|
| 914 |
def discover_assets(
|
| 915 |
root: Path, exclude: Path | None = None,
|
| 916 |
) -> tuple[list[Path], list[dict]]:
|