Skip to content

ci(macos): darwin testbed — the mini stops compiling - #779

Merged
norrietaylor merged 3 commits into
mainfrom
ci/n6-darwin-testbed
Jul 16, 2026
Merged

ci(macos): darwin testbed — the mini stops compiling#779
norrietaylor merged 3 commits into
mainfrom
ci/n6-darwin-testbed

Conversation

@norrietaylor

Copy link
Copy Markdown
Member

Implements N6 — the last ordered subtask of the CI refactor epic #687: all compilation moves off the Mac mini.

What changed

unit (GitHub-hosted arm64) is now the mac lane's build phase, mirroring the KVM lane's build-linuxtest-kvm split (#698):

  • Unit tier runs via cargo nextest run -p minvmd -p sessions (integration harnesses excluded — they're the hypervisor tier), with doctests split into their own step, core-tests style.
  • Builds minvmd and min (separate invocations — the feature-unification guard and its otool assert move here, next to the build they check).
  • Stages a mac-testbed artifact: bin/minvmd + bin/min + lib/libkrun.1.dylib in the shipped layout, with scripts/rewrite-macos-linkage.sh applied to minvmd (the script's own verification reds the PR on a broken ship layout), plus the minvmd+sessions nextest archive.

e2e (the mini) compiles nothing: toolchain, libkrun provisioning, and every cargo invocation are gone. It downloads the testbed, restores exec bits, codesigns minvmd with the hypervisor entitlement, then:

  • replays the kernel-less FFI smoke and the _integration harnesses from the archive (cargo-nextest ... --archive-file, auto-discovery filtersets unchanged);
  • runs the unified session e2e with the testbed bin/ on PATH.

Archive-extracted test binaries resolve @rpath/libkrun.1.dylib via DYLD_FALLBACK_LIBRARY_PATH pointing at the testbed lib/ — exported in-script, because SIP strips DYLD_* crossing protected shells, so a step-level env: entry may never reach the test processes. The testbed minvmd needs no such help: its rewritten @loader_path/../lib rpath finds the bundled dylib — meaning the e2e now boots the production linkage layout for real, replacing the old static rewrite-on-a-throwaway-copy check.

Why

  • One compile serves both tiers — the unit/e2e build divergence (hosted cargo test build + a second full build on the mini) collapses into the single hosted build.
  • The mini does hypervisor work only — a flake rerun replays just this test job, and the shared runner stops burning time on cargo.
  • Test what ships — the exact dylib and the exact bin/../lib layout users receive is what CI boots.

Also updates the docs/ci-strategy.md mapping note (the archive-replay pattern now lives in the KVM and macOS lanes, per §7's "build nothing on this machine"). The CONTRIBUTING.md contract table needs no change — harness auto-discovery by _integration suffix is untouched.

Validation

  • actionlint clean.
  • This PR touches ci-macos.yml + scripts/**-adjacent paths, so the changes filter runs the full lane against itself: the real proof is this PR's own ci-macos-success.
  • Note: the mini's first run simply stops using its persistent target/ dir; stale contents there are inert.

Refs: #687 (N6)

🤖 Generated with Claude Code

Mirror the KVM lane's build→test split on the mac lane (N6, podman
pattern). The GitHub-hosted `unit` job becomes the lane's build phase:
its unit tier moves to nextest (doctests split out, core-tests style),
it builds minvmd + min once, and stages a darwin testbed — the shipped
bin/../lib layout with the @rpath linkage rewrite applied to minvmd and
libkrun.1.dylib bundled — plus the minvmd+sessions nextest archive.

The mini's e2e job compiles nothing: no toolchain, no libkrun
provisioning, no cargo. It downloads the testbed, restores exec bits,
codesigns minvmd with the hypervisor entitlement, and replays the FFI
smoke + `_integration` harnesses from the archive. The archive binaries
resolve libkrun via an in-script DYLD_FALLBACK_LIBRARY_PATH (their
baked rpaths point at the build runner; SIP strips DYLD_* through
protected shells, so a step-level env: entry would not arrive); the
testbed minvmd resolves it through its own @loader_path/../lib rpath.

This collapses the unit/e2e build divergence (one compile serves both
tiers), boots the production @rpath layout for real — replacing the
static rewrite-on-a-copy check — and cuts a flake rerun of the e2e to
the test phase alone. The minimal-links-only-system-libraries guard
moves to the hosted job next to the build it checks.

Refs: #687

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7d94f79-e144-44c1-bde8-d8944a89b318

📥 Commits

Reviewing files that changed from the base of the PR and between ca23aeb and a1e16c3.

📒 Files selected for processing (3)
  • .github/workflows/ci-macos.yml
  • crates/minvmd/tests/krun_smoke_integration.rs
  • docs/ci-strategy.md

Comment @coderabbitai help to get the list of available commands.

norrietaylor and others added 2 commits July 15, 2026 18:44
The FFI smoke spawned its helper through the compile-time
CARGO_BIN_EXE_krun_smoke_child path, which only exists on the machine
that built it — replaying the nextest archive on the mini died with
NotFound. nextest ships the helper in the archive and publishes its
extracted location as NEXTEST_BIN_EXE_krun_smoke_child at runtime;
prefer that, falling back to the compile-time path for plain
`cargo test` on a dev box. Same relocation pattern as the harnesses'
MINVMD_BIN override.

Refs: #687

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scripts/minvmd-lifecycle.sh was written target-agnostic ("a macOS
testbed later" per its header) but only the KVM lane ran it. With the
darwin testbed the mini now has a prebuilt, codesigned minvmd on PATH,
so the mac lane gains the same supervised-daemon proof: run --detach →
status (Running) → stop → status (Stopped). Placed between the reap
and the CLI session e2e, mirroring the KVM lane; boot-daemon.log joins
the uploaded console logs. Requires jq on the mini (the script fails
fast with a clear error if absent).

Refs: #687

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@norrietaylor

Copy link
Copy Markdown
Member Author

Two updates after the first run's red e2e:

  1. Failure causekrun_smoke_bring_up spawns its helper via the compile-time CARGO_BIN_EXE_krun_smoke_child path, which only exists on the build runner; the archive replay on the mini hit NotFound. Fixed by preferring nextest's runtime NEXTEST_BIN_EXE_krun_smoke_child (the helper ships in the archive — the "1 non-test binary" in the extraction log), falling back to the compile-time path for plain cargo test. Same relocation pattern as the harnesses' MINVMD_BIN override from #698.

  2. Scope addition — the mac lane now runs scripts/minvmd-lifecycle.sh (run --detach → status → stop), which its header already earmarked for "a macOS testbed later". Placed reap → lifecycle → session e2e, mirroring the KVM lane.

⚠️ One prerequisite: the lifecycle script requires host jq on the mini (it fails fast with a clear ::error if absent). If the mini doesn't have it yet, a one-time brew install jq there is needed before this lane can go green.

🤖 Generated with Claude Code

@norrietaylor
norrietaylor merged commit 664c0ee into main Jul 16, 2026
28 checks passed
@norrietaylor
norrietaylor deleted the ci/n6-darwin-testbed branch July 16, 2026 02:21
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.

2 participants