Skip to content

ci(local): add --native so the long legs can run without the VM - #716

Merged
TinDang97 merged 3 commits into
mainfrom
feat/ci-local-native
Aug 25, 2026
Merged

ci(local): add --native so the long legs can run without the VM#716
TinDang97 merged 3 commits into
mainfrom
feat/ci-local-native

Conversation

@TinDang97

Copy link
Copy Markdown
Collaborator

Why

The merge bar's two full suites and the client-compat harness only exist in the moon-dev VM.
When that VM is unavailable — it has been destroyed mid-run more than once, and did so again this
week — the long legs cannot run at all. There was also no supported way to keep a long testing
phase on one machine.

What

scripts/ci-local.sh --native runs on the macOS host: the same lint gates, the monoio suite,
the tokio suite, a release build, and the client-compat harness against a host
redis-server (pinned with --moon-bin to the binary built in that run — find_moon_binary()'s
fallback has graded a stale quarantined binary before).

What it deliberately does not claim

macOS drives monoio on kqueue, so a native run does not exercise the shipped Linux
io_uring path, nor cfg(target_os = "linux") code (O_DIRECT, spin governor, migration), nor
Windows, nor the MSRV pin. The mode ends by printing exactly that instead of a bare
RESULT: PASS — a local gate that quietly implies full coverage is worse than no gate.

For the same reason a missing redis-server refuses with exit 2 rather than skipping: a
differential harness with no oracle proves nothing, and a green skip would be a lie.

  RESULT: PASS (native/macOS) — this did NOT cover:
    · io_uring   — monoio ran on kqueue here; the shipped Linux
                   path is io_uring and is untested by this run
    · Linux-only cfg code (O_DIRECT, spin governor, migration)
    · Windows, and the MSRV 1.94 toolchain pin

Tests

Four new cases in scripts/test-ci-local-preflight.sh (25 passed, 0 failed):

case asserts
no redis-server oracle refuses, not skips exit 2 + refusal text
a native pass names the io_uring gap exit 0 + "did NOT cover"
a failing native step still exits 1 exit 1 + RESULT: FAIL
unknown flag exits 2 usage still rejects

They work by rewriting run_step into a recorder, so the real branching executes in ~1s without
running the 20-minute steps.

Both new guards were mutation-checked, and each mutation fails its test:

mutation result
delete the redis-server refusal got exit=0 want=2
hoist the native summary above the FAILED check got exit=0 want=1 ✗ — i.e. every failing native run would have exited 0

No new shellcheck findings vs main (diffed the reports).

Evidence it works end to end

The first full --native run is what surfaced the mq_integration flake fixed in #715.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 5 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c308b8fb-e0d5-475d-9122-18c96be2008e

📥 Commits

Reviewing files that changed from the base of the PR and between ec506eb and b48c562.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • CLAUDE.md
  • scripts/ci-local.sh
  • scripts/test-ci-local-preflight.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

The merge bar's two full suites and the client-compat harness only exist
in the moon-dev VM. When that VM is unavailable — it has been destroyed
mid-run more than once — the long legs cannot run at all, and a testing
phase that wants to stay on one machine has no supported way to do it.

--native runs, on the macOS host: the same lint gates, the monoio suite,
the tokio suite, a release build, and the client-compat harness against a
host redis-server (pinned via --moon-bin to the binary built in that run,
because find_moon_binary()'s fallback has graded a stale quarantined
binary before).

It is deliberately not sold as equivalent. macOS drives monoio on kqueue,
so the SHIPPED Linux io_uring path is untested by a native run, as are
cfg(target_os = "linux") code, Windows, and the MSRV pin. The mode ends by
naming those gaps instead of printing a bare "RESULT: PASS" — a local gate
that quietly implies full coverage is worse than no gate. For the same
reason a missing redis-server oracle REFUSES with exit 2 rather than
skipping: a differential harness with no oracle proves nothing.

Tests: four cases in scripts/test-ci-local-preflight.sh cover the refusal,
the gap-naming pass, a failing native step still exiting 1, and an unknown
flag still exiting 2. Both new guards were mutation-checked — deleting the
oracle refusal, and hoisting the native summary above the failure check
(which would make every failing native run exit 0) — and each mutation
fails its test.

author: Tin Dang
The Lint job caught a real bug in the test added one commit ago:
`mktemp -t cilocal-dry` is a BSD spelling. GNU mktemp requires X's in the
template and fails, so on the Ubuntu runner $DRY was empty and the
oracle-refusal case got exit 127 instead of the exit 2 it asserts —
green on the machine it was written on, red everywhere else.

Use the explicit `mktemp -d "${TMPDIR:-/tmp}/...XXXXXX"` form, which is
correct on both, and put the dry script inside that directory.

While here: the two "oracle present" cases only need `command -v
redis-server` to succeed — the dry run never executes it — so they now
run against a stub on PATH instead of skipping on any machine without
redis installed. They were both skipped on the runner, and a guard test
that skips is a guard nobody is testing. The absence case still uses a
real PATH without redis, and skips (loudly) rather than asserting this
machine's /usr/bin layout if redis-server happens to live there.

Both mutations still fail their tests after the refactor: deleting the
oracle refusal (exit 0, want 2) and hoisting the native summary above the
FAILED check (exit 0, want 1).

author: Tin Dang
The Lint job failed again, and the reason was not the assertion it looked
like: ci-local.sh hardcodes REPO=/Volumes/Games/tindang-repo/moon and
`cd "$REPO" || exit 2` at the top, so on a hosted runner EVERY invocation
exits 2 before any gate runs. The oracle-refusal test asserts exit 2, saw
exit 2, and still failed on the message — while the two tests that expect
0 and 1 failed outright. An exit code that means "this machine is not the
author's laptop" is indistinguishable from a gate's verdict.

The hardcode stays as the default — a relative path has resolved to the
OLD /Users/tindang/workspaces/tind-repo/moon checkout before, and that
trap is worth keeping — but CI_LOCAL_REPO now overrides it, and the test
harness passes the current checkout.

Reproduced the runner condition locally by pointing the default at a
nonexistent path: all four cases still pass, where before the fix they
could not have. Both guard mutations still fail their tests under the new
plumbing (oracle refusal deleted -> exit 0 want 2; native summary hoisted
above the FAILED check -> exit 0 want 1).

author: Tin Dang
@TinDang97
TinDang97 force-pushed the feat/ci-local-native branch from 71bb8ff to b48c562 Compare August 25, 2026 14:42
@TinDang97

Copy link
Copy Markdown
Collaborator Author

Merge-bar record

This PR is the mode that exists because the bar cannot be met the usual way right now:

$ orb list
(empty — the moon-dev VM is gone)
$ gh api repos/pilotspace/moon/actions/runners
moon-dev-vm offline busy=false

Check (monoio) and Client compat are self-hosted on that runner and sit queued forever on
any dispatch. All hosted PR checks are green, and the Lint job runs the four new native-mode
cases for real on the Ubuntu runner — verified in the job log, not inferred:

── ci-local.sh --native control flow ──
  ok    no redis-server oracle refuses, not skips      exit=2
  ok    a native pass names the io_uring gap           exit=0
  ok    a failing native step still exits 1            exit=1
  ok    unknown flag exits 2                           exit=2
  24 passed, 0 failed

That matters because the first two attempts at this file were green here and red there — once on
mktemp -t (BSD-only spelling) and once because ci-local.sh cds to a hardcoded macOS path and
exited 2 before any gate ran, which my exit-2 assertion happily read as its own verdict.

The mode itself was exercised end to end on a branch merging this with #715 and #717: exit 0,
fingerprint valid, monoio 6055/6055 (kqueue), tokio 5266/5266, client-compat strict + INFO green
against redis 8.6.1.

Standing gap, printed by the mode on every run rather than left to memory: no io_uring
coverage
. That returns when moon-dev is rebuilt.

@TinDang97
TinDang97 merged commit ab60b9a into main Aug 25, 2026
10 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