Skip to content

test(sp3): Bardeen 1973 numerical regression + SAB/mode/motion contract tests - #9

Merged
steeltroops-ai merged 2 commits into
mainfrom
tests/sp3-regression-infrastructure
Apr 29, 2026
Merged

test(sp3): Bardeen 1973 numerical regression + SAB/mode/motion contract tests#9
steeltroops-ai merged 2 commits into
mainfrom
tests/sp3-regression-infrastructure

Conversation

@steeltroops-ai

Copy link
Copy Markdown
Owner

Two commits closing the regression-test gap that audit zone 8 flagged:
bun run physics:regress used to match zero tests, and the rule's drift
threshold (1e-9 over 10^5 steps) lived in a comment.

Group 3A wires six Rust integration-test binaries against gravitas-core,
anchored to analytic Kerr orbit references. tests/common/mod.rs holds
the shared baselines: prograde and retrograde branches of Bardeen 1973
Eq. 28 (photon-sphere critical impact parameter) and Eq. 38 (Bardeen-
Press-Teukolsky ISCO), plus the standard regression spin grid mirroring
the EHT M87* and Sgr A* spin brackets.

  • conservation.rs runs three 10^5-step integrations of an equatorial
    null ray at a* in {0, 0.5, 0.99} with adaptive RKF45; asserts the
    post-run E, L_z, Carter Q drift by less than 1e-9.
  • photon_ring.rs pins photon_sphere() against the closed-form Bardeen
    formula across the spin grid plus the Schwarzschild and near-extremal
    limits.
  • isco.rs locks both Kerr::isco branches against BPT closed-form across
    the spin grid; checks the Schwarzschild 6M coincidence and the
    near-extremal asymmetry.
  • schwarzschild_degenerate.rs guards against future 1/a divisions: at
    a = 0 every Kerr-specific branch must collapse cleanly to the
    Schwarzschild form (r_+ = 2M, r_isco = 6M, r_ph = 3M, omega_ZAMO = 0,
    r_ergo = 2M independent of theta).
  • near_extremal.rs is a 200-case proptest at a* = 0.99 across a wide
    spread of equatorial-ish initial conditions; the integrator must
    either escape, terminate cleanly, or surface NormalizationFailure
    within a 2000-step budget without producing NaN coordinates.

physics:regress in package.json now invokes cargo test --release across
all six binaries (the five new ones plus the SP-1 normalize.rs).

Group 3C lands three TypeScript test files locking the contracts the
renderer and worker rely on every frame. sab-schema.test.ts asserts
the offset arithmetic plus a property-based round-trip on byte offset
= f32 index times four. useSimulationMode.test.ts walks the three-state
mutex end to end under fake timers including the 500 ms transition
window and the idempotent-in-destination contract. useReducedMotion.test.ts
stubs window.matchMedia and verifies initial read, reactive flipping,
and listener cleanup on unmount.

Group 3B (Playwright + SSIM visual regression) and Group 3D (goldens
manifest + maintenance script) follow as separate PRs because they
need a dev-server boot harness and Playwright dep additions worth
their own review.

Test plan

  • cd physics-engine && cargo test --release -p gravitas-core --tests (27 lib + 23 integration tests pass)
  • bun run physics:regress (alias now runs the real suite)
  • cd physics-engine && cargo clippy -p gravitas-core --tests -- -D warnings (clean)
  • bunx vitest run src/tests/engine/sab-schema.test.ts src/tests/hooks/useSimulationMode.test.ts src/tests/hooks/useReducedMotion.test.ts (16 pass)
  • bun run type-check (clean)

Six Rust integration-test binaries against gravitas-core, anchored to
analytic Kerr orbit references. The physics:regress alias used to point
at a vitest pattern that matched zero tests; it now invokes the real
suite and the rule's drift threshold (1e-9 over 10^5 steps) becomes a
machine-checked invariant rather than wishful prose.

tests/common/mod.rs holds the shared analytic baselines: the
prograde and retrograde branches of Bardeen 1973 Eq. 28 (photon-sphere
critical impact parameter) and Eq. 38 (Bardeen-Press-Teukolsky ISCO),
plus the standard regression spin grid {0, 0.5, 0.9, 0.99, 0.998} that
mirrors the EHT M87* and Sgr A* spin brackets.

conservation.rs runs three 10^5-step integrations of an equatorial
null ray at a* in {0, 0.5, 0.99} with adaptive RKF45, asserting the
post-run constants of motion (E, L_z, Carter Q) drift by less than
1e-9. The renormalization step (rule 05 §3) runs every 10 steps and
must produce no NormalizationFailure across the budget.

photon_ring.rs pins the engine's photon_sphere() output against an
independent recomputation of the Bardeen closed form across the spin
grid plus the Schwarzschild and near-extremal limits.

isco.rs locks the prograde and retrograde Kerr::isco(orbit) results
against the BPT formula across the spin grid; checks the Schwarzschild
6M coincidence and the near-extremal asymmetry (prograde -> M, retro
-> 9M).

schwarzschild_degenerate.rs guards against future refactors that might
introduce a 1/a division: at a = 0 the Kerr machinery must produce
r_+ = 2M, r_isco = 6M for both branches, r_ph = 3M, omega_ZAMO = 0
everywhere, and r_ergo = 2M independent of theta.

near_extremal.rs is a 200-case proptest at a* = 0.99 across a wide
spread of equatorial-ish initial conditions; the integrator must
either escape, terminate cleanly, or surface NormalizationFailure
within a 2000-step budget without producing NaN coordinates.

physics:regress in package.json now invokes cargo test --release
across all six binaries. Adds proptest 1.x to gravitas-core
dev-dependencies.
…n hook

Three TypeScript test files locking the contracts that the renderer
and worker rely on every frame.

sab-schema.test.ts asserts the offset arithmetic that the worker and
the bridge both index against: blocks monotonically ordered, all
offsets non-negative integers, the four block sizes sum to the LUTS
offset, every TELEMETRY slot fits inside its block, and the shadow
curve cap (16 reserved scalars + 56 (x,y) points) fits inside the
PHYSICS block. A property-based round-trip on byte offset = f32 index
times four guards against future drift between the byte and float
views.

useSimulationMode.test.ts walks the three-state machine end to end
under fake timers: starts interactive, takes the 500 ms transition
window into cinematic, ignores re-entry while transitioning,
transitions back to interactive on enterInteractive, and is
idempotent when called in its own destination state. The transition
window is the contract that lets renderers fade cleanly between
modes; without this test the timer could drift to zero or to several
seconds without anyone noticing.

useReducedMotion.test.ts stubs window.matchMedia and verifies the
hook reads the initial state, flips reactively when the change
event fires, and removes its listener on unmount. WCAG 2.2 SC 2.3.3
compliance hinges on the cinematic auto-orbit reading this signal,
so a regression in the hook silently strips an accessibility
guarantee.
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@steeltroops-ai has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 57 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39393263-4578-4059-8b09-ce6978a9077e

📥 Commits

Reviewing files that changed from the base of the PR and between e5742d1 and 5ab9a02.

📒 Files selected for processing (11)
  • package.json
  • physics-engine/gravitas-core/Cargo.toml
  • physics-engine/gravitas-core/tests/common/mod.rs
  • physics-engine/gravitas-core/tests/conservation.rs
  • physics-engine/gravitas-core/tests/isco.rs
  • physics-engine/gravitas-core/tests/near_extremal.rs
  • physics-engine/gravitas-core/tests/photon_ring.rs
  • physics-engine/gravitas-core/tests/schwarzschild_degenerate.rs
  • src/__tests__/engine/sab-schema.test.ts
  • src/__tests__/hooks/useReducedMotion.test.ts
  • src/__tests__/hooks/useSimulationMode.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tests/sp3-regression-infrastructure

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
Review rate limit: 0/1 reviews remaining, refill in 44 minutes and 57 seconds.

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ab9a02e52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +52 to +54
if matches!(traj.termination, TerminationReason::NormalizationFailure) {
panic!("integrator hit NormalizationFailure at step {}", traj.steps_taken);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce full-step termination in conservation tests

run_long_integration only panics on NormalizationFailure, so these tests still pass when integration exits early via Horizon, Escape, or other non-None reasons before reaching the intended STEP_COUNT=100_000. In those cases the drift check is no longer validating the stated long-horizon contract and can mask regressions by measuring invariants over a much shorter trajectory. Please assert traj.termination == TerminationReason::MaxSteps (and/or traj.steps_taken == STEP_COUNT) before accepting the drift thresholds.

Useful? React with 👍 / 👎.

@steeltroops-ai
steeltroops-ai merged commit 29881eb into main Apr 29, 2026
2 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