fix(parser): stamp Permanent on duration-less additive type grants - #6306
Conversation
|
🚨 Contributor flagged. Click here for more info: Superagent Dashboard |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe parser now resolves additive type grants without an explicit duration to ChangesAdditive type grant duration
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
matthewevans
left a comment
There was a problem hiding this comment.
Changes requested — the parser stamp is at the right seam, but the reported gameplay regression is not tested through resolution and cleanup.
🔴 Blocker
[HIGH] Missing a discriminating production-pipeline regression for the persistent grant. Evidence: crates/engine/src/parser/oracle_effect/subject.rs:3613 changes only the parsed duration, while the new crates/engine/src/parser/oracle_effect/tests.rs:210 test stops at the AbilityDefinition; the observable behavior is produced later by crates/engine/src/game/effects/effect.rs:59 and cleanup retains/removes effects in crates/engine/src/game/layers.rs:152. Why it matters: this PR fixes a resolution-to-cleanup rules result, but its new test cannot prove that activating Sensei Golden-Tail's ability registers a permanent effect which survives cleanup on the affected creature. Suggested fix: add a registered integration scenario that activates the actual ability (or an equivalent parsed production ability), advances through resolution and cleanup, and asserts the target still has both Bushido 1 and the Samurai subtype; it must fail when the parser's Duration::Permanent stamp is reverted.
🟡 Non-blocking
The required current-head parse-diff sticky artifact is still absent. GitHub shows the card-data job succeeded, but the GraphQL review packet at a215fc21dace322a03ecb6ce68f2d3e0e01ecdd4 has no <!-- coverage-parse-diff --> comment, so approval remains withheld until CI publishes it.
Recommendation: request changes for the runtime regression, then re-review the new head with its current parse-diff artifact.
Parse changes introduced by this PR · 6 card(s), 6 signature(s) (baseline: main
|
matthewevans
left a comment
There was a problem hiding this comment.
Approved: right parser seam, scoped six-card duration correction, and the registered production regression now proves the grant survives cleanup.
|
@matthewevans |
|
The implementation review is approved and the required repository checks are green. The PR is currently held outside code review because the independent Contributor trust check remains |
|
**Blocked — implementation review remains approved; enqueue is halted by the current required contributor-trust check. 🔴 Blocker
Recommendation: resolve the contributor-trust gate, then a maintainer can re-enable merge-when-ready without further code changes. |
Closes #5950
Summary
Discord report: the bushido 1 + Samurai type that Sensei Golden-Tail's training ability grants ("Put a training counter on target creature. That creature gains bushido 1 and becomes a Samurai in addition to its other creature types.") wears off after one turn, even though the card states no duration.
The parse is faithful (a
GenericEffectgrantingAddKeyword(Bushido 1)+AddSubtype(Samurai)), but itsdurationwasNone. Per CR 611.2a a resolution-generated continuous effect with no stated duration lasts until end of game (permanent). At the resolution seam (effect.rs::resolve) an unstatedNoneduration is defaulted toDuration::UntilEndOfTurn(a documented known deviation, becauseNoneis overloaded there and a global flip is blocked on a parser-side task). So the grant was swept byprune_end_of_turn_effectsat cleanup and "wore off."Root cause:
build_continuous_clause(parser/oracle_effect/subject.rs) parsed the "gains … and becomes a … in addition to its other creature types" predicate into the right modifications but leftduration = None, relying on that wrong default.Fix: follow the existing parser-side precedent (the Suspend grant and
build_become_clauseboth stampDuration::Permanentfor known-permanent grants). When a continuous grant carries the additive "in addition to its other [creature] types" marker (CR 205.1b) and no duration was parsed, stampDuration::Permanent(CR 611.2a). This gates the whole class of additive permanent type grants, not just Sensei Golden-Tail — the same defect affected Curious Colossus ("…loses all abilities, becomes a Coward in addition to its other types, and has base power and toughness 1/1"), whose effect is likewise indefinite and now correctly persists. The override only fires when the duration is unstated, so an explicit "…in addition to its other types until end of turn" keeps its parsed turn-scoped duration. No engine change is needed: the resolver already honors aPermanentduration andprune_end_of_turn_effectsnever sweeps it.Changes
crates/engine/src/parser/oracle_effect/subject.rs— inbuild_continuous_clause, stampDuration::Permanentwhen the predicate carries the additive "in addition to its other [creature] types" marker (has_in_addition_to_other_types, already imported) and no duration was parsed. Mirrors the adjacent Suspend/build_become_clausepermanent-default precedents.crates/engine/src/parser/oracle_effect/tests.rs— new building-block regressionadditive_type_grant_with_no_duration_is_permanent(Sensei Golden-Tail): the training grant'sGenericEffect(bushido keyword + Samurai subtype) carriesSome(Duration::Permanent). Updatedcomma_list_type_change_and_has_base_pt_parses_as_single_generic_effect(Curious Colossus) — the effect its own doc calls "indefinite" now assertsPermanent(previously codified theNonebug).crates/engine/src/parser/oracle_tests.rs— updatedcurious_colossus_base_pt_comma_list_has_no_unimplemented_trigger_tailto assertSome(Duration::Permanent)(wasNone); Oracle text verified duration-less against Scryfall.Test Plan
cargo fmt --all -- --checkcargo clippy -p engine --lib -- -D warningscargo test -p engine --lib(full suite: 17,477 pass)cargo test -p engine --lib -- additive_type_grant_with_no_duration_is_permanentcargo test -p engine --lib -- curious_colossus_base_pt_comma_list_has_no_unimplemented_trigger_tail comma_list_type_change_and_has_base_pt_parses_as_single_generic_effectOut of scope
The broader
None-defaults-to-UntilEndOfTurnoverload ateffect.rs::resolve(blocked on the parser-side stated-duration distribution task) is unchanged — this fix is a targeted parser-side stamp for the additive-type-grant class, consistent with the existing per-class Permanent precedents.Summary by CodeRabbit
Bug Fixes
Tests