Skip to content

ci: publish the Linux packages like the macOS ones, tested on the GB10 - #81

Merged
IsuraManchanayake merged 2 commits into
mainfrom
ci/linux-packages-on-gb10
Oct 26, 2026
Merged

IsuraManchanayake merged 2 commits into
mainfrom
ci/linux-packages-on-gb10

Conversation

@IsuraManchanayake

@IsuraManchanayake IsuraManchanayake commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Linux is published the same way macOS is: every release uploads the Linux wheel and @basecompute/basert-linux-arm64-cuda alongside the macOS ones, and the Linux install tests run on the DGX Spark (GB10) that builds the CUDA engine.

Changes (publish.yml)

  • No more PUBLISH_LINUX. The plan's Linux switch, the registry checks' Linux-only lists, the build's --engines, the PyPI job's step that dropped the Linux wheel, and the npm job's engine list all go. The main npm package now always lists both engine packages as optional dependencies.
  • test-linux runs on [self-hosted, Linux, ARM64, gb10] instead of ubuntu-24.04-arm. GitHub's arm64 runners have no NVIDIA GPU or CUDA runtime, so that job could only check that the packages install and that the bindings point at the right file. On the GB10 it checks what test-macos checks:
    • pip install the Linux wheel, run basert --version, chat --help and serve --help, and load the engine through the Python bindings (baseRT_version_string);
    • npm install the main package with the Linux engine package, run basert, and load the engine through the Node bindings;
    • link a C program against each install, check its libbaseRT.so.0 resolves inside the package, and run it. That load pulls in the CUDA driver and cuBLAS, so a missing CUDA library fails here.
  • The job works under RUNNER_TEMP, because a self-hosted runner keeps its workspace between runs. It sets BASERT_SUPERFLUID_AUTO_INSTALL=0, so serve --help never installs superfluid on the shared machine.
  • Uploads and the package build stay on GitHub-hosted runners. npm trusted publishing doesn't support self-hosted runners, and nothing there needs a GPU.

Before merging

  • The engine licence covers Linux. It ships in every engine bundle as LICENSE, and until now it granted use on Apple Silicon only. The release that first publishes Linux must carry the new licence.
  • The GB10 runner is available to this repository (org runner group settings). Otherwise test-linux waits in the queue and every upload waits with it. As for the M4 Pro runner this repository already uses, keep fork pull request workflows requiring approval, since a fork PR could target a self-hosted runner. Checked from job records: the GB10 runners are org runners in the same group that already runs this repository's M4 Pro jobs, and fork PR workflows from all external contributors need approval.

Not verified

  • This job has never run: publish.yml runs only on a published release or by hand from main. Its first run is a dry run if PUBLISH_ENABLED is unset.
    • setup-python and setup-node have to install the pinned 3.14.9 and Node 24.21.0 into the GB10's tool cache. setup-python matches its Linux builds to Ubuntu 24.04, which DGX OS 7 is based on.
    • The engine's CUDA libraries have to resolve through the system's library paths, since the engine records no RUNPATH. The staging smoke test already loads the packaged engine on that machine.
  • Parsed and bash -n-checked every run block locally; no actionlint run.

The Linux wheel and npm engine package were built and tested on every
run but uploaded only with PUBLISH_LINUX, because the engine licence
granted use on Apple Silicon only. With Linux on NVIDIA GPUs licensed
too, every release uploads both platforms' packages, and the variable
goes.

test-linux moves from GitHub's ubuntu-24.04-arm, which has no NVIDIA GPU
or CUDA runtime, to the self-hosted GB10, and checks what test-macos
checks: the Python and Node bindings load the engine, and a program
linked against each install starts. It works under RUNNER_TEMP, since a
self-hosted runner keeps its workspace between runs, and forbids a
superfluid download on the shared machine.
@IsuraManchanayake
IsuraManchanayake marked this pull request as ready for review October 26, 2026 15:04

@IsuraManchanayake IsuraManchanayake left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review

Reviewed d9207f75ae75d142584b6a21544519cde570b739 together with basecompute/baseRT-internal#785. One P2 finding is attached inline: the new Linux Node smoke test reports success for library/binding failures.

The two-platform registry probes, package selection and upload lists are otherwise consistent. Local checks passed:

  • actionlint, all 18 publish shell blocks, and this tree's 17 packaging tests;
  • nine upload/dry-run decision cases and five registry cases, including a macOS-only partial publication correctly requiring both PyPI and npm work;
  • a default three-package npm build using matching cached 0.4.1 source/bundles as fixtures, confirming that the main package depends on both platform engines;
  • the normal Node probe against the installed macOS engine. Negative cases exposed the inline finding: missing/invalid libraries and an unresolved binding symbol also exited zero.

These local checks do not establish that the new GB10 job runs successfully: the actual 0.4.2 bundles, pinned tools on that runner, and release/publish workflow execution remain untested here. The updated licence must be in the first Linux release's bundles, and the GB10 runner must be enabled for this repository, as the PR already specifies.

Comment thread .github/workflows/publish.yml Outdated
Comment on lines +354 to +356
try { new BaseRTModel("/nonexistent.base"); } catch (e) {
if (/Cannot find libbaseRT/.test(e.message)) throw e;
console.log("engine loaded:", e.message.split("\n")[0]);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review — [P2] Accept only the expected missing-model failure

This treats every exception except Cannot find libbaseRT as a successful load. Koffi reports failed dynamic loads as Failed to load shared library: ... and missing API symbols as Cannot find function ..., so both are swallowed here. I ran this exact snippet with a missing library, an invalid library, and a binding requesting a missing symbol: every case printed engine loaded: and exited 0. A CUDA kernel-library initialization failure would also be accepted as an ordinary model-loading exception. The Python/C version probes do not cover Node binding setup or kernel initialization, so they do not close this gap. Require the specific expected file-not-found error for /nonexistent.base, rethrow every other error, and fail if construction unexpectedly succeeds; apply the same correction to the matching macOS probe too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1d2be94. Both Node probes, on macOS and the GB10, now:

  • accept only the engine's own refusal, Failed to load model: Failed to open model: /nonexistent.base (the backend-neutral loader produces it on Metal and CUDA alike);
  • rethrow every other error, a missing symbol included;
  • fail if construction succeeds.

I checked locally against packages built from the current source with the 0.4.1 engine. The real engine passes. An invalid libbaseRT.dylib now fails with koffi's Failed to load shared library.

The missing-library case showed a second gap. With the package's engine gone, the bindings fall back to an engine installed elsewhere; here that was an older 0.4.0 in ~/.basert, which then loaded.

  • npm: the linked-program step already fails in that case, since it links against the engine package's folder.
  • pip: that step links against whatever _find_library() returns, so a fallback engine passed everything. Both pip steps now assert that the path is the wheel's _engine/ again. The earlier Linux job had that check and the GB10 rewrite dropped it. On a shared runner, an installed engine would otherwise pass every check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review: Verified fixed in 1d2be94. The exact updated probe passes with the real macOS engine and now rejects all three previously reproduced failures (missing/invalid library and missing symbol). It also rejects simulated kernel-load errors and unexpected construction success. Confirmed the restored Python assertion rejects an actual fallback to an external engine. No further issue with this change.

The Node probe took any error but "Cannot find libbaseRT" as proof the
engine loaded, so koffi failing to load the library or one of its
symbols passed. It now accepts only the engine's own refusal of the
missing model ("Failed to load model: Failed to open model:
/nonexistent.base", the same on Metal and CUDA), rethrows anything
else, and fails if the model loads. Both install jobs run it.

The pip steps assert again that the bindings found the wheel's own
engine. Without it they fall back to an engine installed elsewhere, and
on the shared GB10 that one would pass every later check, the linked
program included.

@IsuraManchanayake IsuraManchanayake left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review — follow-up

Reviewed 1d2be944d5712c006f9ce87160ff7495928335d6, including the response to the previous review and the full current diff. The previous P2 is fixed; no additional actionable findings.

Both platform jobs now use identical Node probes that accept the expected missing-model error and reject other failures. The Python probes again reject an engine found outside the wheel.

Validation on the actual snippets extracted from this revision:

  • Eight Node cases passed: the real installed macOS engine and a controlled expected-error case succeeded; missing library, invalid library, unresolved binding symbol, simulated CUDA kernel-load failure, wrong missing-model error, and unexpected construction success all failed as intended.
  • The Python check accepted the bundled engine and rejected both an explicit external library and an actual fallback to a separate installation after removing the bundled engine from the fixture.
  • actionlint, all 18 shell blocks, and the diff whitespace check passed.

The real-engine checks used cached 0.4.1 macOS package fixtures; they do not validate a fresh 0.4.2 CUDA build. The new GB10 publish job, including its pinned tool setup and end-to-end package execution, remains unrun in this review. The registry/publication logic is unchanged from the previous reviewed revision.

@IsuraManchanayake
IsuraManchanayake merged commit b14b039 into main Oct 26, 2026
11 checks passed
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