Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0969441
Add Puzzletron v2 GPU quality baseline
j-rausch Aug 11, 2026
7fbe3ee
Preserve authored Puzzletron stage identity
j-rausch Aug 11, 2026
4ed2e74
Fix Puzzletron worker semantic validation
j-rausch Aug 11, 2026
dfb1083
Fix Puzzletron GPU baseline regressions
j-rausch Aug 11, 2026
3429426
Fix Puzzletron GPU artifact assertion
j-rausch Aug 11, 2026
c51e989
Fix Puzzletron CI style checks
j-rausch Aug 12, 2026
7f082eb
Fix Puzzletron MIP solution assertion
j-rausch Aug 12, 2026
12de313
Fix Puzzletron checkpoint reload probe
j-rausch Aug 12, 2026
b219607
Exercise full Puzzletron GPU campaign lifecycle
j-rausch Aug 12, 2026
26e0fa4
Fix composite stage manifest validation
j-rausch Aug 12, 2026
79145c6
Forward overrides to post-MIP aggregation
j-rausch Aug 12, 2026
5c9c435
Preserve heterogeneous KD checkpoint metadata
j-rausch Aug 12, 2026
baceb70
Format Puzzletron GPU test imports
j-rausch Aug 12, 2026
2c43fbc
Harden Puzzletron GPU baseline recovery
j-rausch Aug 12, 2026
a667d9d
Avoid Puzzletron post-MIP import cycle
j-rausch Aug 12, 2026
c486159
Format Puzzletron GPU lifecycle test
j-rausch Aug 12, 2026
8baa662
Fix Puzzletron quality checks
j-rausch Aug 12, 2026
8c2ac0b
Fix Puzzletron changed-file typing
j-rausch Aug 12, 2026
f12abd1
Validate Puzzletron security policy inputs
j-rausch Aug 12, 2026
3e5dc6c
Use module-scope future stage imports
j-rausch Aug 12, 2026
630d69e
Harden Puzzletron recovery and policy handling
j-rausch Aug 12, 2026
10f02ec
Add non-interactive Puzzletron setup
j-rausch Aug 12, 2026
57c87e1
Fix Puzzletron post-MIP test import
j-rausch Aug 13, 2026
ba510fc
Fix non-interactive setup defaults
j-rausch Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions examples/puzzletron/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@ The defaults file is loaded only when passed explicitly and takes precedence
over the selected profile. To expose every per-section and nested setting, use
the advanced flow explicitly:

Automation can use the same setup entry point without answering prompts. The
defaults file must provide every required value that has no resolved default:

Comment on lines +88 to +90

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Describe resolved defaults accurately.

puzzletron_setup/v2/defaults.py resolves values from built-in, model-derived, preset, model-profile, and defaults-file layers. A required value can therefore lack a built-in default but still have a resolved default. Replace “no built-in default” with “no resolved default” or list the supported default layers.

Suggested wording
-Automation can use the same setup entry point without answering prompts. The
-defaults file must provide every required value that has no built-in default:
+Automation can use the same setup entry point without answering prompts. The
+defaults file must provide every required value that has no resolved default:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Automation can use the same setup entry point without answering prompts. The
defaults file must provide every required value that has no built-in default:
Automation can use the same setup entry point without answering prompts. The
defaults file must provide every required value that has no resolved default:
🤖 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 `@examples/puzzletron/README.md` around lines 88 - 90, Update the automation
setup description in the README to state that the defaults file must provide
every required value without a resolved default, rather than only values lacking
a built-in default. Align the wording with the layered resolution behavior
implemented by puzzletron_setup/v2/defaults.py.

```bash
python examples/puzzletron/puzzletron_setup_v2.py \
--defaults /path/to/setup-v2-defaults.yaml \
--campaign-dir /path/to/campaign \
--profile smoke \
--non-interactive
```

Non-interactive setup fails instead of guessing when a required answer has no
resolved default. It generates and validates the same smoke and production
bundles as the interactive wizard.

```bash
python examples/puzzletron/puzzletron_setup_v2.py --full
```
Expand Down Expand Up @@ -269,13 +284,15 @@ git -C "${AUTOMODEL_ROOT}" rev-parse HEAD
```

```bash
python - <<'PY'
PYTHONPATH="${MODEL_OPT_ROOT}" python - <<'PY'
import importlib.metadata as metadata
import json
import os

from packaging.version import Version

from examples.puzzletron.ci_environment import verify_installed_vcs_source
Comment thread
coderabbitai[bot] marked this conversation as resolved.

import aiperf
import lmms_eval
import modelopt
Expand Down Expand Up @@ -307,10 +324,17 @@ assert Version(metadata.version("torchvision")).release == Version(
ci_environment["torchvision"]
).release
assert transformers.__version__ == ci_environment["transformers"]
assert metadata.version("lmms-eval") == ci_environment["lmms_eval"]
assert Version(metadata.version("lmms-eval")).base_version == (
ci_environment["lmms_eval"]["base_version"]
)
assert Version(metadata.version("nemo-automodel")).base_version == (
ci_environment["nemo_automodel"]["base_version"]
)
for package, source in (
("lmms-eval", ci_environment["lmms_eval"]),
("nemo-automodel", ci_environment["nemo_automodel"]),
):
verify_installed_vcs_source(package, source)
assert torch.version.cuda == "12.9"
assert torch.cuda.is_available()
PY
Expand Down Expand Up @@ -492,6 +516,11 @@ The setup wizard can also add downstream evaluation for materialized campaign
candidates. See [post-MIP pipelines](docs/post_mip_pipeline.md) to configure it
or add it to an existing campaign.

Remote model code and AIPerf v0.11 online tokenizer resolution are disabled by
default. Enable remote code only for a trusted model source. The tokenizer
compatibility option permits the AIPerf child process to resolve its tokenizer
online even when the surrounding campaign is configured for offline loading.

### Legacy checked-in Nano campaign

The checked-in Nano experiment uses the legacy `zero_shot_evaluation`,
Expand Down
8 changes: 6 additions & 2 deletions examples/puzzletron/ci_environment.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
{
"schema_version": 1,
"scope": "puzzletron_v2_cpu_ci",
"scope": "puzzletron_v2_ci",
"python": "3.12",
"torch": "2.11.0",
"torchvision": "0.26.0",
"transformers": "5.8.1",
"lmms_eval": "0.7.0",
"lmms_eval": {
"base_version": "0.7.0",
"repository": "https://github.com/EvolvingLMMs-Lab/lmms-eval.git",
"commit": "15c32bfec165df13c269ddd3cda03b2ed9137825"
},
"nemo_automodel": {
"base_version": "0.5.0",
"repository": "https://github.com/Separius/Automodel.git",
Expand Down
68 changes: 68 additions & 0 deletions examples/puzzletron/ci_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Verification helpers for the pinned Puzzletron CI environment."""

from __future__ import annotations

import json
import subprocess
from importlib import metadata
from typing import Any
from urllib.parse import unquote, urlparse

__all__ = ["verify_installed_vcs_source"]


def _normalized_repository(url: object) -> str:
return str(url or "").removesuffix(".git").rstrip("/")


def _installed_vcs_source(package: str) -> tuple[str | None, str | None]:
payload = json.loads(metadata.distribution(package).read_text("direct_url.json") or "{}")
vcs_info = payload.get("vcs_info") or {}
if vcs_info.get("commit_id"):
return payload.get("url"), vcs_info["commit_id"]
if (payload.get("dir_info") or {}).get("editable") and str(payload.get("url", "")).startswith(
"file:"
):
root = unquote(urlparse(payload["url"]).path)
repository = subprocess.check_output(
["git", "-C", root, "remote", "get-url", "origin"], text=True
).strip()
commit = subprocess.check_output(
["git", "-C", root, "rev-parse", "HEAD"], text=True
).strip()
dirty = subprocess.check_output(
["git", "-C", root, "status", "--porcelain", "--untracked-files=all"],
text=True,
).strip()
if dirty:
raise RuntimeError(f"Pinned Puzzletron dependency {package!r} is dirty: {dirty}")
return repository, commit
return payload.get("url"), vcs_info.get("commit_id")


def verify_installed_vcs_source(package: str, expected: dict[str, Any]) -> None:
"""Require an installed VCS dependency to match its repository and commit."""

repository, commit = _installed_vcs_source(package)
expected_source = (_normalized_repository(expected["repository"]), expected["commit"])
actual_source = (_normalized_repository(repository), commit)
if actual_source != expected_source:
raise RuntimeError(
f"Pinned Puzzletron dependency {package!r} source mismatch: "
f"actual={actual_source!r}, expected={expected_source!r}"
)
28 changes: 26 additions & 2 deletions examples/puzzletron/distributed_eval/run_coordinator.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuo pipefail

: "${CAMPAIGN_DIR:?set CAMPAIGN_DIR}"
Expand Down Expand Up @@ -88,6 +103,11 @@ from pathlib import Path
import subprocess
import sys

from examples.puzzletron.finalize_replacement_scoring import (
finalization_marker_is_current,
write_finalization_marker,
)

(
completion_dir_text,
marker_name,
Expand All @@ -104,8 +124,12 @@ completion_dir.mkdir(parents=True, exist_ok=True)
with (completion_dir / ".finalize.lock").open("a+") as lock:
fcntl.flock(lock, fcntl.LOCK_EX)
finalized = completion_dir / "finalized"
if finalized.is_file():
root = Path(puzzle_dir)
root_summary = root / "artifacts" / "replacement_scoring" / "summary.json"
root_manifest = root / "manifests" / "replacement_scoring.json"
if finalization_marker_is_current(finalized, root_manifest, root_summary):
raise SystemExit(0)
finalized.unlink(missing_ok=True)
completed = tuple(completion_dir.glob("*.done"))
expected = int(expected_text)
if len(completed) < expected:
Expand All @@ -126,7 +150,7 @@ with (completion_dir / ".finalize.lock").open("a+") as lock:
],
check=True,
)
finalized.touch()
write_finalization_marker(finalized, root_manifest)
PY
else
"${PYTHON_BIN}" "${SCRIPT_DIR}/../finalize_replacement_scoring.py" \
Expand Down
24 changes: 17 additions & 7 deletions examples/puzzletron/distributed_eval/run_depth_pool.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuo pipefail

Expand All @@ -10,10 +22,12 @@ set -Eeuo pipefail
: "${WORKER_COUNT:?set WORKER_COUNT to the number of worker groups}"
: "${PUZZLETRON_GROUP_INDEX:=${PUZZLETRON_TASK_INDEX:-${SLURM_PROCID:-}}}"
: "${PUZZLETRON_GROUP_INDEX:?run this script as one orchestrator worker-group task}"
: "${PUZZLETRON_GROUP_RANK:=0}"

PYTHON_BIN="${PYTHON_BIN:-python}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
GROUP_INDEX="${PUZZLETRON_GROUP_INDEX}"
GROUP_RANK="${PUZZLETRON_GROUP_RANK}"
JOB_ID="${SLURM_JOB_ID:-local}"
WORKER_PREFIX="${JOB_ID}-depth-"
MANIFEST_PATH="${CAMPAIGN_DIR}/manifest.json"
Expand All @@ -38,7 +52,7 @@ cleanup() {
local rc=$?
trap - EXIT INT TERM
set +e
if [[ "${GROUP_INDEX}" == "0" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" ]]; then
drain_workers
fi
if [[ -n "${worker_pid}" ]] && kill -0 "${worker_pid}" 2>/dev/null; then
Expand All @@ -50,7 +64,7 @@ cleanup() {
trap cleanup EXIT INT TERM

# Rank 0 creates the shared campaign before any worker attempts to open it.
if [[ "${GROUP_INDEX}" == "0" && ! -f "${MANIFEST_PATH}" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" && ! -f "${MANIFEST_PATH}" ]]; then
CUDA_VISIBLE_DEVICES="" "${PYTHON_BIN}" \
-m modelopt.torch.puzzletron.distributed_eval.cli init \
--campaign-dir "${CAMPAIGN_DIR}" \
Expand All @@ -72,21 +86,17 @@ done

# Every scheduler task owns one GPU slice and starts one worker group. Multiple
# independent worker groups may share a node.
export NNODES=1
export NODE_RANK=0
export NPROC_PER_NODE="${NPROC_PER_NODE:-${WORLD_SIZE}}"
export WORKER_GROUP_INDEX="${GROUP_INDEX}"
export WORKER_ID="${WORKER_PREFIX}${GROUP_INDEX}"
export WORKER_HOST="${WORKER_HOST:-$(hostname -f)}"
export WORKER_PORT="${WORKER_PORT:-$((5010 + GROUP_INDEX))}"
export RDZV_ENDPOINT="127.0.0.1:$((29500 + GROUP_INDEX))"
export RDZV_ID="depth-${JOB_ID}-${GROUP_INDEX}"

bash "${SCRIPT_DIR}/run_worker.sh" &
worker_pid=$!

coordinator_rc=0
if [[ "${GROUP_INDEX}" == "0" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" ]]; then
# Do not start depth iteration zero until every resident model is ready.
CUDA_VISIBLE_DEVICES="" "${PYTHON_BIN}" - \
"${CAMPAIGN_DIR}" \
Expand Down
24 changes: 17 additions & 7 deletions examples/puzzletron/distributed_eval/run_replacement_pool.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuo pipefail

Expand All @@ -10,10 +22,12 @@ set -Eeuo pipefail
: "${WORKER_COUNT:?set WORKER_COUNT to the number of worker groups}"
: "${PUZZLETRON_GROUP_INDEX:=${PUZZLETRON_TASK_INDEX:-${SLURM_PROCID:-}}}"
: "${PUZZLETRON_GROUP_INDEX:?run this script as one orchestrator worker-group task}"
: "${PUZZLETRON_GROUP_RANK:=0}"

PYTHON_BIN="${PYTHON_BIN:-python}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
GROUP_INDEX="${PUZZLETRON_GROUP_INDEX}"
GROUP_RANK="${PUZZLETRON_GROUP_RANK}"
JOB_ID="${SLURM_JOB_ID:-local}"
WORKER_PREFIX="${JOB_ID}-replacement-"
MANIFEST_PATH="${CAMPAIGN_DIR}/manifest.json"
Expand All @@ -38,7 +52,7 @@ cleanup() {
local rc=$?
trap - EXIT INT TERM
set +e
if [[ "${GROUP_INDEX}" == "0" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" ]]; then
drain_workers
fi
if [[ -n "${worker_pid}" ]] && kill -0 "${worker_pid}" 2>/dev/null; then
Expand All @@ -49,7 +63,7 @@ cleanup() {
}
trap cleanup EXIT INT TERM

if [[ "${GROUP_INDEX}" == "0" && ! -f "${MANIFEST_PATH}" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" && ! -f "${MANIFEST_PATH}" ]]; then
CUDA_VISIBLE_DEVICES="" "${PYTHON_BIN}" \
-m modelopt.torch.puzzletron.distributed_eval.cli init \
--campaign-dir "${CAMPAIGN_DIR}" \
Expand All @@ -69,21 +83,17 @@ while [[ ! -f "${MANIFEST_PATH}" ]]; do
sleep 1
done

export NNODES=1
export NODE_RANK=0
export NPROC_PER_NODE="${NPROC_PER_NODE:-${WORLD_SIZE}}"
export WORKER_GROUP_INDEX="${GROUP_INDEX}"
export WORKER_ID="${WORKER_PREFIX}${GROUP_INDEX}"
export WORKER_HOST="${WORKER_HOST:-$(hostname -f)}"
export WORKER_PORT="${WORKER_PORT:-$((5010 + GROUP_INDEX))}"
export RDZV_ENDPOINT="127.0.0.1:$((29500 + GROUP_INDEX))"
export RDZV_ID="replacement-${JOB_ID}-${GROUP_INDEX}"

bash "${SCRIPT_DIR}/run_worker.sh" &
worker_pid=$!

coordinator_rc=0
if [[ "${GROUP_INDEX}" == "0" ]]; then
if [[ "${GROUP_INDEX}" == "0" && "${GROUP_RANK}" == "0" ]]; then
CUDA_VISIBLE_DEVICES="" "${PYTHON_BIN}" - \
"${CAMPAIGN_DIR}" \
"${WORKER_COUNT}" \
Expand Down
Loading
Loading