Skip to content

feat(harbor): fetch package-store datasets by content hash (M9) - #3743

Merged
adil-a merged 1 commit into
adasif/harbor-m8-tb21from
adasif/harbor-m9-package-store
Oct 21, 2026
Merged

adil-a merged 1 commit into
adasif/harbor-m8-tb21from
adasif/harbor-m9-package-store

Conversation

@adil-a

@adil-a adil-a commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

M9 of the Harbor tasks RFC (GitLab MR 340, 354, 367): datasets that live in Harbor's package store. Stacked on #3730.

  • harbor:<org>/<name>[@<tag> | @sha256:<digest>]. nemo_gym/tasks/harbor/package_store.py resolves the dataset version through Harbor's public PostgREST API (tag or digest), lists its task packages, downloads each archive, checks it against Gym's task digest (the same record format Harbor publishes) and writes manifest.toml. A folder whose digest already matches is kept, so a rerun completes a partial fetch. harbor:terminal-bench/terminal-bench@4.0.0 materializes all 66 Terminal Bench 4 tasks into datasets/terminal-bench-4.0.0/.
  • Task model. The Harbor 1.4 fields those packages use: [[verifier.collect]] hooks and typed artifacts entries (string or table, with host_path). Artifact sources and destinations may not contain .., and a destination must be relative.
  • CLI. The taskset name is the fetched folder's name for both registry and package-store references.

Review fixes (2026-10-04)

  • Task names from registry.json and from package-store replies pass validate_task_name before they become path components. Empty names, ., .., anything containing .., a path separator or NUL are refused. Characters real Harbor task names use, such as $, are accepted.
  • contained_path checks that a folder resolves strictly inside the dataset folder before a fetch removes or replaces it. A spoofed name or a symlink cannot make a fetch touch files outside the dataset.
  • A task folder whose digest differs from the store (edited locally, or republished) now stops the prepare step with both digests named instead of being replaced silently. The error says to keep the local copy, or delete the folder (or move it aside) and run again, which fetches the store's copy. There is no flag for this: discarding local edits stays a step the user takes by hand.

Validation

  • pytest tests/unit_tests/test_harbor_package_store.py tests/unit_tests/test_harbor_tasks.py tests/unit_tests/test_cli_main.py environment_servers/harbor/tests: pass. TestPackageStore (tests/unit_tests/test_harbor_package_store.py) fakes the store at the HTTP layer: tag and digest resolution, the archive check against the published hash and the manifest, a rerun without downloads, the exclusion-free archive hash next to the folder digest (a package that ships a name the folder digest skips, with and without run noise), a spoofed package name refused before any filesystem use, nothing deleted outside the dataset folder, linked dataset folders and manifests refused, a folder without task.toml left alone, duplicate task names refused before writing, an edited folder stopping the fetch with both digests named, a deleted folder fetched again, the [dataset] identity check (a folder fetched for another package, a moved latest refused with both hashes), two concurrent fetches keeping the completed copy and a failed rename leaving no partial destination, an unreadable archive reported as a one-line error by gym eval run and gym dataset validate, an unreadable manifest rewritten only after the task checks, folder naming and fetch_ref dispatch. TestTaskNames covers refused and accepted names, and a registry entry with an unsafe name is refused. TestSeparateVerifierFields covers collect hooks, artifacts and artifact path containment.
  • There is no --force flag. A folder whose digest differs from the store stops the fetch, and the documented recovery is to keep the local copy, or delete the folder (or move it aside) and run again, which fetches the store's copy.
  • Real fetch (before the rebase): all 66 terminal-bench/terminal-bench@4.0.0 packages downloaded and every digest matched the store's content hash.
  • pre-commit run --files <changed files> clean.

Rollouts

The 52 CPU tasks of the fetched dataset ran through gym dataset validate on OpenSandbox Cell-3 in the M12 PR of this stack (#3746). Those runs predate the rebase below.

Rebased onto main

Rebased onto main 128eab4 (2026-10-04).

Compatibility and benchmark impact

Registry references and local folders are unchanged, apart from the task-name check on registry.json entries. Package-store access uses Harbor's public read-only key. No credentials are needed.

Checklist

  • I have read the contributing guidelines.
  • The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs.
  • Tests added or updated and pass locally, or N/A for docs-only / non-code changes (so CI unit/server checks pass when applicable).
  • Documentation added or updated, or N/A with justification.
  • Pre-commit checks pass locally (pre-commit run --all-files) (so CI lint/format checks pass).
  • New source files include the required Apache-2.0 SPDX header.
  • All commits have DCO sign-off (git commit -s) (so the DCO check passes).

🤖 Generated with Claude Code

@copy-pr-bot

copy-pr-bot Bot commented Sep 29, 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.

@adil-a
adil-a added this pull request to stack #3733 September 29, 2026 01:01
@adil-a adil-a changed the title feat(harbor): fetch package-store datasets by content hash feat(harbor): fetch package-store datasets by content hash (M9) Sep 29, 2026
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from 1c6394b to b22e0e6 Compare September 30, 2026 03:48
@adil-a
adil-a removed this pull request from stack #3733 September 30, 2026 03:50
@adil-a
adil-a added this pull request to stack #3806 September 30, 2026 03:51
@adil-a
adil-a removed this pull request from stack #3806 September 30, 2026 04:12
@adil-a
adil-a added this pull request to stack #3808 September 30, 2026 04:12
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from b22e0e6 to 00c97bf Compare October 4, 2026 23:19
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from 00c97bf to 3cf1d97 Compare October 9, 2026 20:08
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from 3cf1d97 to 2bdcada Compare October 9, 2026 20:20

@yuhezhang-ai yuhezhang-ai 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.

Before merging, please address the four cases below involving protection of local edits, dataset cache identity, duplicate task destinations, and compatibility with Harbor's published file hashes. Each has a local reproduction; they can erase local work, change the requested task set, or reject an intact package. The CLI-identifier and concurrent-fetch comments are nonblocking follow-ups.

Reviewed the M9 increment against adasif/harbor-m8-tb21. Focused tests and reproductions ran on 00c97bf4; after the rebase, I verified both M9 patches and the finding locations are unchanged at 2bdcada5. The rebased tree was not retested, and no live-store fetch or model rollout was performed during this review.

Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
Comment thread nemo_gym/tasks/harbor/cli.py Resolved
Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
@adil-a
adil-a removed this pull request from stack #3808 October 14, 2026 00:54
@adil-a
adil-a added this pull request to stack #4583 October 14, 2026 00:55
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from 2bdcada to f716c1e Compare October 14, 2026 01:06
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch 2 times, most recently from c1fe3bc to b93dbef Compare October 14, 2026 15:02
@adil-a
adil-a force-pushed the adasif/harbor-m9-package-store branch from b93dbef to 7889adc Compare October 14, 2026 16:29
@adil-a
adil-a marked this pull request as ready for review October 14, 2026 16:49
@adil-a

adil-a commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test bdbe918

@yuhezhang-ai yuhezhang-ai 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.

Thanks for the fixes. I've verified and resolved the folder-preservation, duplicate-name, and symlink threads.

The remaining threads still need attention: dataset cache identity, published-file hashing, concurrent fetches, and CLI errors. On bdbe9182, a fetch finishing just after the new check can still make preparation omit a task, and run_target still lacks the ValueError catch mentioned in the reply.

@yuhezhang-ai

Copy link
Copy Markdown
Contributor

Nonblocking: update the validation section. It still lists --force replacement, flag-default tests, and forwarding force through prepare. At bdbe9182, those commands have no --force flag and those tests are absent. Please refresh the validation list to match the current branch and the documented move/delete recovery flow.

@adil-a

adil-a commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 5b4eb8b

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

@adil-a

adil-a commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 9d489d6

@adil-a

adil-a commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 06cb0da

@adil-a

adil-a commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 92a5e8f

@adil-a

adil-a commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Status at the new head 92a5e8f. The four remaining threads each have the fix inline:

  • dataset cache identity: folder names stay readable and the identity lives in manifest.toml's [dataset] table (package, reference, resolved hash), read back before any task is touched, so alice/evals and bob/evals cannot share a folder and a moved latest is refused with both hashes (_check_recorded_identity).
  • published-file hashing: the archive is checked with an exclusion-free archive_hash, the same record format over every file, so an intact package always matches the store, while Gym's folder digest with exclusions is what reruns compare against, recorded in the manifest.
  • concurrent fetches: promotion is one os.rename of a sibling staging folder, a rename refused by a peer's complete copy keeps that copy, and a failed rename leaves no partial destination (test_peer_copy_promoted_after_check_is_kept, test_failed_rename_leaves_no_partial_destination).
  • CLI errors: a bad archive body becomes a PackageStoreError, and run_target catches ValueError around preparation, so eval run and dataset validate print one parser error line.

You are right that the validation section was stale. I am replacing it in the description to match the branch: there is no --force flag anywhere, the recovery flow is to keep the local copy or delete the folder (or move it aside) and fetch again, and the test list names what tests/unit_tests/test_harbor_package_store.py actually holds.

@yuhezhang-ai yuhezhang-ai 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.

Thanks for the fixes. The fixed threads are resolved. Dataset cache identity still needs addressing before merge. Added one new nonblocking finding below for interrupted HTTP downloads.

Comment thread nemo_gym/tasks/harbor/package_store.py Resolved
@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 58723ba

@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test aaed18f

@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 0306fc7

yuhezhang-ai
yuhezhang-ai previously approved these changes Oct 21, 2026

@yuhezhang-ai yuhezhang-ai 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.

Thanks for the fixes. Approved for the planned Harbor stack, including #4664 (5df89d45), where I verified the remaining cache-identity fix. The interrupted-download error is fixed in M9.

Focused tests and reproductions pass, as do the main CI checks. The optional, nonblocking harness-conformance check remains failing.

@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test d5ff29a

ffrujeri
ffrujeri previously approved these changes Oct 21, 2026

@ffrujeri ffrujeri 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.

Approving d5ff29a9. The cache-identity fix now lives in M9 itself: fetch_package_dataset claims the folder through an exclusive manifest.toml create before the first download, records each task as it lands, and refuses an unreadable or foreign manifest. An interrupted fetch can no longer leave a folder another dataset reuses. The interrupted-download error and the other threads are fixed too. Package-store, Harbor, validation, CLI, config, sandbox, sessions and rollout-collection suites pass locally at this head (1514 passed, 13 skipped); CI was still running at approval time.

@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test bcee436

yuhezhang-ai
yuhezhang-ai previously approved these changes Oct 21, 2026

@yuhezhang-ai yuhezhang-ai 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.

Rechecked after the rebase: the reviewed M9 changes are unchanged. Approved for the planned Harbor stack, including #4664 (66bcacd0), which contains the verified remaining cache-recovery fixes. Main CI passes; the optional harness-conformance checks remain nonblocking.

M9 of the Harbor tasks RFC. `harbor:<org>/<name>[@<tag> | @sha256:<digest>]` resolves a dataset
in Harbor's package store, downloads every task package, checks each against Gym's task digest
(the same record format Harbor publishes) and writes `manifest.toml` next to the tasks. Terminal
Bench 4 lives there: `harbor:terminal-bench/terminal-bench@4.0.0` materializes all 66 tasks into
`datasets/terminal-bench-4.0.0/`.

The task model gains the Harbor 1.4 fields those packages use: `[[verifier.collect]]` hooks and
typed `artifacts` entries. Names from the package store and the registry are checked before they
become path components, and nothing is removed outside the dataset folder. A task folder whose
digest differs from the store stops prepare with both digests named; `--force` refetches it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Adil Asif <adasif@nvidia.com>
@adil-a

adil-a commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 1bc58a7

@ffrujeri ffrujeri 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.

Re-approving 1bc58a73 after the restack. git range-diff shows the patch is identical to the d5ff29a9 I approved.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/39680942488

This branch was previously deployed

1 inactive deployment
public — 1bc58a73 Deployed Oct 21, 2026 by copy-pr-bot[bot] via release / finalize / notify #6385
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:data Datasets, preparation, task formats, and materialization complexity:medium Single-domain change with interacting parts or a moderate review surface feature New capabilities, enhancements, or enablement work waiting-on-customer Waiting on the original author to respond

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants