Skip to content

Decision record: portable CLI and DCP distribution

Status: published in stable Core 1.0.0; legacy 1.0.0-rc.6 remains cache-dependent.

Updated: 2026-10-13. Original tool decision: 2026-06-25.

Problem and evidence

Aspire 13.4.2 embeds absolute build-cache DCP paths in AppHost metadata. A tool installed on a fresh machine cannot use those paths. The original same-machine packaging smoke was insufficient: its restored cache concealed the missing payload. The 2026-07-12 cache fallback improved relocated cache resolution but still required a matching Aspire restore. A clean 1.0.0-rc.6 installation measured on 2026-10-10 still failed before Docker; supplying matching tools through ASPIRE_DCP_PATH allowed topology execution. Neither result proves the published tool works standalone.

Decision

Keep the framework-dependent net8.0 global tool (PackAsTool, ToolCommandName: vouchfx) and self-contained multi-file archives/installers. Do not use single-file publishing: provider discovery needs Assembly.Location.

The tool contains the complete pinned Aspire 13.4.2 native tools trees for win-x64, glibc linux-x64, osx-x64 and osx-arm64. RID-specific publications contain only their own tree. The path is dcp/13.4.2/<rid>/tools/, beside the host assembly; manifests, tunnel helpers, licences and notices travel with the binaries. Private CLI-only package references avoid changing the provider SDK dependency or ABI. Ordinary source builds keep their build-host metadata without copying four large native trees into test output.

Resolution stays lazy inside inline Aspire startup. Priority is explicit ASPIRE_DCP_PATH, then the host-relative installed bundle, then legacy source/custom-runner metadata and cache fallback. An incomplete declared bundle fails without borrowing a warmed cache. Process architecture selects the RID, including x64 processes under ARM64 emulation. NuGet tool startup restores Unix execute bits only in its selected bundle; archives/installers preserve those bits during packaging.

Release acceptance

  • scripts/check_distribution.py checks the exact pinned version, RID set, executable platform, required files and native checksums. With --nuget-cache, it compares every shipped tools file with the exact restored upstream payload. The upstream osx-arm64 13.4.2 SBOM contains an incorrect NOTICE checksum; the original notice and manifest are preserved unchanged and checked against the restored package instead.
  • NuGet.org documents a 250 MB maximum. This repository enforces 250,000,000 bytes, a conservative decimal ceiling. Exceeding it requires a reviewed distribution strategy; required native files must not be removed.
  • The release workflow launches the candidate CLI and native DCP on all four advertised RIDs, verifies installer payloads, and runs a real Linux topology with an empty alternate cache, hidden build cache and fixtures outside the checkout. It requires executed passing scenarios and zero new containers/networks. Platform preflights alone do not prove Docker orchestration.

Validation commands

python -m unittest discover -s scripts/tests -p test_check_distribution.py -v
python scripts/check_distribution.py --package artifacts/nuget/vouchfx.VERSION.nupkg --nuget-cache "$HOME/.nuget/packages"
python scripts/check_distribution.py --publish artifacts/publish/linux-x64 --rid linux-x64 --nuget-cache "$HOME/.nuget/packages"

See installation and DCP troubleshooting.