Skip to content

refactor(parser): reify CopyChosenHost relation synthesis - #6832

Merged
matthewevans merged 2 commits into
mainfrom
ship/refactor-parser-reify-copychosenhost-relation-synthesis
Jul 31, 2026
Merged

refactor(parser): reify CopyChosenHost relation synthesis#6832
matthewevans merged 2 commits into
mainfrom
ship/refactor-parser-reify-copychosenhost-relation-synthesis

Conversation

@matthewevans

@matthewevans matthewevans commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of permanent-choice relations during game ability processing.
    • Preserved source identity, descriptions, targeting details, and printed ability slots when eligible choices are synthesized.
    • Corrected ability-slot accounting across supported and unsupported entries.
    • Prevented unsupported relation-synthesis entries from being emitted as new spell content.
  • Tests

    • Added regression coverage for relation synthesis, metadata preservation, lowering behavior, and ability-slot retention.
    • Stabilized AI controller tests with deterministic retry timing.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Oracle parser adds relation-synthesis IR for CopyChosenHost, preserves chooser metadata and source identity, and lowers synthesized relations into ChoosePermanent replacements with source-order slot accounting. Regression coverage validates the flow. AI retry tests now use deterministic randomness.

Changes

Oracle relation synthesis

Layer / File(s) Summary
Relation synthesis IR contract
crates/engine/src/parser/oracle_ir/doc.rs, crates/engine/src/parser/oracle_ir/relation.rs, crates/engine/src/parser/oracle_ir/feature.rs
Adds RelationSynthesisIr and its node variant, captures chooser filter and description, rejects fresh synthesis, and excludes synthesized nodes from direct evidence and spell handling.
Relation finalization and source-order lowering
crates/engine/src/parser/oracle.rs
Finalization replaces the matching unsupported chooser in place. Lowering emits ChoosePermanent replacements and tracks printed ability slots independently of the result vector.
Relation synthesis regression coverage
crates/engine/src/parser/oracle_tests.rs, crates/engine/src/parser/oracle_ir/doc.rs, scripts/prelowered-ratchet.txt
Tests verify pair selection, source identity, printed slots, lowering, retained unsupported abilities, and swallow-audit behavior. The fixture is added to the ratchet ledger.

AI retry test determinism

Layer / File(s) Summary
Deterministic AI retry test setup
client/src/game/controllers/__tests__/aiController.test.ts
The test fixes Math.random during retry timing and restores the spy during teardown.

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

Sequence Diagram(s)

sequenceDiagram
  participant OracleDocBuilder
  participant CopyChosenHost
  participant ChoosePermanent
  OracleDocBuilder->>CopyChosenHost: finalize chooser/static relation
  CopyChosenHost->>ChoosePermanent: lower filter and description
  ChoosePermanent->>OracleDocBuilder: add Moved replacement and printed slot
Loading

Possibly related PRs

  • phase-rs/phase#6539: Extends the ChoosePermanent flow with Oracle parser relation synthesis.
  • phase-rs/phase#6726: Modifies the parser flow for “as-enters becomes your choice” handling.
  • phase-rs/phase#6748: Refactors relation finalization and lowering for source identity and printed slots.

Suggested labels: enhancement

Suggested reviewers: claytonlin1110, andriypolanski, mike-thedude

🚥 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 clearly and concisely describes the parser refactor that reifies CopyChosenHost relation synthesis.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ship/refactor-parser-reify-copychosenhost-relation-synthesis

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

@matthewevans
matthewevans enabled auto-merge July 31, 2026 04:24
@matthewevans
matthewevans added this pull request to the merge queue Jul 31, 2026
@github-actions

Copy link
Copy Markdown

Parse changes introduced by this PR

✓ No card-parse changes detected.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 31, 2026
@matthewevans
matthewevans enabled auto-merge July 31, 2026 06:33

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

🤖 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/parser/oracle_tests.rs`:
- Around line 269-273: Update the assertion message in the retained_slots test
to describe that the value 2 is the copy ability’s own source_ability_index,
rather than claiming the synthesized chooser occupies printed slot 0. Keep the
assertion and expected value unchanged.

In `@crates/engine/src/parser/oracle.rs`:
- Around line 3039-3043: Keep source_ability_index aligned with
source.base_abilities while processing printed abilities: do not advance
printed_ability_slot for RelationSynthesis replacements, since they do not
create base_abilities entries. Preserve the existing slot progression for actual
source abilities so later copy abilities receive valid indices.
🪄 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: 652a119a-ca52-40e1-ae65-7e22fefff0cf

📥 Commits

Reviewing files that changed from the base of the PR and between 73fd7f6 and 4cf3ccd.

📒 Files selected for processing (7)
  • client/src/game/controllers/__tests__/aiController.test.ts
  • crates/engine/src/parser/oracle.rs
  • crates/engine/src/parser/oracle_ir/doc.rs
  • crates/engine/src/parser/oracle_ir/feature.rs
  • crates/engine/src/parser/oracle_ir/relation.rs
  • crates/engine/src/parser/oracle_tests.rs
  • scripts/prelowered-ratchet.txt

Comment on lines +269 to +273
assert_eq!(
retained_slots,
vec![2],
"the synthesized chooser is absent from result.abilities but still occupies printed slot 0"
);

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the assertion message: it describes a different fact than the assertion checks.

retained_slots holds the copy ability's own source_ability_index, which the assertion pins at 2. The message states the synthesized chooser "still occupies printed slot 0". The assertion does not check slot 0 for the chooser. State what the value means, so a future reader does not treat 2 as proof of the chooser's slot.

💚 Proposed message fix
     assert_eq!(
         retained_slots,
         vec![2],
-        "the synthesized chooser is absent from result.abilities but still occupies printed slot 0"
+        "the copy ability's retained index counts source-order printed slots, so the synthesized chooser at slot 0 still shifts it to 2"
     );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert_eq!(
retained_slots,
vec![2],
"the synthesized chooser is absent from result.abilities but still occupies printed slot 0"
);
assert_eq!(
retained_slots,
vec![2],
"the copy ability's retained index counts source-order printed slots, so the synthesized chooser at slot 0 still shifts it to 2"
);
🤖 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/parser/oracle_tests.rs` around lines 269 - 273, Update the
assertion message in the retained_slots test to describe that the value 2 is the
copy ability’s own source_ability_index, rather than claiming the synthesized
chooser occupies printed slot 0. Keep the assertion and expected value
unchanged.

Comment on lines +3039 to +3043
// An already-emitted unsupported chooser can become a relation-synthesized
// replacement without entering `result.abilities`.
// Its historical printed slot still exists, so this source-order counter is
// deliberately independent of the published ability vector length.
let mut printed_ability_slot = 0usize;

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the runtime consumer of RetainPrintedAbilityFromSource and see which list source_ability_index addresses.
rg -nP -C10 'RetainPrintedAbilityFromSource' crates/engine/src --glob '!**/parser/**'
rg -nP -C6 '\bsource_ability_index\b' crates/engine/src
ast-grep outline crates/engine/src/game --items all --match 'Retain|copy|Copy' --type function

Repository: phase-rs/phase

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- oracle parser target ---'
sed -n '2980,3135p' crates/engine/src/parser/oracle.rs
printf '%s\n' '--- IR slot stamping and lowering ---'
sed -n '1230,1335p' crates/engine/src/parser/oracle_ir/doc.rs
rg -n -C8 'printed_ability_slot|RelationSynthesis|source_ability_index' crates/engine/src/parser/oracle.rs crates/engine/src/parser/oracle_ir/doc.rs crates/engine/src/parser/oracle_ir
printf '%s\n' '--- runtime ability list definitions and copy application ---'
sed -n '6200,6250p' crates/engine/src/game/layers.rs
sed -n '6975,7005p' crates/engine/src/game/layers.rs
sed -n '7218,7242p' crates/engine/src/game/layers.rs

Repository: phase-rs/phase

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- parsed abilities to object base_abilities ---'
rg -n -C8 'base_abilities\s*[:=]|ParsedAbilities|\.abilities\.clone|parsed\.abilities' crates/engine/src --glob '*.rs' | head -n 240
printf '%s\n' '--- relation-synthesis fixture and expected vectors ---'
sed -n '1,290p' crates/engine/src/parser/oracle_tests.rs
printf '%s\n' '--- lower result consumers ---'
rg -n -C10 'lower_oracle_ir|parse_warnings|base_abilities' crates/engine/src/parser crates/engine/src/game crates/engine/src/types --glob '*.rs' | head -n 320

Repository: phase-rs/phase

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- card abilities and object initialization ---'
rg -n -C5 'base_abilities|abilities:\s*parsed\.abilities|abilities:\s*self\.abilities|abilities:\s*card\.abilities' crates/engine/src --glob '*.rs' | head -n 260
printf '%s\n' '--- relation replacement lowering completion ---'
sed -n '3150,3275p' crates/engine/src/parser/oracle.rs
printf '%s\n' '--- exact copy-layer reads ---'
sed -n '6228,6245p' crates/engine/src/game/layers.rs
sed -n '7220,7240p' crates/engine/src/game/layers.rs

Repository: phase-rs/phase

Length of output: 30010


Keep source_ability_index aligned with source.base_abilities.

The copy layer reads source.base_abilities[source_ability_index]. RelationSynthesis publishes only a replacement, so it does not add an entry to base_abilities. The later copy ability therefore receives an out-of-range index. Do not advance printed_ability_slot for RelationSynthesis, or rewrite the index after lowering.

🤖 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/parser/oracle.rs` around lines 3039 - 3043, Keep
source_ability_index aligned with source.base_abilities while processing printed
abilities: do not advance printed_ability_slot for RelationSynthesis
replacements, since they do not create base_abilities entries. Preserve the
existing slot progression for actual source abilities so later copy abilities
receive valid indices.

@matthewevans
matthewevans added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit d740520 Jul 31, 2026
15 checks passed
@matthewevans
matthewevans deleted the ship/refactor-parser-reify-copychosenhost-relation-synthesis branch July 31, 2026 07:04
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