From 8ca2736f68378121b231e2a9ed8bc0fa6e72c419 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Wed, 19 Aug 2026 15:51:50 -0400 Subject: [PATCH 1/3] docs(agents): CodeRabbit does not auto-review this repo, and its check never resolves Found while working #411. CodeRabbit's own comment gives the reason: this repository does not receive automatic reviews because it has fewer than 10 stars. The configuration from #316 is loaded and correct -- it reports the .coderabbit.yaml path, the ASSERTIVE profile and the Pro Plus plan -- so only the automatic trigger is missing. Two consequences, both of which have been operated wrongly since #316. The bot ceremony silently covers two bots rather than three. AGENTS.md credits CodeRabbit with catching a critical fast-forward defect (#358) and a use-after-free in the v2.3.5 libretro controller tables. None of that arrives unless a review is explicitly requested, so a PR reviewed by "all three bots" has in fact been reviewed by Copilot and Antigravity. `@coderabbitai review` requests one. And waiting for zero pending checks never terminates. The CodeRabbit context sits with a null status and a null conclusion indefinitely, so a healthy PR here reads as roughly 27 checks with exactly one permanently pending. The merge criterion is `CI success` = SUCCESS with every OTHER check complete -- never "nothing pending", and never a bare check count either, since a CONFLICTING PR also shows a short list because CI cannot run on it at all. --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index 0f9f6600..2040596d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -222,6 +222,7 @@ These cross-cutting decisions span multiple files. Reading individual chip docs - **There is ONE toolchain, `rust-toolchain.toml`'s `channel`, and no version literal anywhere in `.github/` — don't add one.** `.github/actions/rust-setup` parses the channel out of that file and fails closed if it can't, so a toolchain bump is a one-line edit there. Pass the composite's `toolchain:` input only to install something *deliberately* different from the project pin. **The resolver is table-scoped `awk` on purpose — do NOT "simplify" it back to a one-line `sed`.** Matching the first `channel = "..."` *anywhere* in the file (the first implementation, caught in review on PR #322) resolves `nightly` if any other table carries a `channel` key ahead of `[toolchain]` — silently installing the very toolchain this setup exists to keep out, while the step still reports success. `awk` rather than `tomllib` because the step runs on Windows and macOS runners too and Python ≥3.11 is not a safe assumption there; only double-quoted TOML strings are accepted, and anything else (missing table, single-quoted value, empty file) aborts the job rather than being guessed at. The old `stable` default was misleading rather than wrong: `rust-toolchain.toml` is a directory override that outranks the `rustup default` the action performs, so every job was already compiling on 1.96.0 (rustup logs `overridden by .../rust-toolchain.toml`) — `stable` just downloaded a second toolchain nothing used and made the workflows *read* as though they tested latest stable, which they never did. **Nightly is used in exactly one place, not a gate:** `cargo fuzz` (hard requirement — libFuzzer's sanitizer flags are nightly-only). If you think a CI job needs nightly, it doesn't. - **`rust-libretro 0.3.2` is unmaintained (no commit since 2023-02) and has a MinGW bug we work around.** It casts a keycode with `cfg(target_family = "windows")`, but C enum signedness follows the *ABI*: only **MSVC** gives plain enums `int` — under **MinGW** (`x86_64-pc-windows-gnu`, what the buildbot builds) bindgen emits `c_uint` and the crate fails `E0308`. `.cargo/config.toml`'s `[env] BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu = "--target=x86_64-pc-windows-msvc"` fixes it; the generated-bindings diff is 28 lines, all enum signedness. Don't "clean up" that env var without rebuilding for `x86_64-pc-windows-gnu`. - **CodeRabbit is now a 3rd automated PR review bot** (`.coderabbit.yaml`, added 2026-07-20 in PR #316), alongside gemini-code-assist and copilot-pull-request-reviewer — same reply-and-resolve-every-thread ceremony applies before any merge. Configured `profile: assertive` (not the "chill" default) and a `tools{}`/`path_instructions`/custom-checks set audited against this repo's actual file footprint, not guessed. `tone_instructions` has a hard 250-character schema limit that fails validation silently on the CodeRabbit side — after editing `.coderabbit.yaml`, verify with a `@coderabbitai configuration` PR comment and confirm every changed field shows `Source: Repository YAML (base)`. +- **CodeRabbit does NOT auto-review this repository, and its check never resolves.** Its own comment states the reason: *"This repository does not receive automatic reviews because it has fewer than 10 stars."* The configuration from #316 is loaded and correct (it reports `Path: .coderabbit.yaml`, `Review profile: ASSERTIVE`, `Plan: Pro Plus`) — only the automatic trigger is absent. Two consequences, both of which have been operated wrongly. **First, the ceremony below silently covers two bots, not three.** AGENTS.md credits CodeRabbit with catching a critical fast-forward defect (#358) and a use-after-free in the v2.3.5 libretro tables; none of that arrives unless a review is *requested*. Post `@coderabbitai review` on any PR whose diff warrants it. **Second, waiting for zero pending checks never terminates**: the `CodeRabbit` context sits with a null status and a null conclusion forever, so a healthy PR here reads as ~27 checks with exactly one permanently pending. The merge criterion is `CI success` = SUCCESS with every OTHER check complete — never "nothing pending", and never a bare check count, since a CONFLICTING PR also shows few checks (see the conflicting-PR trap in the memory index). - **The bot-comment ceremony must read the review BODIES, not just the resolvable threads.** CodeRabbit posts "Outside diff range" and other suppressed findings **inside the review body**, where they are invisible to a resolve-every-thread sweep — and Copilot does the same. This has now cost the project three times: issue #360 (an untested attestation path) reached `main` unaddressed; two findings of the same class on #357 were genuine defects, **one critical** (two threads producing frames during fast-forward under threaded display-sync, fixed in #358); and a **use-after-free** in the v2.3.5 libretro controller tables was caught only because the review body was read. A green "all threads resolved" is not evidence the review was addressed. Fetch the bodies explicitly — `gh pr view --json reviews --jq '.reviews[].body'` — and triage every finding in them before merging. - **lz4_flex 0.14+ requires the crate's own `alloc` feature explicitly** for `compress_prepend_size`/`decompress_size_prepended` (used by `rewind.rs`/`zwinder.rs`) — it split real no_std support into an `alloc`-vs-`std` distinction that didn't exist in 0.13. A `cargo build --workspace` will NOT catch a missing `alloc` feature here because `rustynes-core`'s own default-on `std` feature implies it via cargo's feature unification; only a standalone `cargo build -p rustynes-core --target thumbv7em-none-eabihf --no-default-features` (the exact CI `no_std build` job) will. Run that command locally before pushing any bump that touches this dependency. From 0aba85b68e07f1b0953769e43785565c2f3bf0d6 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Wed, 19 Aug 2026 17:54:29 -0400 Subject: [PATCH 2/3] docs(agents): state the conflicting-PR trap inline, and why removing the check is not the fix Two review findings, both correct in what they point at. Copilot: the parenthetical pointed at a "memory index" that does not exist in this repository -- it referenced a private note a contributor cannot see, which makes the sentence unactionable exactly where it is meant to be actionable. The trap is now stated inline: a CONFLICTING PR shows a short check list because GitHub cannot build a merge ref so CI never runs, and that is indistinguishable from a healthy PR whose jobs are still queuing. The merge criterion is spelled out as three conditions rather than as a cross-reference. Antigravity proposed removing the CodeRabbit check from branch protection instead of documenting it. Checked before answering: `main`'s ruleset requires exactly ONE context, `CI success` (`gh api repos/OWNER/REPO/rules/branches/main`), so the pending CodeRabbit context is not required and blocks nothing -- there is nothing to remove. Suppressing its status reporting would also lose the check on the PRs where a review IS triggered, which is the one occasion it carries information. Both facts are now in the entry so the next reader does not re-propose it. Also records what this session found the hard way: CodeRabbit rate-limits manual triggers per developer, so a batch of `@coderabbitai review` comments can produce no reviews at all while looking like it worked. --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2040596d..bfa55f7e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -222,7 +222,7 @@ These cross-cutting decisions span multiple files. Reading individual chip docs - **There is ONE toolchain, `rust-toolchain.toml`'s `channel`, and no version literal anywhere in `.github/` — don't add one.** `.github/actions/rust-setup` parses the channel out of that file and fails closed if it can't, so a toolchain bump is a one-line edit there. Pass the composite's `toolchain:` input only to install something *deliberately* different from the project pin. **The resolver is table-scoped `awk` on purpose — do NOT "simplify" it back to a one-line `sed`.** Matching the first `channel = "..."` *anywhere* in the file (the first implementation, caught in review on PR #322) resolves `nightly` if any other table carries a `channel` key ahead of `[toolchain]` — silently installing the very toolchain this setup exists to keep out, while the step still reports success. `awk` rather than `tomllib` because the step runs on Windows and macOS runners too and Python ≥3.11 is not a safe assumption there; only double-quoted TOML strings are accepted, and anything else (missing table, single-quoted value, empty file) aborts the job rather than being guessed at. The old `stable` default was misleading rather than wrong: `rust-toolchain.toml` is a directory override that outranks the `rustup default` the action performs, so every job was already compiling on 1.96.0 (rustup logs `overridden by .../rust-toolchain.toml`) — `stable` just downloaded a second toolchain nothing used and made the workflows *read* as though they tested latest stable, which they never did. **Nightly is used in exactly one place, not a gate:** `cargo fuzz` (hard requirement — libFuzzer's sanitizer flags are nightly-only). If you think a CI job needs nightly, it doesn't. - **`rust-libretro 0.3.2` is unmaintained (no commit since 2023-02) and has a MinGW bug we work around.** It casts a keycode with `cfg(target_family = "windows")`, but C enum signedness follows the *ABI*: only **MSVC** gives plain enums `int` — under **MinGW** (`x86_64-pc-windows-gnu`, what the buildbot builds) bindgen emits `c_uint` and the crate fails `E0308`. `.cargo/config.toml`'s `[env] BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu = "--target=x86_64-pc-windows-msvc"` fixes it; the generated-bindings diff is 28 lines, all enum signedness. Don't "clean up" that env var without rebuilding for `x86_64-pc-windows-gnu`. - **CodeRabbit is now a 3rd automated PR review bot** (`.coderabbit.yaml`, added 2026-07-20 in PR #316), alongside gemini-code-assist and copilot-pull-request-reviewer — same reply-and-resolve-every-thread ceremony applies before any merge. Configured `profile: assertive` (not the "chill" default) and a `tools{}`/`path_instructions`/custom-checks set audited against this repo's actual file footprint, not guessed. `tone_instructions` has a hard 250-character schema limit that fails validation silently on the CodeRabbit side — after editing `.coderabbit.yaml`, verify with a `@coderabbitai configuration` PR comment and confirm every changed field shows `Source: Repository YAML (base)`. -- **CodeRabbit does NOT auto-review this repository, and its check never resolves.** Its own comment states the reason: *"This repository does not receive automatic reviews because it has fewer than 10 stars."* The configuration from #316 is loaded and correct (it reports `Path: .coderabbit.yaml`, `Review profile: ASSERTIVE`, `Plan: Pro Plus`) — only the automatic trigger is absent. Two consequences, both of which have been operated wrongly. **First, the ceremony below silently covers two bots, not three.** AGENTS.md credits CodeRabbit with catching a critical fast-forward defect (#358) and a use-after-free in the v2.3.5 libretro tables; none of that arrives unless a review is *requested*. Post `@coderabbitai review` on any PR whose diff warrants it. **Second, waiting for zero pending checks never terminates**: the `CodeRabbit` context sits with a null status and a null conclusion forever, so a healthy PR here reads as ~27 checks with exactly one permanently pending. The merge criterion is `CI success` = SUCCESS with every OTHER check complete — never "nothing pending", and never a bare check count, since a CONFLICTING PR also shows few checks (see the conflicting-PR trap in the memory index). +- **CodeRabbit does NOT auto-review this repository, and its check never resolves.** Its own comment states the reason: *"This repository does not receive automatic reviews because it has fewer than 10 stars."* The configuration from #316 is loaded and correct (it reports `Path: .coderabbit.yaml`, `Review profile: ASSERTIVE`, `Plan: Pro Plus`) — only the automatic trigger is absent. Two consequences, both of which have been operated wrongly. **First, the ceremony below silently covers two bots, not three.** AGENTS.md credits CodeRabbit with catching a critical fast-forward defect (#358) and a use-after-free in the v2.3.5 libretro tables; none of that arrives unless a review is *requested*. Post `@coderabbitai review` on any PR whose diff warrants it. **Second, waiting for zero pending checks never terminates**: the `CodeRabbit` context sits with a null status and a null conclusion forever, so a healthy PR here reads as ~27 checks with exactly one permanently pending. The merge criterion is `CI success` = SUCCESS with every OTHER check complete — never "nothing pending", and never a bare check count either: a **CONFLICTING** PR also shows a short list, because GitHub cannot build a merge ref so CI never runs at all, and it is otherwise indistinguishable from a healthy PR whose jobs are still queuing. Gate on all three together — `CI success` green, every non-`CodeRabbit` check complete, and `mergeable == MERGEABLE`. **Also note the check is not required and removing it is not the fix**: `main`'s ruleset requires exactly one context, `CI success` (verified via `gh api repos/OWNER/REPO/rules/branches/main`), so the pending `CodeRabbit` context blocks nothing — and suppressing its status reporting would also lose the check on the PRs where a review IS triggered, which is the one time it carries information. And CodeRabbit rate-limits manual triggers per developer, so a batch of `@coderabbitai review` comments can silently produce no reviews at all. - **The bot-comment ceremony must read the review BODIES, not just the resolvable threads.** CodeRabbit posts "Outside diff range" and other suppressed findings **inside the review body**, where they are invisible to a resolve-every-thread sweep — and Copilot does the same. This has now cost the project three times: issue #360 (an untested attestation path) reached `main` unaddressed; two findings of the same class on #357 were genuine defects, **one critical** (two threads producing frames during fast-forward under threaded display-sync, fixed in #358); and a **use-after-free** in the v2.3.5 libretro controller tables was caught only because the review body was read. A green "all threads resolved" is not evidence the review was addressed. Fetch the bodies explicitly — `gh pr view --json reviews --jq '.reviews[].body'` — and triage every finding in them before merging. - **lz4_flex 0.14+ requires the crate's own `alloc` feature explicitly** for `compress_prepend_size`/`decompress_size_prepended` (used by `rewind.rs`/`zwinder.rs`) — it split real no_std support into an `alloc`-vs-`std` distinction that didn't exist in 0.13. A `cargo build --workspace` will NOT catch a missing `alloc` feature here because `rustynes-core`'s own default-on `std` feature implies it via cargo's feature unification; only a standalone `cargo build -p rustynes-core --target thumbv7em-none-eabihf --no-default-features` (the exact CI `no_std build` job) will. Run that command locally before pushing any bump that touches this dependency. From e4d8277d34a7776778d4b18e593670cddc8036ee Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Wed, 19 Aug 2026 18:23:39 -0400 Subject: [PATCH 3/3] docs(agents): correct the older bullet instead of contradicting it two lines later Review caught something this PR did to itself. The bullet directly above the new one has said, since #316, that CodeRabbit is a "3rd AUTOMATED PR review bot" whose ceremony "applies before any merge". The new bullet says it does not auto-review and that the ceremony covers two bots. Both were left standing, adjacent, so a reader arriving at the first one gets the false claim and the correction only if they keep going. That is the same defect class this release keeps finding -- prose asserting a behaviour the system does not have -- reproduced while documenting an instance of it. Corrected at the source: the #316 bullet now says CodeRabbit is CONFIGURED as a third bot, that the ceremony applies to its threads, and that it does not review automatically, pointing at the bullet with the detail. It also records what the old wording cost: "automated" plus "applies before any merge" read as a promise that its findings were arriving, and they were not. --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index bfa55f7e..977965bd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -221,7 +221,7 @@ These cross-cutting decisions span multiple files. Reading individual chip docs - **The libretro build image injects `-C ar` into EVERY Apple job, and it is a hard error from Rust 1.97 — a bomb armed against the next MSRV bump.** The image (not the `rust-apple.yml` template, which sets no `RUSTFLAGS` at all, and not our `.cargo/config.toml`) adds `-Car=,Clink-arg=-undefined,Clink-arg=dynamic_lookup,-rpath=` to osx-x64 / osx-arm64 / ios-arm64 / tvos-arm64. `-C ar` was a deprecated no-op for years and became a **hard error in 1.97** (bisected locally: 1.93.0-nightly / 1.96.0 / 1.96.1 warn; 1.97.1 and 1.99.0-nightly error). No job trips it today — all four Apple jobs are on the pinned 1.96.0 and merely log the warning. **The day `rust-toolchain.toml` moves to 1.97+, all four fail together** — the warning lives in that file, at the line someone would edit. Discarding the flags is behaviour-preserving, not a gamble: rustc splits `-C` at the FIRST `=`, so the whole comma-joined string is swallowed as the `ar` value and those link args have never reached the linker for *any* core (cargo prints it as one argv token), and two upstream Rust cores have green tvOS jobs on the same image with the same dead token. The override works without knowing where the image sets it because cargo takes rustflags from exactly one source, first match wins: `CARGO_ENCODED_RUSTFLAGS` → `RUSTFLAGS` → `target..rustflags` → `build.rustflags` (verified locally against a global `~/.cargo/config.toml` `build.rustflags`: `RUSTFLAGS=""` removes every injected `-C`, and empty means zero flags, not one empty argument). - **There is ONE toolchain, `rust-toolchain.toml`'s `channel`, and no version literal anywhere in `.github/` — don't add one.** `.github/actions/rust-setup` parses the channel out of that file and fails closed if it can't, so a toolchain bump is a one-line edit there. Pass the composite's `toolchain:` input only to install something *deliberately* different from the project pin. **The resolver is table-scoped `awk` on purpose — do NOT "simplify" it back to a one-line `sed`.** Matching the first `channel = "..."` *anywhere* in the file (the first implementation, caught in review on PR #322) resolves `nightly` if any other table carries a `channel` key ahead of `[toolchain]` — silently installing the very toolchain this setup exists to keep out, while the step still reports success. `awk` rather than `tomllib` because the step runs on Windows and macOS runners too and Python ≥3.11 is not a safe assumption there; only double-quoted TOML strings are accepted, and anything else (missing table, single-quoted value, empty file) aborts the job rather than being guessed at. The old `stable` default was misleading rather than wrong: `rust-toolchain.toml` is a directory override that outranks the `rustup default` the action performs, so every job was already compiling on 1.96.0 (rustup logs `overridden by .../rust-toolchain.toml`) — `stable` just downloaded a second toolchain nothing used and made the workflows *read* as though they tested latest stable, which they never did. **Nightly is used in exactly one place, not a gate:** `cargo fuzz` (hard requirement — libFuzzer's sanitizer flags are nightly-only). If you think a CI job needs nightly, it doesn't. - **`rust-libretro 0.3.2` is unmaintained (no commit since 2023-02) and has a MinGW bug we work around.** It casts a keycode with `cfg(target_family = "windows")`, but C enum signedness follows the *ABI*: only **MSVC** gives plain enums `int` — under **MinGW** (`x86_64-pc-windows-gnu`, what the buildbot builds) bindgen emits `c_uint` and the crate fails `E0308`. `.cargo/config.toml`'s `[env] BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu = "--target=x86_64-pc-windows-msvc"` fixes it; the generated-bindings diff is 28 lines, all enum signedness. Don't "clean up" that env var without rebuilding for `x86_64-pc-windows-gnu`. -- **CodeRabbit is now a 3rd automated PR review bot** (`.coderabbit.yaml`, added 2026-07-20 in PR #316), alongside gemini-code-assist and copilot-pull-request-reviewer — same reply-and-resolve-every-thread ceremony applies before any merge. Configured `profile: assertive` (not the "chill" default) and a `tools{}`/`path_instructions`/custom-checks set audited against this repo's actual file footprint, not guessed. `tone_instructions` has a hard 250-character schema limit that fails validation silently on the CodeRabbit side — after editing `.coderabbit.yaml`, verify with a `@coderabbitai configuration` PR comment and confirm every changed field shows `Source: Repository YAML (base)`. +- **CodeRabbit is configured as a 3rd PR review bot** (`.coderabbit.yaml`, added 2026-07-20 in PR #316), alongside gemini-code-assist and copilot-pull-request-reviewer — the reply-and-resolve-every-thread ceremony applies to its threads too. **It does NOT review automatically on this repository — see the next bullet.** This one said "automated" and "applies before any merge" from #316 until v2.3.9, which read as a promise that its findings were arriving; they were not. Configured `profile: assertive` (not the "chill" default) and a `tools{}`/`path_instructions`/custom-checks set audited against this repo's actual file footprint, not guessed. `tone_instructions` has a hard 250-character schema limit that fails validation silently on the CodeRabbit side — after editing `.coderabbit.yaml`, verify with a `@coderabbitai configuration` PR comment and confirm every changed field shows `Source: Repository YAML (base)`. - **CodeRabbit does NOT auto-review this repository, and its check never resolves.** Its own comment states the reason: *"This repository does not receive automatic reviews because it has fewer than 10 stars."* The configuration from #316 is loaded and correct (it reports `Path: .coderabbit.yaml`, `Review profile: ASSERTIVE`, `Plan: Pro Plus`) — only the automatic trigger is absent. Two consequences, both of which have been operated wrongly. **First, the ceremony below silently covers two bots, not three.** AGENTS.md credits CodeRabbit with catching a critical fast-forward defect (#358) and a use-after-free in the v2.3.5 libretro tables; none of that arrives unless a review is *requested*. Post `@coderabbitai review` on any PR whose diff warrants it. **Second, waiting for zero pending checks never terminates**: the `CodeRabbit` context sits with a null status and a null conclusion forever, so a healthy PR here reads as ~27 checks with exactly one permanently pending. The merge criterion is `CI success` = SUCCESS with every OTHER check complete — never "nothing pending", and never a bare check count either: a **CONFLICTING** PR also shows a short list, because GitHub cannot build a merge ref so CI never runs at all, and it is otherwise indistinguishable from a healthy PR whose jobs are still queuing. Gate on all three together — `CI success` green, every non-`CodeRabbit` check complete, and `mergeable == MERGEABLE`. **Also note the check is not required and removing it is not the fix**: `main`'s ruleset requires exactly one context, `CI success` (verified via `gh api repos/OWNER/REPO/rules/branches/main`), so the pending `CodeRabbit` context blocks nothing — and suppressing its status reporting would also lose the check on the PRs where a review IS triggered, which is the one time it carries information. And CodeRabbit rate-limits manual triggers per developer, so a batch of `@coderabbitai review` comments can silently produce no reviews at all. - **The bot-comment ceremony must read the review BODIES, not just the resolvable threads.** CodeRabbit posts "Outside diff range" and other suppressed findings **inside the review body**, where they are invisible to a resolve-every-thread sweep — and Copilot does the same. This has now cost the project three times: issue #360 (an untested attestation path) reached `main` unaddressed; two findings of the same class on #357 were genuine defects, **one critical** (two threads producing frames during fast-forward under threaded display-sync, fixed in #358); and a **use-after-free** in the v2.3.5 libretro controller tables was caught only because the review body was read. A green "all threads resolved" is not evidence the review was addressed. Fetch the bodies explicitly — `gh pr view --json reviews --jq '.reviews[].body'` — and triage every finding in them before merging. - **lz4_flex 0.14+ requires the crate's own `alloc` feature explicitly** for `compress_prepend_size`/`decompress_size_prepended` (used by `rewind.rs`/`zwinder.rs`) — it split real no_std support into an `alloc`-vs-`std` distinction that didn't exist in 0.13. A `cargo build --workspace` will NOT catch a missing `alloc` feature here because `rustynes-core`'s own default-on `std` feature implies it via cargo's feature unification; only a standalone `cargo build -p rustynes-core --target thumbv7em-none-eabihf --no-default-features` (the exact CI `no_std build` job) will. Run that command locally before pushing any bump that touches this dependency.