Skip to content

docs: perry-runtime's tests must run single-threaded locally, as CI already does - #7791

Merged
proggeramlug merged 2 commits into
mainfrom
test/perry-runtime-single-threaded
Aug 10, 2026
Merged

docs: perry-runtime's tests must run single-threaded locally, as CI already does#7791
proggeramlug merged 2 commits into
mainfrom
test/perry-runtime-single-threaded

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What

CLAUDE.md documented cargo test --release --workspace … for local runs. That command does not pin RUST_TEST_THREADS, so it runs perry-runtime multi-threaded — the exact configuration every CI path deliberately avoids. This splits the documented command so perry-runtime runs RUST_TEST_THREADS=1, and records the hazard under "CI gates that surprise people".

Why — the investigation behind it

gc::tests::root_words::bare_address_in_shadow_slot_survives_a_real_collection was reported failing on a clean c2a96b638 with the box at load ~111, passing in isolation and passing three full-suite reruns on a lightly loaded box. It was handed to me as "either make it deterministic, or it's a real load-dependent GC bug — and if so that outranks everything."

It is not a GC bug. perry-runtime's tests share process-global side tables. test.yml has pinned RUST_TEST_THREADS=1 for this crate since #1444 (its comment: the default pool "races the GC/threading tests into intermittent SIGSEGV"), and gc::tests::global_sink_isolation's header records that ~180 readers still do not take the clearing lock, with #7672 converting them to per_test_global! one table at a time. The local command was the one place that still walked into it.

Evidence

Against 2e5bf4434, release, on a tree that includes #7317:

configuration runs result
full suite, --test-threads=16, load ~90 4 × 150 600/600 clean, 0 vacuous
full suite, --test-threads=64, load ~115 4 × 80 2 failures / 320

The two failures were proxy::tests::object_array_numeric_write_guard_requires_complete_uniform_proof and array::element_shape::matrix_tests::matrix_delete_revokes — neither is root_words. The failing test is simply whichever one loses the race.

The decisive detail is what they assert when they fail. Both are the crate's own vacuity guards:

  • fixture must start proven, or every verdict below is vacuous
  • one-field loops should publish one non-zero 16-bit lane

That is a test discovering its own precondition was destroyed by a concurrent thread — not a collector invariant being violated. A real GC bug would surface as a swept-while-live object, not as a fixture that never armed.

root_words itself did not fail once across:

  • 920 parallel full-suite runs (release + debug),
  • 1500 targeted root_words + global_sink_isolation pairings at --test-threads=16,
  • a 40-seed PERRY_GC_SCHEDULE_SEED sweep at rate 25% — it never appears among that sweep's failures.

Deliberately not done

No #[ignore], no retry wrapper. Both would hide which of the two possibilities this was. The fix is to stop documenting a configuration the repo already knows is unsupported.

Side note recorded in the changelog fragment

PERRY_GC_SCHEDULE_SEED is a whole-process env var and scripts/gc_schedule_fuzz.sh takes a compiled binary, not the unit-test suite. Setting it across cargo test fails 8 GC tests at every seed, several of which assert the unset behaviour outright (schedule::unset_is_inert_for_evacuation_policy). That is the tool used outside its contract, not a defect — written down so the next person doesn't re-derive it.

Validation

cargo fmt --all -- --check and scripts/check_file_size.sh both clean. Docs-only change; no code paths touched.

Summary by CodeRabbit

  • Documentation
    • Documented that runtime tests run single-threaded to avoid failures caused by shared process-wide test state.
    • Clarified local and CI test commands, including that no tests are skipped or retried.
    • Added guidance on garbage-collection scheduling controls and stress-test behavior.

@proggeramlug
proggeramlug force-pushed the test/perry-runtime-single-threaded branch from 15a5163 to 1d06cbf Compare August 10, 2026 18:27
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@proggeramlug, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

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

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 357469db-77cc-415e-a3e1-a08c156d4621

📥 Commits

Reviewing files that changed from the base of the PR and between 1d06cbf and 2365dfc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • CLAUDE.md
  • Cargo.toml
📝 Walkthrough

Walkthrough

The test instructions now run perry-runtime separately with RUST_TEST_THREADS=1, exclude it from workspace tests, and document the shared process-global state and seeded-schedule tooling constraints.

Changes

Runtime test isolation

Layer / File(s) Summary
Test command and guidance
CLAUDE.md, changelog.d/7791-perry-runtime-tests-single-threaded.md
The test commands isolate perry-runtime and run it single-threaded. Documentation records parallel-execution failures, test-harness evidence, and seeded-schedule tooling constraints.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 7365: The changes isolate perry-runtime tests and use RUST_TEST_THREADS=1 to prevent shared global-state interference.

Possibly related PRs

  • PerryTS/perry#7061: Adds the single-threaded test-runner configuration that this PR documents and enforces.
  • PerryTS/perry#7317: Introduces seeded GC schedule behavior documented by this PR.
  • PerryTS/perry#7020: Addresses related perry-runtime GC test behavior involving shared process-global state.

Suggested labels: tooling

Suggested reviewers: jdalton, thehypnoo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main documentation change: requiring single-threaded local perry-runtime tests.
Description check ✅ Passed The description clearly explains the change, investigation, evidence, rationale, scope, and validation, despite not using the template headings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/perry-runtime-single-threaded

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLAUDE.md`:
- Around line 85-86: Remove the added test commands and runtime guidance from
CLAUDE.md, including the content around the shown cargo test commands and the
related section near line 241. Keep CLAUDE.md limited to the permitted Current
Version update, or move the guidance to an approved documentation file if it
must be retained.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b9a8904-e50e-4dc0-806c-8e74aabd94c8

📥 Commits

Reviewing files that changed from the base of the PR and between db44b31 and 1d06cbf.

📒 Files selected for processing (2)
  • CLAUDE.md
  • changelog.d/7791-perry-runtime-tests-single-threaded.md

Comment thread CLAUDE.md
Comment on lines +85 to +86
RUST_TEST_THREADS=1 cargo test --release -p perry-runtime # MUST be single-threaded (see below)
cargo test --release --workspace --exclude perry-runtime \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CLAUDE.md line count and relevant lines =="
wc -l CLAUDE.md
sed -n '75,90p' CLAUDE.md
sed -n '235,245p' CLAUDE.md

echo
echo "== Check for current guideline in repository/config files =="
rg -n "supplied coding guideline|CLAUDE.md|Current Version|changes only|allowed documentation" -S .

Repository: PerryTS/perry

Length of output: 50372


Move CLAUDE.md guidance out of the change.

Coding guidelines allow CLAUDE.md to update only **Current Version:**. Lines 85-86 and 241 add test commands and runtime guidance instead, so get an approved exception or move this content to an allowed documentation file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` around lines 85 - 86, Remove the added test commands and runtime
guidance from CLAUDE.md, including the content around the shown cargo test
commands and the related section near line 241. Keep CLAUDE.md limited to the
permitted Current Version update, or move the guidance to an approved
documentation file if it must be retained.

Source: Coding guidelines

@proggeramlug
proggeramlug force-pushed the test/perry-runtime-single-threaded branch from 1d06cbf to 2603ebf Compare August 10, 2026 21:49
Ralph Küpper and others added 2 commits August 10, 2026 23:52
…lready does

`gc::tests::root_words::bare_address_in_shadow_slot_survives_a_real_collection`
was reported failing on a clean c2a96b6 at load ~111 and investigated as a
possible load-dependent GC bug. It is not one.

perry-runtime's tests share process-global side tables. test.yml has pinned
RUST_TEST_THREADS=1 for this crate since #1444; global_sink_isolation's header
records ~180 readers that still do not take the clearing lock (#7672 converts
them one at a time). CLAUDE.md documented `cargo test --release --workspace`,
which does not pin the thread count and therefore runs this crate in exactly
the configuration CI exists to avoid.

Measured against 2e5bf44 in release: 600/600 full-suite runs clean at
--test-threads=16 (load ~90); 2 failures in 320 at --test-threads=64 (load
~115), in proxy::...numeric_write_guard... and element_shape matrix_delete_revokes.
Both are the crate's own vacuity guards firing on a destroyed fixture
precondition, not a collector invariant. root_words itself never failed across
920 parallel full-suite runs, 1500 targeted pairings, or a 40-seed
PERRY_GC_SCHEDULE_SEED sweep.

No test is ignored and no retry is added; the unsupported configuration simply
stops being documented.

Claude-Session: https://claude.ai/code/session_012B8z92S82sCfqCrVqrFgS2
@proggeramlug
proggeramlug force-pushed the test/perry-runtime-single-threaded branch from 2603ebf to 2365dfc Compare August 10, 2026 21:52
@proggeramlug

Copy link
Copy Markdown
Contributor Author

Audit complete — merging.

Facts verified against the tree: test.yml pins RUST_TEST_THREADS=1 for perry-runtime at both invocations (lines 753/806, plus the macOS-leg comment), per_test_global! exists with #7672's migration in progress, and the CLAUDE.md edit changes exactly the documented local command plus one CI-gates bullet. The investigation behind it (920 parallel full-suite runs isolating the failure to the harness's shared globals, with the vacuity-guard message as the discriminator) is the right way to close a phantom GC bug — and the "seeded-schedule sweep is per-binary, not per-test-suite" note will save the next person a real detour.

This session hit the same class four times today (gate reds at load 26–45 that re-ran clean), so the operational value is immediate. Bumped to 0.5.1461; gate 19/19 green (docs-only diff).

@proggeramlug
proggeramlug merged commit 1804991 into main Aug 10, 2026
13 of 18 checks passed
@proggeramlug
proggeramlug deleted the test/perry-runtime-single-threaded branch August 10, 2026 21:54
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