Skip to content

Experiment: replay verification at scale + FP perturbation sensitivity - #47

Open
gmliao wants to merge 8 commits into
mainfrom
experiment/replay-scale-fp-perturbation
Open

Experiment: replay verification at scale + FP perturbation sensitivity#47
gmliao wants to merge 8 commits into
mainfrom
experiment/replay-scale-fp-perturbation

Conversation

@gmliao

@gmliao gmliao commented Aug 31, 2026

Copy link
Copy Markdown
Owner

RQ3 reinforcement experiment (design note: Notes/plans/2026-08-31-replay-scale-fp-perturbation-experiment-design.md).

Results

Part A — replay verification at scale (aggregate)

recordings total ticks total client events hash mismatches verified vs recorded run1 == run2
41 70,800 22,110 0 41/41 41/41

Core matrix: 30 seeds × 1,200 ticks (5 players, MoveTo every 20 ticks). Robustness variants: players 2 and 10 (3 seeds each), MoveTo cadence 5 (3 seeds), plus two 12,000-tick (~10 min) long-horizon recordings. 0 mismatches everywhere → 95% rule-of-three upper bound on per-tick mismatch probability ≈ 4.2e-5.

Part B — perturbation sensitivity (injected at tick 600, 10 recordings each)

mode eps detected detection latency
float +1e-7 (sub-LSB, pre-quantization) 1e-07 0/10 (absorbed)
fixed +1 LSB (0.001 world units) 1 10/10 0 ticks (all)
fixed +1000 LSB (1.0 world unit) 1000 10/10 0 ticks (all)

Conclusion

Per-tick hash verification stays at 0 mismatches over 41 recordings / 70,800 ticks across player-count, input-cadence, and duration variations; sub-quantization floating-point noise cannot enter the fixed-point state (quantization barrier), and once state actually shifts by even 1 LSB (= one fixed-point quantization step, 0.001 world units — not a float ULP), audit-time replay verification exposes it in the same tick with no blind spots. This is an offline audit/CI mechanism, not runtime monitoring.

Notable findings (in this PR's code commits)

  • Real determinism bug found and fixed: hero-defense combat depended on Dictionary iteration order (28/30 of the first full run diverged; one seed diverged between two same-process replays). Fixed with sorted-key iteration + lowest-id target tie-break.
  • Replay sequence-counter gap (core, follow-up): replayed inputs keep recorded sequences but the shared counter is not advanced, so replay-emitted events differ in sequence only. Runner now re-checks by content and warns instead of failing.

Cross-architecture follow-up

crossarch-verify.sh replays the same arm64-recorded batch on an x86_64 machine (records tarball prepared separately); results to be appended.

Axes NOT varied

perturbation tick (600, applied to the first 10 core seeds only), turrets (0). Same-arch (arm64) in this PR; cross-arch run pending per above.

Environment: d23d66d/fcdd41e, Apple Swift 6.3.2, release, Apple M2 (arm64). regenerate.py --check = OK.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Sm3UKGwyUw6RyELpBMFd3H

gmliao and others added 2 commits August 31, 2026 14:50
…ation

- ReevaluationRunner --record: headless batch recording with deterministic
  MoveTo injection; seed via landID
- MovementSystem: env-driven perturbation hook (HERO_PERTURB_*) for the
  replay sensitivity experiment; inert when unset
- Fix order-dependent game logic: sorted-key iteration over players/
  monsters/turrets and lowest-id tie-break in nearest-target selection.
  Dictionary iteration order made 1,200-tick replays diverge (28/30
  failed); 30/30 verify cleanly after the fix
- Runner: re-check server-event mismatches by content, reporting pure
  sequence-numbering differences (known replay accounting gap) as a
  warning instead of a failure

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sm3UKGwyUw6RyELpBMFd3H
30 recordings x 1,200 ticks: 0 hash mismatches, run1 == run2 for all.
Perturbation at tick 600: sub-LSB float noise absorbed 10/10 by
fixed-point quantization; >=1 LSB shifts detected 10/10 with 0-tick
latency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sm3UKGwyUw6RyELpBMFd3H

@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: a3181997b6

ℹ️ 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".

// Experiment hook: shift the quantized x coordinate by eps raw LSB units (1 LSB = 0.001)
if let p = MovementPerturbation.current, p.mode == "fixed", ctx.tickId == p.tick {
// eps is in raw LSB units (1 LSB = 0.001 world units); eps/1000 quantizes back to exactly eps LSB
player.position = Position2(v: player.position.v + IVec2(x: p.eps / 1000.0, y: 0.0))

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 Apply fixed perturbations through a semantic helper

When HERO_PERTURB_MODE=fixed, this converts a raw-LSB count to world-space Float by manually dividing by 1000 and then requantizing it. For fractional, sufficiently large, or precision-losing HERO_PERTURB_EPS values, the applied delta can differ from the requested LSB count, trap during Int32 conversion, or wrap when added to the coordinate, invalidating the experiment rather than producing a controlled perturbation. Parse a bounded integer LSB value and add a semantic DeterministicMath helper instead of manipulating the scale directly.

AGENTS.md reference: AGENTS.md:L130-L138

Useful? React with 👍 / 👎.

@@ -0,0 +1,117 @@
# Replay verification at scale + FP perturbation sensitivity

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 Add synchronized English and Chinese experiment documentation

This new README.md is predominantly Traditional Chinese, but no README.zh-TW.md counterpart or language-switching links are added; the new English design note likewise has no synchronized Chinese version. Consequently English readers do not receive the default-language experiment report, and future regeneration can update only one language. Add paired English/Traditional Chinese documents using the required filenames and switcher links.

AGENTS.md reference: AGENTS.md:L248-L254

Useful? React with 👍 / 👎.

gmliao added 6 commits August 31, 2026 15:04
Records and logs are deterministically reproducible via --record/--verify.
9 variant recordings (players 2/10, MoveTo cadence 5) and two 12,000-tick
long-horizon recordings, all 0 mismatches; totals now 41 recordings /
70,800 ticks. crossarch-verify.sh replays the same arm64-recorded batch
on an x86_64 machine.
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