Skip to content

feat: consume Rez package bundles as a runtime source - #1215

Open
loonghao wants to merge 9 commits into
mainfrom
agent/rez-bundle-provider
Open

loonghao wants to merge 9 commits into
mainfrom
agent/rez-bundle-provider

Conversation

@loonghao

Copy link
Copy Markdown
Collaborator

Summary

Consume immutable Rez package bundles as a runtime source, so a provider can
resolve a tool from a published bundle instead of a raw upstream archive.

The work is driven by the public vx-rez-adapter crate (pinned to =0.1.1)
rather than by shelling out to an external process.

What changed

Provider surface. A new @vx//stdlib:rez.star stdlib module exposes
rez_bundle_source(), which returns fetch_versions, download_url,
install_layout, and rez_bundle functions. It maps the host platform and
architecture onto a release asset triple, and reports unsupported targets with
the reason the recipe declares.

Activation. ManifestDrivenRuntime gains an optional Rez bundle bridge.
When a provider supplies a request, prepare_execution() resolves the unpacked
bundle repository through the adapter and locates the requested program on the
resolved PATH rather than the ambient one, so the bundle payload wins without
leaking host entries. The resolved environment reaches the executor through
prepare_execution, which now contributes environment variables and PATH
prepends in addition to an executable override.

Version discovery. A rez_bundle_versions transform reads either a
published release index or a GitHub releases listing, keeping only releases that
publish both an index and a bundle asset for the requested tool, and preserving
each release's publish date.

Offline reuse. An exact version already present in the local store resolves
without a remote index.

Rust provider. Routes download_url, install_layout, and fetch_versions
through its bundle when one is enabled, leaving the rustup contract untouched as
the fallback.

Testing

  • crates/vx-starlark/tests/rez_bundle_tests.rs — 13 tests covering platform
    selection, unsupported-target reasons, version discovery, and asset naming.
  • crates/vx-runtime/tests/rez_bundle_execution_tests.rs — an end-to-end
    activation test against a real bundle fixture, asserting the resolved program,
    the activated environment, and parent-environment inheritance.
  • cargo clippy --workspace --all-targets -- -D warnings is clean, and
    cargo fmt --check passes.

Notes

The rez-bundles feature gates the adapter dependency, so the default build is
unchanged.

@loonghao
loonghao force-pushed the agent/rez-bundle-provider branch from aaa6627 to 09350cf Compare October 10, 2026 22:10
Wire vx to the public vx-rez-adapter crate so providers can select an
immutable Rez bundle instead of a raw upstream archive.

Providers opt in by defining rez_bundle() in provider.star through the
rez_bundle_source stdlib helper, which maps the host platform and
architecture onto a release asset, reports unsupported targets with the
reason declared in the recipe, and emits the package requirements the
adapter needs.

Activation resolves the unpacked bundle repository through the adapter,
then locates the requested program on the resolved PATH rather than the
ambient one, so the bundle payload wins without leaking host entries.
The resolved environment and executable reach the executor through
prepare_execution, which now contributes environment variables and PATH
prepends in addition to an executable override.

An exact version already present in the local store resolves without a
remote index, keeping offline reuse of installed bundles working.
Finish wiring the Rez bundle source: register rez.star in the stdlib
module loader so providers can load it, and add the version transform
that reads either a published release index or a GitHub releases
listing, keeping only releases that publish both an index and a bundle
asset for the requested tool.

Route the Rust provider's download_url, install_layout, and
fetch_versions through its bundle when one is enabled, leaving the
rustup path untouched as the fallback.

Report an unsupported official target with the reason the recipe
declares instead of resolving to no URL, and update the loader module
count plus the provider test mocks accordingly.
A Rez bundle bridge is attached to every runtime built from a
provider.star, and most providers never opt in, so its presence said
nothing about how a runtime is installed. Treating it as installable
made bundled runtimes directly installable, which broke the FreeCAD
console runtime's "bundled and Windows-only" contract.

Restore the parent-owns-installation rule: a bundled runtime is never
directly installed regardless of any Rez bridge.

Also apply cargo fmt.
The runtime bridge asks every provider for a bundle, and rez_bundle()
derived `enabled` purely from platform support. With the Rust provider
declaring one, `vx cargo` tried to activate a bundle from a rustup
installation and failed during prepare with "unusable package path".

Add a `published` option to rez_bundle_source() so a provider can declare
its bundle metadata while keeping activation off until a release actually
exists, and set it for Rust, which has no published bundle yet.

Update the Rust provider test to assert the gated contract, and pin the
request shape activation will use once a release is published so flipping
the flag later is a one-line change with a known outcome.
execute_download_url() handled null, unsupported rez_bundle_asset,
github_smart_detect, and bare strings. A supported rez_bundle_asset is
an object, so it matched none of those and fell through to Ok(None),
discarding its url.

A provider opting into a published Rez source therefore reached the
installer with no URL: install_layout() returns only required_paths, so
the layout branch stays unused and the direct download branch receives
None, falling back to system strategies.

Return the asset url for a supported descriptor, and fail with a clear
error when one is missing instead of silently reporting no URL. The
unsupported branch is matched first, so the declared reason and the
published=False gate keep their behaviour.

Add bridge-level contract tests that resolve a supported target through
the public download_url_for_runtime() rather than the Starlark engine,
which is the path the green CI did not cover.
check computes the toolchain that will actually run, then ignores it in
two branches:

- Installed fell back to the configured version whenever detection and
  path extraction found nothing, so a repository pinned to 1.0.0 while
  1.99.0 ran reported installed = 1.0.0. The drift was invisible, and a
  numeric pin looked satisfied.
- The no-owner system-fallback branch reported only the detected
  version, which is absent in the same situation, leaving installed
  empty.

Both now prefer the already-resolved toolchain for Rust, so installed
reflects what will run. Non-Rust tools, the rustup-owned branch, status
and severity semantics are unchanged, and no extra rustc is spawned —
the value was already computed above the match.

The version choice is extracted so it can be asserted directly; the
end-to-end tests cannot force detection to fail on every machine.
The fixture set VX_HOME to a directory already named "store", but VxPaths
resolves the store as <VX_HOME>/store, so the directory it created was one
level off and the public check never saw it. The test therefore ran against
the real store and could pass on the unfixed code.

Point VX_HOME at an independent base and create <base>/store/rust/<pin>/bin,
which is the path common.rs checks, so the requirement really is Installed
with the pin as its detected version. Assert the natural command exit,
status, store path, required pin and installed version, and fail when the
real toolchain cannot be resolved instead of skipping.

The pin is derived to be numeric and unequal to the actual toolchain, so the
drift the assertion depends on is guaranteed on any machine.

With the production fix reverted this reproduces the CI failure exactly —
left "1.0.0", right "1.98.0", exit 101 — and passes with it in place.
@loonghao
loonghao force-pushed the agent/rez-bundle-provider branch from 0f56ca8 to d16292d Compare October 12, 2026 15:21
The offline short-circuit in resolve_version is the implementation of the
offline-reuse acceptance criterion, but nothing referenced it, so a
regression there would ship silently.

These tests make every network call fail, so a resolved version proves the
remote index was never fetched. They also pin the boundary: non-exact specs
and path-like specs must still consult the index even when the pinned form
is installed.

Verified by mutation: disabling the short-circuit fails exactly the four
positive offline cases and leaves the negative cases passing.

This branch has not been deployed

No deployments
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.

1 participant