Skip to content

fix: reject non-integer CPU replay entries - #618

Merged
bachase merged 1 commit into
mainfrom
codex/replay-record-validation
Oct 24, 2026
Merged

bachase merged 1 commit into
mainfrom
codex/replay-record-validation

Conversation

@bachase-agent

@bachase-agent bachase-agent commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The private CPU replay binding accepted numeric strings such as "0" because nanobind converted entries to uint8_t before Clifft validated them. This reproduces with the locked nanobind 2.11.0 on CPython 3.14.2; numeric bytes and numpy.float32(0) also passed through.

Keep entries as Python objects until applying Python's integer-index protocol and checking that each value is 0 or 1. Python booleans and Python/NumPy integers remain supported, with the existing container and record-length validation preserved. Add regression cases for string, bytes, and floating-point inputs, plus valid boolean/integer branches.

Closes #611. Discovered during #610; this fix changes only the private CPU replay binding and its tests.

Test plan

  • Before the fix, the expanded reference tests reproduced five failures with nanobind 2.11.0, including the original string case.
  • Built a cp312-abi3 wheel with nanobind 2.11.0. All 47 GPU-reference tests pass on CPython 3.12.14, 3.13.11, and 3.14.2.
  • On CPython 3.14.2, GPU-reference, experimental-GPU, GPU-sampling-mode, and record-probability tests: 104 passed, 68 skipped because GPU backends/devices are unavailable.
  • uv run --frozen --only-group dev pre-commit run --all-files --show-diff-on-failure passes.

Contributor agreement

  • I confirm this contribution is original work and license it under the project's Apache-2.0 license.
  • Human review of the AI-assisted changes is pending. The commit includes the Codex Assisted-by: trailer.

Use the Python integer-index protocol before narrowing replay entries to
bytes, so numeric strings, bytes, and floats cannot bypass validation.
Retain Python boolean and Python/NumPy integer bit inputs and the existing
record-length checks. Cover rejected values and valid deterministic bits.

Closes #611

Assisted-by: Codex (GPT-6) <noreply@openai.com>
@bachase
bachase marked this pull request as ready for review October 24, 2026 16:06
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-24 16:27 UTC

@github-actions

Copy link
Copy Markdown
Contributor

🐤 Performance Canary

No confirmed regressions detected. 1 benchmark comparison was inconclusive. This does not block merging.

Benchmark Base PR Runtime change Assessment
Squeeze 8192 T gates 24.7 us 24.7 us +0.3% No material change
Phase pass, 4,096 measurement barriers 3.60 ms 3.58 ms -0.6% No material change
Phase pass, 4,096 Clifford regions 5.62 ms 5.59 ms -0.4% No material change
Phase pass, 32,000 rank-limited rotations 18.1 ms 18.3 ms +1.0% No material change
Phase pass, 4,096 postselected lookahead regions 3.50 ms 3.55 ms +1.6% No material change
Compile/plan cultivation d5 13.3 ms 13.3 ms +0.3% No material change
Compile+schedule+plan, coherent QEC d5/r5 11.6 ms 11.6 ms -0.4% No material change
Schedule pass, coherent QEC d5/r5 8.93 ms 8.91 ms -0.2% No material change
Schedule pass, cultivation d5 3.67 ms 3.73 ms +1.6% No material change
Schedule dependence build, surface code d7/r7 1.39 ms 1.39 ms -0.1% No material change
QV-10, 100 shots 4.98 ms 4.96 ms -0.4% No material change
Cultivation d5, 1,000 shots 16.1 ms 15.9 ms -1.4% No material change
Early rejection with noisy suffix, 1,000 shots 929 us 932 us +0.3% No material change
Coherent QEC d5/r5, width 13, 100 shots 69.2 ms 68.9 ms -0.4% No material change
Surface code d7/r7, 10,000 shots 12.1 ms 12.0 ms -1.0% No material change
Surface code d5/r5 high noise, 10,000 shots 25.0 ms 24.9 ms -0.5% No material change
Surface code d11/r11, 1,000 shots 4.06 ms 4.05 ms -0.4% No material change
EXP_VAL 20q/200 probes, 100,000 shots 50.7 ms 47.7 ms -6.0% Inconclusive
external_inputs_nonclifford_packed_256_shots 123 us 123 us +0.1% No material change
external_inputs_nonclifford_scalar_256_shots 403 us 404 us +0.2% No material change
external_inputs_surface_d7_packed_256_shots 194 us 192 us -0.6% No material change
external_inputs_surface_d7_scalar_256_shots 7.52 ms 7.54 ms +0.1% No material change

Compared main (e16fa40) with this PR (3c39ce4) on the same runner using workload-local A/B/B/A ordering. Positive changes are slower. Changes under 5% are reported as no material change; changes of at least 5% but under 10% are notable; changes of at least 10% are possible regressions or improvements. Material changes that do not repeat in both pairs with low noise are inconclusive.

Environment and method
  • Runner CPU: AMD EPYC 9V74 80-Core Processor
  • Pinned logical CPU: 0
  • ISA: AVX2 runtime backend (forced)
  • Compiler: clang version 22.1.8
  • Build: Release, x86-64-v2, ThinLTO, lld, and OpenMP enabled.
  • Each pass warms every workload for at least 0.2 seconds, then runs 3 Google Benchmark repetitions with at least 0.5 seconds of measured CPU time each.
  • One unreported full-suite process per revision runs before the measured pairs.
  • Displayed timings are the geometric mean of the two drift-balanced pass medians.
  • Material changes must repeat in both pairs with under 5% within-pass relative standard deviation; otherwise they are inconclusive.
  • Results apply only to this runner and are intended to detect large regressions, not establish release performance.

View workflow run

@bachase
bachase merged commit 5fc87ec into main Oct 24, 2026
26 checks passed
@bachase
bachase deleted the codex/replay-record-validation branch October 24, 2026 16:24
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.

Reject string record entries in the CPU replay binding

2 participants