Skip to content

cr733(p2): journal resolved library shuffles + RNG entropy receipt#6522

Merged
matthewevans merged 1 commit into
mainfrom
ship/cr733-p2-library-shuffle
Jul 23, 2026
Merged

cr733(p2): journal resolved library shuffles + RNG entropy receipt#6522
matthewevans merged 1 commit into
mainfrom
ship/cr733-p2-library-shuffle

Conversation

@matthewevans

@matthewevans matthewevans commented Jul 23, 2026

Copy link
Copy Markdown
Member

Adds the first Tier-A leaf command family in the re-sequenced P2 phase
(leaves-first, hub-last): a resolved library shuffle command with an exact
predecessor/resulting order fingerprint and a ChaCha20 entropy receipt
(pre/post word position). Replay installs the recorded order and advances the
RNG via set_word_pos — it never calls shuffle_vector, so retained-prefix replay
cannot consume entropy or pick a different permutation (CR 701.24a).

Introduces the reusable GameState::advance_rng_high_water primitive (monotonic
on both the persisted high-water and the live stream cursor); capture_rng_word_pos
now routes through it as the single RNG-position write path. Both
change_zone::shuffle_library and the library branch of Effect::Shuffle delegate
to game::library::{resolve_and_apply_library_shuffle, apply_resolved_library_shuffle}.

Writes only already-classified census fields (rng/rng_word_pos/players), so the
always-on P0 field-set ratchet holds against the current fixtures; the opt-in
CR733_CENSUS_STRICT line-level pins fold in at the next full fixture regen.

Authored via codex Run 9; ported code-only onto current main (campaign branch
had drifted; uncompressed .json census fixtures superseded by main's gzipped set).

Summary by CodeRabbit

  • New Features
    • Added deterministic in-place library shuffling with recorded shuffle outcomes for reliable replay.
    • Introduced resolved journal entries for library shuffles, including RNG position tracking.
  • Bug Fixes
    • Improved handling when a shuffle target player cannot be found.
    • Replay now verifies preconditions (card order and RNG progression) and rejects invalid/mismatched receipts without mutating state.
  • Tests
    • Expanded unit and integration coverage for deterministic results, receipt roundtrips, malformed receipt rejection, empty-library shuffles, and consecutive shuffle ordering.

@matthewevans
matthewevans enabled auto-merge July 23, 2026 00:10
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e1052ebd-3996-4e63-9dd1-0645bf90369f

📥 Commits

Reviewing files that changed from the base of the PR and between 8e80b4e and 226eeac.

📒 Files selected for processing (8)
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/effects/shuffle.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/types/mod.rs
  • crates/engine/src/types/resolved_commands.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs
📝 Walkthrough

Walkthrough

Library shuffles now resolve into validated journal receipts containing card orders and RNG positions. The engine applies those receipts deterministically, enforces RNG and library preconditions, records shuffle commands, and supports them in semantic replay.

Changes

Library shuffle replay

Layer / File(s) Summary
Shuffle receipt contract
crates/engine/src/types/resolved_commands.rs, crates/engine/src/types/mod.rs
Adds the LibraryShuffle resolved command, replay invariant errors, journal recording, receipt validation, and serialization tests.
RNG high-water invariants
crates/engine/src/types/game_state.rs
Routes RNG position capture through monotonic high-water validation and reports regression errors.
Library shuffle resolution and application
crates/engine/src/game/library.rs
Resolves deterministic permutations into receipts, applies validated orders without resampling, updates derived state, emits shuffle events, and tests replay and composition behavior.
Effect and replay integration
crates/engine/src/game/effects/*, crates/engine/src/game/mod.rs, crates/engine/tests/integration/cr733_resolved_commands_p2.rs
Delegates shuffle effects to the library authority, handles missing players, exposes the module, and applies library shuffle commands during semantic replay.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ShuffleEffect
  participant LibraryModule
  participant GameState
  participant ResolvedRulesJournal
  ShuffleEffect->>LibraryModule: resolve_and_apply_library_shuffle
  LibraryModule->>GameState: capture and advance RNG word positions
  LibraryModule->>LibraryModule: apply_resolved_library_shuffle
  LibraryModule->>ResolvedRulesJournal: record_library_shuffle
  LibraryModule-->>ShuffleEffect: emit ShuffledLibrary action
Loading

Possibly related PRs

  • phase-rs/phase#5872: Both changes touch the library-shuffle effect pipeline and ShuffledLibrary event emission.
  • phase-rs/phase#6339: Both changes extend CR733 P2 resolved-command replay dispatch.

Suggested labels: enhancement

Suggested reviewers: minion1227

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: journaling resolved library shuffles with an RNG entropy receipt.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ship/cr733-p2-library-shuffle

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/engine/src/game/library.rs (1)

73-80: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid materializing the whole library into a Vec just to compare it.

current_order clones the entire im::Vector into a fresh Vec solely to run != against command.precondition_order. An iterator-based .eq() comparison avoids the allocation/copy and keeps the im::Vector zone comparison idiomatic.

♻️ Proposed refactor
-    let current_order: Vec<_> = state.players[player_index]
-        .library
-        .iter()
-        .copied()
-        .collect();
-    if current_order != command.precondition_order {
+    if !state.players[player_index]
+        .library
+        .iter()
+        .eq(command.precondition_order.iter())
+    {
         return Err(ResolvedLibraryShuffleReplayInvariantError::LibraryOrderPreconditionMismatch);
     }

As per path instructions, "Hot im::Vector zones must use im methods (push_back/pop_back/iter_mut), not materialize a std Vec."

🤖 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 `@crates/engine/src/game/library.rs` around lines 73 - 80, Replace the
`current_order` materialization in the library shuffle replay validation with an
iterator-based equality comparison between `state.players[player_index].library`
and `command.precondition_order`, preserving the existing mismatch error and
control flow. Avoid collecting the `im::Vector` into a `Vec`.

Source: Path instructions

🤖 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.

Nitpick comments:
In `@crates/engine/src/game/library.rs`:
- Around line 73-80: Replace the `current_order` materialization in the library
shuffle replay validation with an iterator-based equality comparison between
`state.players[player_index].library` and `command.precondition_order`,
preserving the existing mismatch error and control flow. Avoid collecting the
`im::Vector` into a `Vec`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: feca0cf5-e15b-4933-98da-e9a31bd4907d

📥 Commits

Reviewing files that changed from the base of the PR and between 70e4f2d and f911b32.

📒 Files selected for processing (8)
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/effects/shuffle.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/types/mod.rs
  • crates/engine/src/types/resolved_commands.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs

@matthewevans
matthewevans force-pushed the ship/cr733-p2-library-shuffle branch from f911b32 to 1c27eae Compare July 23, 2026 00:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@crates/engine/src/types/resolved_commands.rs`:
- Around line 1509-1532: Update validate_library_shuffle_receipt to reject
pre_word_pos == post_word_pos when the validated library order contains more
than one card, while preserving zero-length spans for zero- or one-card
libraries and existing regression checks. Add a malformed-receipt test covering
a multi-card permutation with an unchanged entropy span.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ccb03fc3-0df7-4a52-bd6b-757ca68922f5

📥 Commits

Reviewing files that changed from the base of the PR and between f911b32 and 1c27eae.

📒 Files selected for processing (8)
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/effects/shuffle.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/types/mod.rs
  • crates/engine/src/types/resolved_commands.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/engine/src/types/mod.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/game/effects/shuffle.rs

Comment thread crates/engine/src/types/resolved_commands.rs
@matthewevans
matthewevans force-pushed the ship/cr733-p2-library-shuffle branch from 1c27eae to 8e80b4e Compare July 23, 2026 00:49
@github-actions

Copy link
Copy Markdown

Parse changes introduced by this PR

✓ No card-parse changes detected.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@crates/engine/src/game/effects/shuffle.rs`:
- Around line 69-75: Move the player-existence validation in the shuffle effect
to immediately after resolving target_player, before evaluating CantShuffle
suppression; ensure unknown players always return EffectError::PlayerNotFound
even when suppressed. Update the regression coverage for the broad CantShuffle
static to assert this behavior.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f61b09b1-da32-4244-83f3-5c954ef50529

📥 Commits

Reviewing files that changed from the base of the PR and between 1c27eae and 8e80b4e.

📒 Files selected for processing (8)
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/effects/shuffle.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/types/mod.rs
  • crates/engine/src/types/resolved_commands.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/engine/src/types/mod.rs
  • crates/engine/tests/integration/cr733_resolved_commands_p2.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/game/mod.rs
  • crates/engine/src/game/effects/change_zone.rs
  • crates/engine/src/game/library.rs
  • crates/engine/src/types/resolved_commands.rs

Comment thread crates/engine/src/game/effects/shuffle.rs Outdated
Adds the first Tier-A leaf command family in the re-sequenced P2 phase
(leaves-first, hub-last): a resolved library shuffle command with an exact
predecessor/resulting order fingerprint and a ChaCha20 entropy receipt
(pre/post word position). Replay installs the recorded order and advances the
RNG via set_word_pos — it never calls shuffle_vector, so retained-prefix replay
cannot consume entropy or pick a different permutation (CR 701.24a).

Introduces the reusable GameState::advance_rng_high_water primitive (monotonic
on both the persisted high-water and the live stream cursor); capture_rng_word_pos
now routes through it as the single RNG-position write path. Both
change_zone::shuffle_library and the library branch of Effect::Shuffle delegate
to game::library::{resolve_and_apply_library_shuffle, apply_resolved_library_shuffle}.

Writes only already-classified census fields (rng/rng_word_pos/players), so the
always-on P0 field-set ratchet holds against the current fixtures; the opt-in
CR733_CENSUS_STRICT line-level pins fold in at the next full fixture regen.

Authored via codex Run 9; ported code-only onto current main (campaign branch
had drifted; uncompressed .json census fixtures superseded by main's gzipped set).
@matthewevans
matthewevans force-pushed the ship/cr733-p2-library-shuffle branch from 8e80b4e to 226eeac Compare July 23, 2026 00:58
@matthewevans
matthewevans added this pull request to the merge queue Jul 23, 2026
Merged via the queue into main with commit 47118ea Jul 23, 2026
14 checks passed
@matthewevans
matthewevans deleted the ship/cr733-p2-library-shuffle branch July 23, 2026 01:34
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